summaryrefslogtreecommitdiffstats
path: root/pigeonhole
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 17:36:47 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 17:36:47 +0000
commit0441d265f2bb9da249c7abf333f0f771fadb4ab5 (patch)
tree3f3789daa2f6db22da6e55e92bee0062a7d613fe /pigeonhole
parentInitial commit. (diff)
downloaddovecot-0441d265f2bb9da249c7abf333f0f771fadb4ab5.tar.xz
dovecot-0441d265f2bb9da249c7abf333f0f771fadb4ab5.zip
Adding upstream version 1:2.3.21+dfsg1.upstream/1%2.3.21+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'pigeonhole')
-rw-r--r--pigeonhole/AUTHORS8
-rw-r--r--pigeonhole/COPYING4
-rw-r--r--pigeonhole/COPYING.LGPL502
-rw-r--r--pigeonhole/ChangeLog38862
-rw-r--r--pigeonhole/INSTALL903
-rw-r--r--pigeonhole/Makefile.am227
-rw-r--r--pigeonhole/Makefile.in1233
-rw-r--r--pigeonhole/NEWS1841
-rw-r--r--pigeonhole/README332
-rw-r--r--pigeonhole/TODO97
-rw-r--r--pigeonhole/aclocal.m41174
-rwxr-xr-xpigeonhole/compile348
-rwxr-xr-xpigeonhole/config.guess1480
-rwxr-xr-xpigeonhole/config.rpath684
-rwxr-xr-xpigeonhole/config.sub1801
-rwxr-xr-xpigeonhole/configure16069
-rw-r--r--pigeonhole/configure.ac245
-rwxr-xr-xpigeonhole/depcomp791
-rw-r--r--pigeonhole/doc/Makefile.am18
-rw-r--r--pigeonhole/doc/Makefile.in760
-rw-r--r--pigeonhole/doc/devel/DESIGN45
-rw-r--r--pigeonhole/doc/example-config/Makefile.am10
-rw-r--r--pigeonhole/doc/example-config/Makefile.in755
-rw-r--r--pigeonhole/doc/example-config/conf.d/20-managesieve.conf84
-rw-r--r--pigeonhole/doc/example-config/conf.d/90-sieve-extprograms.conf44
-rw-r--r--pigeonhole/doc/example-config/conf.d/90-sieve.conf205
-rw-r--r--pigeonhole/doc/example-config/conf.d/Makefile.am10
-rw-r--r--pigeonhole/doc/example-config/conf.d/Makefile.in576
-rw-r--r--pigeonhole/doc/example-config/sieve-ldap.conf74
-rw-r--r--pigeonhole/doc/extensions/Makefile.am17
-rw-r--r--pigeonhole/doc/extensions/Makefile.in580
-rw-r--r--pigeonhole/doc/extensions/duplicate.txt48
-rw-r--r--pigeonhole/doc/extensions/editheader.txt64
-rw-r--r--pigeonhole/doc/extensions/include.txt32
-rw-r--r--pigeonhole/doc/extensions/spamtest-virustest.txt140
-rw-r--r--pigeonhole/doc/extensions/vacation.txt122
-rw-r--r--pigeonhole/doc/extensions/vnd.dovecot.environment.txt48
-rw-r--r--pigeonhole/doc/extensions/vnd.dovecot.report.txt54
-rw-r--r--pigeonhole/doc/locations/Makefile.am13
-rw-r--r--pigeonhole/doc/locations/Makefile.in576
-rw-r--r--pigeonhole/doc/locations/dict.txt145
-rw-r--r--pigeonhole/doc/locations/file.txt48
-rw-r--r--pigeonhole/doc/locations/ldap.txt73
-rw-r--r--pigeonhole/doc/man/Makefile.am46
-rw-r--r--pigeonhole/doc/man/Makefile.in675
-rw-r--r--pigeonhole/doc/man/doveadm-sieve.1.in125
-rw-r--r--pigeonhole/doc/man/global-options-formatter.inc46
-rw-r--r--pigeonhole/doc/man/global-options.inc21
-rw-r--r--pigeonhole/doc/man/option-A.inc27
-rw-r--r--pigeonhole/doc/man/option-S-socket.inc10
-rw-r--r--pigeonhole/doc/man/option-u-user.inc20
-rw-r--r--pigeonhole/doc/man/pigeonhole.7.in99
-rw-r--r--pigeonhole/doc/man/reporting-bugs.inc6
-rw-r--r--pigeonhole/doc/man/sed.sh34
-rw-r--r--pigeonhole/doc/man/sieve-dump.1.in122
-rw-r--r--pigeonhole/doc/man/sieve-filter.1.in253
-rw-r--r--pigeonhole/doc/man/sieve-test.1.in257
-rw-r--r--pigeonhole/doc/man/sievec.1.in142
-rw-r--r--pigeonhole/doc/man/sieved.11
-rw-r--r--pigeonhole/doc/plugins/Makefile.am13
-rw-r--r--pigeonhole/doc/plugins/Makefile.in576
-rw-r--r--pigeonhole/doc/plugins/imap_filter_sieve.txt52
-rw-r--r--pigeonhole/doc/plugins/imapsieve.txt155
-rw-r--r--pigeonhole/doc/plugins/sieve_extprograms.txt182
-rw-r--r--pigeonhole/dovecot-pigeonhole.m462
-rw-r--r--pigeonhole/dummy-config.h.in106
-rw-r--r--pigeonhole/examples/elvey.sieve153
-rw-r--r--pigeonhole/examples/jerry.sieve224
-rw-r--r--pigeonhole/examples/mjohnson.sieve421
-rw-r--r--pigeonhole/examples/mklose.sieve303
-rw-r--r--pigeonhole/examples/relational.rfc5231.sieve33
-rw-r--r--pigeonhole/examples/rfc3028.sieve58
-rw-r--r--pigeonhole/examples/sanjay.sieve171
-rw-r--r--pigeonhole/examples/sieve_examples.sieve73
-rw-r--r--pigeonhole/examples/subaddress.rfc5233.sieve23
-rw-r--r--pigeonhole/examples/vacation.sieve23
-rw-r--r--pigeonhole/examples/vivil.sieve94
-rwxr-xr-xpigeonhole/install-sh541
-rwxr-xr-xpigeonhole/ltmain.sh11251
-rw-r--r--pigeonhole/m4/dovecot.m4609
-rw-r--r--pigeonhole/m4/libtool.m48394
-rw-r--r--pigeonhole/m4/ltoptions.m4437
-rw-r--r--pigeonhole/m4/ltsugar.m4124
-rw-r--r--pigeonhole/m4/ltversion.m423
-rw-r--r--pigeonhole/m4/lt~obsolete.m499
-rwxr-xr-xpigeonhole/missing215
-rw-r--r--pigeonhole/pigeonhole-config.h.in15
-rw-r--r--pigeonhole/pigeonhole-version.h6
-rw-r--r--pigeonhole/src/Makefile.am21
-rw-r--r--pigeonhole/src/Makefile.in709
-rw-r--r--pigeonhole/src/lib-managesieve/Makefile.am15
-rw-r--r--pigeonhole/src/lib-managesieve/Makefile.in691
-rw-r--r--pigeonhole/src/lib-managesieve/managesieve-arg.c207
-rw-r--r--pigeonhole/src/lib-managesieve/managesieve-arg.h117
-rw-r--r--pigeonhole/src/lib-managesieve/managesieve-parser.c757
-rw-r--r--pigeonhole/src/lib-managesieve/managesieve-parser.h67
-rw-r--r--pigeonhole/src/lib-managesieve/managesieve-quote.c121
-rw-r--r--pigeonhole/src/lib-managesieve/managesieve-quote.h17
-rw-r--r--pigeonhole/src/lib-sieve-tool/Makefile.am13
-rw-r--r--pigeonhole/src/lib-sieve-tool/Makefile.in680
-rw-r--r--pigeonhole/src/lib-sieve-tool/sieve-tool.c672
-rw-r--r--pigeonhole/src/lib-sieve-tool/sieve-tool.h100
-rw-r--r--pigeonhole/src/lib-sieve/Makefile.am188
-rw-r--r--pigeonhole/src/lib-sieve/Makefile.in1311
-rw-r--r--pigeonhole/src/lib-sieve/cmd-discard.c173
-rw-r--r--pigeonhole/src/lib-sieve/cmd-if.c277
-rw-r--r--pigeonhole/src/lib-sieve/cmd-keep.c113
-rw-r--r--pigeonhole/src/lib-sieve/cmd-redirect.c677
-rw-r--r--pigeonhole/src/lib-sieve/cmd-require.c86
-rw-r--r--pigeonhole/src/lib-sieve/cmd-stop.c86
-rw-r--r--pigeonhole/src/lib-sieve/cmp-i-ascii-casemap.c99
-rw-r--r--pigeonhole/src/lib-sieve/cmp-i-octet.c97
-rw-r--r--pigeonhole/src/lib-sieve/ext-encoded-character.c271
-rw-r--r--pigeonhole/src/lib-sieve/ext-envelope.c732
-rw-r--r--pigeonhole/src/lib-sieve/ext-fileinto.c225
-rw-r--r--pigeonhole/src/lib-sieve/ext-reject.c606
-rw-r--r--pigeonhole/src/lib-sieve/mcht-contains.c66
-rw-r--r--pigeonhole/src/lib-sieve/mcht-is.c52
-rw-r--r--pigeonhole/src/lib-sieve/mcht-matches.c440
-rw-r--r--pigeonhole/src/lib-sieve/plugins/Makefile.am32
-rw-r--r--pigeonhole/src/lib-sieve/plugins/Makefile.in719
-rw-r--r--pigeonhole/src/lib-sieve/plugins/body/Makefile.am16
-rw-r--r--pigeonhole/src/lib-sieve/plugins/body/Makefile.in692
-rw-r--r--pigeonhole/src/lib-sieve/plugins/body/ext-body-common.c102
-rw-r--r--pigeonhole/src/lib-sieve/plugins/body/ext-body-common.h40
-rw-r--r--pigeonhole/src/lib-sieve/plugins/body/ext-body.c54
-rw-r--r--pigeonhole/src/lib-sieve/plugins/body/tst-body.c385
-rw-r--r--pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile.am8
-rw-r--r--pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile.in674
-rw-r--r--pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c160
-rw-r--r--pigeonhole/src/lib-sieve/plugins/copy/Makefile.am18
-rw-r--r--pigeonhole/src/lib-sieve/plugins/copy/Makefile.in735
-rw-r--r--pigeonhole/src/lib-sieve/plugins/copy/ext-copy.c183
-rw-r--r--pigeonhole/src/lib-sieve/plugins/copy/sieve-ext-copy.h21
-rw-r--r--pigeonhole/src/lib-sieve/plugins/date/Makefile.am16
-rw-r--r--pigeonhole/src/lib-sieve/plugins/date/Makefile.in692
-rw-r--r--pigeonhole/src/lib-sieve/plugins/date/ext-date-common.c593
-rw-r--r--pigeonhole/src/lib-sieve/plugins/date/ext-date-common.h80
-rw-r--r--pigeonhole/src/lib-sieve/plugins/date/ext-date.c62
-rw-r--r--pigeonhole/src/lib-sieve/plugins/date/tst-date.c496
-rw-r--r--pigeonhole/src/lib-sieve/plugins/duplicate/Makefile.am20
-rw-r--r--pigeonhole/src/lib-sieve/plugins/duplicate/Makefile.in697
-rw-r--r--pigeonhole/src/lib-sieve/plugins/duplicate/ext-duplicate-common.c298
-rw-r--r--pigeonhole/src/lib-sieve/plugins/duplicate/ext-duplicate-common.h41
-rw-r--r--pigeonhole/src/lib-sieve/plugins/duplicate/ext-duplicate.c107
-rw-r--r--pigeonhole/src/lib-sieve/plugins/duplicate/tst-duplicate.c449
-rw-r--r--pigeonhole/src/lib-sieve/plugins/editheader/Makefile.am19
-rw-r--r--pigeonhole/src/lib-sieve/plugins/editheader/Makefile.in701
-rw-r--r--pigeonhole/src/lib-sieve/plugins/editheader/cmd-addheader.c337
-rw-r--r--pigeonhole/src/lib-sieve/plugins/editheader/cmd-deleteheader.c551
-rw-r--r--pigeonhole/src/lib-sieve/plugins/editheader/ext-editheader-common.c211
-rw-r--r--pigeonhole/src/lib-sieve/plugins/editheader/ext-editheader-common.h48
-rw-r--r--pigeonhole/src/lib-sieve/plugins/editheader/ext-editheader-limits.h7
-rw-r--r--pigeonhole/src/lib-sieve/plugins/editheader/ext-editheader.c66
-rw-r--r--pigeonhole/src/lib-sieve/plugins/enotify/Makefile.am44
-rw-r--r--pigeonhole/src/lib-sieve/plugins/enotify/Makefile.in904
-rw-r--r--pigeonhole/src/lib-sieve/plugins/enotify/cmd-notify.c621
-rw-r--r--pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-common.c718
-rw-r--r--pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-common.h122
-rw-r--r--pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-limits.h6
-rw-r--r--pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify.c103
-rw-r--r--pigeonhole/src/lib-sieve/plugins/enotify/mailto/Makefile.am16
-rw-r--r--pigeonhole/src/lib-sieve/plugins/enotify/mailto/Makefile.in687
-rw-r--r--pigeonhole/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c794
-rw-r--r--pigeonhole/src/lib-sieve/plugins/enotify/mailto/uri-mailto.c683
-rw-r--r--pigeonhole/src/lib-sieve/plugins/enotify/mailto/uri-mailto.h49
-rw-r--r--pigeonhole/src/lib-sieve/plugins/enotify/sieve-ext-enotify.h197
-rw-r--r--pigeonhole/src/lib-sieve/plugins/enotify/tst-notify-method-capability.c233
-rw-r--r--pigeonhole/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c144
-rw-r--r--pigeonhole/src/lib-sieve/plugins/enotify/vmodf-encodeurl.c119
-rw-r--r--pigeonhole/src/lib-sieve/plugins/environment/Makefile.am24
-rw-r--r--pigeonhole/src/lib-sieve/plugins/environment/Makefile.in753
-rw-r--r--pigeonhole/src/lib-sieve/plugins/environment/ext-environment-common.c339
-rw-r--r--pigeonhole/src/lib-sieve/plugins/environment/ext-environment-common.h53
-rw-r--r--pigeonhole/src/lib-sieve/plugins/environment/ext-environment.c59
-rw-r--r--pigeonhole/src/lib-sieve/plugins/environment/sieve-ext-environment.h54
-rw-r--r--pigeonhole/src/lib-sieve/plugins/environment/tst-environment.c215
-rw-r--r--pigeonhole/src/lib-sieve/plugins/ihave/Makefile.am22
-rw-r--r--pigeonhole/src/lib-sieve/plugins/ihave/Makefile.in707
-rw-r--r--pigeonhole/src/lib-sieve/plugins/ihave/cmd-error.c131
-rw-r--r--pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-binary.c249
-rw-r--r--pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-binary.h33
-rw-r--r--pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-common.c52
-rw-r--r--pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-common.h52
-rw-r--r--pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave.c70
-rw-r--r--pigeonhole/src/lib-sieve/plugins/ihave/tst-ihave.c294
-rw-r--r--pigeonhole/src/lib-sieve/plugins/imap4flags/Makefile.am33
-rw-r--r--pigeonhole/src/lib-sieve/plugins/imap4flags/Makefile.in776
-rw-r--r--pigeonhole/src/lib-sieve/plugins/imap4flags/cmd-flag.c251
-rw-r--r--pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c733
-rw-r--r--pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h97
-rw-r--r--pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags.c96
-rw-r--r--pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imapflags.c213
-rw-r--r--pigeonhole/src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h74
-rw-r--r--pigeonhole/src/lib-sieve/plugins/imap4flags/tag-flags.c402
-rw-r--r--pigeonhole/src/lib-sieve/plugins/imap4flags/tst-hasflag.c248
-rw-r--r--pigeonhole/src/lib-sieve/plugins/include/Makefile.am24
-rw-r--r--pigeonhole/src/lib-sieve/plugins/include/Makefile.in718
-rw-r--r--pigeonhole/src/lib-sieve/plugins/include/cmd-global.c329
-rw-r--r--pigeonhole/src/lib-sieve/plugins/include/cmd-include.c406
-rw-r--r--pigeonhole/src/lib-sieve/plugins/include/cmd-return.c71
-rw-r--r--pigeonhole/src/lib-sieve/plugins/include/ext-include-binary.c492
-rw-r--r--pigeonhole/src/lib-sieve/plugins/include/ext-include-binary.h64
-rw-r--r--pigeonhole/src/lib-sieve/plugins/include/ext-include-common.c892
-rw-r--r--pigeonhole/src/lib-sieve/plugins/include/ext-include-common.h170
-rw-r--r--pigeonhole/src/lib-sieve/plugins/include/ext-include-limits.h9
-rw-r--r--pigeonhole/src/lib-sieve/plugins/include/ext-include-variables.c254
-rw-r--r--pigeonhole/src/lib-sieve/plugins/include/ext-include-variables.h41
-rw-r--r--pigeonhole/src/lib-sieve/plugins/include/ext-include.c121
-rw-r--r--pigeonhole/src/lib-sieve/plugins/index/Makefile.am13
-rw-r--r--pigeonhole/src/lib-sieve/plugins/index/Makefile.in688
-rw-r--r--pigeonhole/src/lib-sieve/plugins/index/ext-index-common.c15
-rw-r--r--pigeonhole/src/lib-sieve/plugins/index/ext-index-common.h29
-rw-r--r--pigeonhole/src/lib-sieve/plugins/index/ext-index.c69
-rw-r--r--pigeonhole/src/lib-sieve/plugins/index/tag-index.c278
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mailbox/Makefile.am26
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mailbox/Makefile.in757
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mailbox/ext-mailbox-common.h39
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mailbox/ext-mailbox.c72
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mailbox/sieve-ext-mailbox.h21
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mailbox/tag-mailbox-create.c186
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mailbox/tst-mailboxexists.c284
-rw-r--r--pigeonhole/src/lib-sieve/plugins/metadata/Makefile.am24
-rw-r--r--pigeonhole/src/lib-sieve/plugins/metadata/Makefile.in705
-rw-r--r--pigeonhole/src/lib-sieve/plugins/metadata/ext-metadata-common.h40
-rw-r--r--pigeonhole/src/lib-sieve/plugins/metadata/ext-metadata.c83
-rw-r--r--pigeonhole/src/lib-sieve/plugins/metadata/tst-metadata.c433
-rw-r--r--pigeonhole/src/lib-sieve/plugins/metadata/tst-metadataexists.c431
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mime/Makefile.am30
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mime/Makefile.in727
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mime/cmd-break.c273
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mime/cmd-extracttext.c370
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mime/cmd-foreverypart.c377
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mime/ext-extracttext.c130
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mime/ext-foreverypart.c62
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mime/ext-mime-common.c27
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mime/ext-mime-common.h85
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mime/ext-mime.c77
-rw-r--r--pigeonhole/src/lib-sieve/plugins/mime/tag-mime.c757
-rw-r--r--pigeonhole/src/lib-sieve/plugins/notify/Makefile.am20
-rw-r--r--pigeonhole/src/lib-sieve/plugins/notify/Makefile.in699
-rw-r--r--pigeonhole/src/lib-sieve/plugins/notify/cmd-denotify.c389
-rw-r--r--pigeonhole/src/lib-sieve/plugins/notify/cmd-notify.c900
-rw-r--r--pigeonhole/src/lib-sieve/plugins/notify/ext-notify-common.c361
-rw-r--r--pigeonhole/src/lib-sieve/plugins/notify/ext-notify-common.h66
-rw-r--r--pigeonhole/src/lib-sieve/plugins/notify/ext-notify-limits.h7
-rw-r--r--pigeonhole/src/lib-sieve/plugins/notify/ext-notify.c108
-rw-r--r--pigeonhole/src/lib-sieve/plugins/regex/Makefile.am13
-rw-r--r--pigeonhole/src/lib-sieve/plugins/regex/Makefile.in688
-rw-r--r--pigeonhole/src/lib-sieve/plugins/regex/ext-regex-common.c22
-rw-r--r--pigeonhole/src/lib-sieve/plugins/regex/ext-regex-common.h24
-rw-r--r--pigeonhole/src/lib-sieve/plugins/regex/ext-regex.c65
-rw-r--r--pigeonhole/src/lib-sieve/plugins/regex/mcht-regex.c385
-rw-r--r--pigeonhole/src/lib-sieve/plugins/relational/Makefile.am14
-rw-r--r--pigeonhole/src/lib-sieve/plugins/relational/Makefile.in694
-rw-r--r--pigeonhole/src/lib-sieve/plugins/relational/ext-relational-common.c171
-rw-r--r--pigeonhole/src/lib-sieve/plugins/relational/ext-relational-common.h86
-rw-r--r--pigeonhole/src/lib-sieve/plugins/relational/ext-relational.c53
-rw-r--r--pigeonhole/src/lib-sieve/plugins/relational/mcht-count.c119
-rw-r--r--pigeonhole/src/lib-sieve/plugins/relational/mcht-value.c80
-rw-r--r--pigeonhole/src/lib-sieve/plugins/spamvirustest/Makefile.am16
-rw-r--r--pigeonhole/src/lib-sieve/plugins/spamvirustest/Makefile.in694
-rw-r--r--pigeonhole/src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c674
-rw-r--r--pigeonhole/src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h35
-rw-r--r--pigeonhole/src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c146
-rw-r--r--pigeonhole/src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c304
-rw-r--r--pigeonhole/src/lib-sieve/plugins/special-use/Makefile.am22
-rw-r--r--pigeonhole/src/lib-sieve/plugins/special-use/Makefile.in703
-rw-r--r--pigeonhole/src/lib-sieve/plugins/special-use/ext-special-use-common.c31
-rw-r--r--pigeonhole/src/lib-sieve/plugins/special-use/ext-special-use-common.h43
-rw-r--r--pigeonhole/src/lib-sieve/plugins/special-use/ext-special-use.c57
-rw-r--r--pigeonhole/src/lib-sieve/plugins/special-use/tag-specialuse.c316
-rw-r--r--pigeonhole/src/lib-sieve/plugins/special-use/tst-specialuse-exists.c525
-rw-r--r--pigeonhole/src/lib-sieve/plugins/subaddress/Makefile.am8
-rw-r--r--pigeonhole/src/lib-sieve/plugins/subaddress/Makefile.in673
-rw-r--r--pigeonhole/src/lib-sieve/plugins/subaddress/ext-subaddress.c191
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vacation/Makefile.am19
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vacation/Makefile.in700
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vacation/cmd-vacation.c1578
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vacation/ext-vacation-common.c114
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vacation/ext-vacation-common.h60
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vacation/ext-vacation-seconds.c66
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vacation/ext-vacation.c131
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/Makefile.am41
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/Makefile.in801
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/cmd-set.c235
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/ext-variables-arguments.c420
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/ext-variables-arguments.h24
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/ext-variables-common.c950
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/ext-variables-common.h102
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/ext-variables-dump.c137
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/ext-variables-dump.h22
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/ext-variables-limits.h35
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/ext-variables-modifiers.c578
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/ext-variables-modifiers.h66
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/ext-variables-name.c110
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/ext-variables-name.h43
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/ext-variables-namespaces.c236
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/ext-variables-namespaces.h43
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/ext-variables-operands.c279
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/ext-variables-operands.h37
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/ext-variables.c84
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/sieve-ext-variables.h364
-rw-r--r--pigeonhole/src/lib-sieve/plugins/variables/tst-string.c271
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/Makefile.am2
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/Makefile.in692
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/Makefile.am15
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/Makefile.in687
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/cmd-debug-log.c130
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug-common.h22
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c70
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/Makefile.am16
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/Makefile.in692
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-common.h37
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-items.c95
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-variables.c206
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment.c112
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/Makefile.am17
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/Makefile.in695
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c692
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.c51
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.h40
-rw-r--r--pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report.c52
-rw-r--r--pigeonhole/src/lib-sieve/sieve-actions.c1096
-rw-r--r--pigeonhole/src/lib-sieve/sieve-actions.h311
-rw-r--r--pigeonhole/src/lib-sieve/sieve-address-parts.c495
-rw-r--r--pigeonhole/src/lib-sieve/sieve-address-parts.h135
-rw-r--r--pigeonhole/src/lib-sieve/sieve-address-source.c119
-rw-r--r--pigeonhole/src/lib-sieve/sieve-address-source.h36
-rw-r--r--pigeonhole/src/lib-sieve/sieve-address.c558
-rw-r--r--pigeonhole/src/lib-sieve/sieve-address.h67
-rw-r--r--pigeonhole/src/lib-sieve/sieve-ast.c1111
-rw-r--r--pigeonhole/src/lib-sieve/sieve-ast.h382
-rw-r--r--pigeonhole/src/lib-sieve/sieve-binary-code.c405
-rw-r--r--pigeonhole/src/lib-sieve/sieve-binary-debug.c276
-rw-r--r--pigeonhole/src/lib-sieve/sieve-binary-dumper.c326
-rw-r--r--pigeonhole/src/lib-sieve/sieve-binary-dumper.h41
-rw-r--r--pigeonhole/src/lib-sieve/sieve-binary-file.c1042
-rw-r--r--pigeonhole/src/lib-sieve/sieve-binary-private.h240
-rw-r--r--pigeonhole/src/lib-sieve/sieve-binary.c606
-rw-r--r--pigeonhole/src/lib-sieve/sieve-binary.h291
-rw-r--r--pigeonhole/src/lib-sieve/sieve-code-dumper.c351
-rw-r--r--pigeonhole/src/lib-sieve/sieve-code-dumper.h55
-rw-r--r--pigeonhole/src/lib-sieve/sieve-code.c1169
-rw-r--r--pigeonhole/src/lib-sieve/sieve-code.h351
-rw-r--r--pigeonhole/src/lib-sieve/sieve-commands.c403
-rw-r--r--pigeonhole/src/lib-sieve/sieve-commands.h286
-rw-r--r--pigeonhole/src/lib-sieve/sieve-common.h240
-rw-r--r--pigeonhole/src/lib-sieve/sieve-comparators.c260
-rw-r--r--pigeonhole/src/lib-sieve/sieve-comparators.h153
-rw-r--r--pigeonhole/src/lib-sieve/sieve-config.h16
-rw-r--r--pigeonhole/src/lib-sieve/sieve-dump.h30
-rw-r--r--pigeonhole/src/lib-sieve/sieve-error-private.h67
-rw-r--r--pigeonhole/src/lib-sieve/sieve-error.c1064
-rw-r--r--pigeonhole/src/lib-sieve/sieve-error.h235
-rw-r--r--pigeonhole/src/lib-sieve/sieve-execute.c162
-rw-r--r--pigeonhole/src/lib-sieve/sieve-execute.h42
-rw-r--r--pigeonhole/src/lib-sieve/sieve-extensions.c879
-rw-r--r--pigeonhole/src/lib-sieve/sieve-extensions.h191
-rw-r--r--pigeonhole/src/lib-sieve/sieve-generator.c578
-rw-r--r--pigeonhole/src/lib-sieve/sieve-generator.h121
-rw-r--r--pigeonhole/src/lib-sieve/sieve-interpreter.c1196
-rw-r--r--pigeonhole/src/lib-sieve/sieve-interpreter.h204
-rw-r--r--pigeonhole/src/lib-sieve/sieve-lexer.c930
-rw-r--r--pigeonhole/src/lib-sieve/sieve-lexer.h119
-rw-r--r--pigeonhole/src/lib-sieve/sieve-limits.h45
-rw-r--r--pigeonhole/src/lib-sieve/sieve-match-types.c569
-rw-r--r--pigeonhole/src/lib-sieve/sieve-match-types.h233
-rw-r--r--pigeonhole/src/lib-sieve/sieve-match.c293
-rw-r--r--pigeonhole/src/lib-sieve/sieve-match.h68
-rw-r--r--pigeonhole/src/lib-sieve/sieve-message.c1845
-rw-r--r--pigeonhole/src/lib-sieve/sieve-message.h280
-rw-r--r--pigeonhole/src/lib-sieve/sieve-objects.c111
-rw-r--r--pigeonhole/src/lib-sieve/sieve-objects.h67
-rw-r--r--pigeonhole/src/lib-sieve/sieve-parser.c670
-rw-r--r--pigeonhole/src/lib-sieve/sieve-parser.h17
-rw-r--r--pigeonhole/src/lib-sieve/sieve-plugins.c181
-rw-r--r--pigeonhole/src/lib-sieve/sieve-plugins.h9
-rw-r--r--pigeonhole/src/lib-sieve/sieve-result.c2445
-rw-r--r--pigeonhole/src/lib-sieve/sieve-result.h224
-rw-r--r--pigeonhole/src/lib-sieve/sieve-runtime-trace.c151
-rw-r--r--pigeonhole/src/lib-sieve/sieve-runtime-trace.h182
-rw-r--r--pigeonhole/src/lib-sieve/sieve-runtime.h40
-rw-r--r--pigeonhole/src/lib-sieve/sieve-script-private.h100
-rw-r--r--pigeonhole/src/lib-sieve/sieve-script.c906
-rw-r--r--pigeonhole/src/lib-sieve/sieve-script.h163
-rw-r--r--pigeonhole/src/lib-sieve/sieve-settings.c270
-rw-r--r--pigeonhole/src/lib-sieve/sieve-settings.h57
-rw-r--r--pigeonhole/src/lib-sieve/sieve-smtp.c95
-rw-r--r--pigeonhole/src/lib-sieve/sieve-smtp.h31
-rw-r--r--pigeonhole/src/lib-sieve/sieve-storage-private.h256
-rw-r--r--pigeonhole/src/lib-sieve/sieve-storage-sync.c195
-rw-r--r--pigeonhole/src/lib-sieve/sieve-storage.c1590
-rw-r--r--pigeonhole/src/lib-sieve/sieve-storage.h187
-rw-r--r--pigeonhole/src/lib-sieve/sieve-stringlist.c276
-rw-r--r--pigeonhole/src/lib-sieve/sieve-stringlist.h74
-rw-r--r--pigeonhole/src/lib-sieve/sieve-types.h316
-rw-r--r--pigeonhole/src/lib-sieve/sieve-validator.c1706
-rw-r--r--pigeonhole/src/lib-sieve/sieve-validator.h197
-rw-r--r--pigeonhole/src/lib-sieve/sieve.c1303
-rw-r--r--pigeonhole/src/lib-sieve/sieve.h261
-rw-r--r--pigeonhole/src/lib-sieve/storage/Makefile.am5
-rw-r--r--pigeonhole/src/lib-sieve/storage/Makefile.in697
-rw-r--r--pigeonhole/src/lib-sieve/storage/data/Makefile.am13
-rw-r--r--pigeonhole/src/lib-sieve/storage/data/Makefile.in686
-rw-r--r--pigeonhole/src/lib-sieve/storage/data/sieve-data-script.c95
-rw-r--r--pigeonhole/src/lib-sieve/storage/data/sieve-data-storage.c47
-rw-r--r--pigeonhole/src/lib-sieve/storage/data/sieve-data-storage.h30
-rw-r--r--pigeonhole/src/lib-sieve/storage/dict/Makefile.am13
-rw-r--r--pigeonhole/src/lib-sieve/storage/dict/Makefile.in686
-rw-r--r--pigeonhole/src/lib-sieve/storage/dict/sieve-dict-script.c343
-rw-r--r--pigeonhole/src/lib-sieve/storage/dict/sieve-dict-storage.c193
-rw-r--r--pigeonhole/src/lib-sieve/storage/dict/sieve-dict-storage.h66
-rw-r--r--pigeonhole/src/lib-sieve/storage/file/Makefile.am19
-rw-r--r--pigeonhole/src/lib-sieve/storage/file/Makefile.in714
-rw-r--r--pigeonhole/src/lib-sieve/storage/file/sieve-file-script-sequence.c244
-rw-r--r--pigeonhole/src/lib-sieve/storage/file/sieve-file-script.c832
-rw-r--r--pigeonhole/src/lib-sieve/storage/file/sieve-file-storage-active.c403
-rw-r--r--pigeonhole/src/lib-sieve/storage/file/sieve-file-storage-list.c140
-rw-r--r--pigeonhole/src/lib-sieve/storage/file/sieve-file-storage-quota.c120
-rw-r--r--pigeonhole/src/lib-sieve/storage/file/sieve-file-storage-save.c544
-rw-r--r--pigeonhole/src/lib-sieve/storage/file/sieve-file-storage.c918
-rw-r--r--pigeonhole/src/lib-sieve/storage/file/sieve-file-storage.h186
-rw-r--r--pigeonhole/src/lib-sieve/storage/ldap/Makefile.am32
-rw-r--r--pigeonhole/src/lib-sieve/storage/ldap/Makefile.in843
-rw-r--r--pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-db.c1378
-rw-r--r--pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-db.h140
-rw-r--r--pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-script.c369
-rw-r--r--pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-storage-settings.c169
-rw-r--r--pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-storage.c230
-rw-r--r--pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-storage.h108
-rw-r--r--pigeonhole/src/lib-sieve/tst-address.c280
-rw-r--r--pigeonhole/src/lib-sieve/tst-allof.c108
-rw-r--r--pigeonhole/src/lib-sieve/tst-anyof.c107
-rw-r--r--pigeonhole/src/lib-sieve/tst-exists.c179
-rw-r--r--pigeonhole/src/lib-sieve/tst-header.c204
-rw-r--r--pigeonhole/src/lib-sieve/tst-not.c67
-rw-r--r--pigeonhole/src/lib-sieve/tst-size.c318
-rw-r--r--pigeonhole/src/lib-sieve/tst-truefalse.c104
-rw-r--r--pigeonhole/src/lib-sieve/util/Makefile.am51
-rw-r--r--pigeonhole/src/lib-sieve/util/Makefile.in810
-rw-r--r--pigeonhole/src/lib-sieve/util/edit-mail.c2254
-rw-r--r--pigeonhole/src/lib-sieve/util/edit-mail.h47
-rw-r--r--pigeonhole/src/lib-sieve/util/mail-raw.c247
-rw-r--r--pigeonhole/src/lib-sieve/util/mail-raw.h27
-rw-r--r--pigeonhole/src/lib-sieve/util/rfc2822.c277
-rw-r--r--pigeonhole/src/lib-sieve/util/rfc2822.h46
-rw-r--r--pigeonhole/src/lib-sieve/util/test-edit-mail.c842
-rw-r--r--pigeonhole/src/lib-sieve/util/test-rfc2822.c197
-rw-r--r--pigeonhole/src/managesieve-login/Makefile.am43
-rw-r--r--pigeonhole/src/managesieve-login/Makefile.in931
-rw-r--r--pigeonhole/src/managesieve-login/client-authenticate.c308
-rw-r--r--pigeonhole/src/managesieve-login/client-authenticate.h21
-rw-r--r--pigeonhole/src/managesieve-login/client.c574
-rw-r--r--pigeonhole/src/managesieve-login/client.h76
-rw-r--r--pigeonhole/src/managesieve-login/managesieve-login-settings-plugin.c223
-rw-r--r--pigeonhole/src/managesieve-login/managesieve-login-settings-plugin.h9
-rw-r--r--pigeonhole/src/managesieve-login/managesieve-login-settings.c104
-rw-r--r--pigeonhole/src/managesieve-login/managesieve-login-settings.h17
-rw-r--r--pigeonhole/src/managesieve-login/managesieve-proxy.c686
-rw-r--r--pigeonhole/src/managesieve-login/managesieve-proxy.h12
-rw-r--r--pigeonhole/src/managesieve/Makefile.am59
-rw-r--r--pigeonhole/src/managesieve/Makefile.in1134
-rw-r--r--pigeonhole/src/managesieve/cmd-capability.c76
-rw-r--r--pigeonhole/src/managesieve/cmd-deletescript.c43
-rw-r--r--pigeonhole/src/managesieve/cmd-getscript.c157
-rw-r--r--pigeonhole/src/managesieve/cmd-havespace.c60
-rw-r--r--pigeonhole/src/managesieve/cmd-listscripts.c65
-rw-r--r--pigeonhole/src/managesieve/cmd-logout.c21
-rw-r--r--pigeonhole/src/managesieve/cmd-noop.c46
-rw-r--r--pigeonhole/src/managesieve/cmd-putscript.c578
-rw-r--r--pigeonhole/src/managesieve/cmd-renamescript.c54
-rw-r--r--pigeonhole/src/managesieve/cmd-setactive.c165
-rw-r--r--pigeonhole/src/managesieve/main.c401
-rw-r--r--pigeonhole/src/managesieve/managesieve-capabilities.c136
-rw-r--r--pigeonhole/src/managesieve/managesieve-capabilities.h6
-rw-r--r--pigeonhole/src/managesieve/managesieve-client.c792
-rw-r--r--pigeonhole/src/managesieve/managesieve-client.h162
-rw-r--r--pigeonhole/src/managesieve/managesieve-commands.c110
-rw-r--r--pigeonhole/src/managesieve/managesieve-commands.h46
-rw-r--r--pigeonhole/src/managesieve/managesieve-common.h31
-rw-r--r--pigeonhole/src/managesieve/managesieve-quota.c98
-rw-r--r--pigeonhole/src/managesieve/managesieve-quota.h11
-rw-r--r--pigeonhole/src/managesieve/managesieve-settings.c170
-rw-r--r--pigeonhole/src/managesieve/managesieve-settings.h29
-rw-r--r--pigeonhole/src/plugins/Makefile.am7
-rw-r--r--pigeonhole/src/plugins/Makefile.in699
-rw-r--r--pigeonhole/src/plugins/doveadm-sieve/Makefile.am31
-rw-r--r--pigeonhole/src/plugins/doveadm-sieve/Makefile.in796
-rw-r--r--pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-activate.c145
-rw-r--r--pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-delete.c116
-rw-r--r--pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-get.c83
-rw-r--r--pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-list.c79
-rw-r--r--pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-put.c189
-rw-r--r--pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-rename.c83
-rw-r--r--pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd.c179
-rw-r--r--pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd.h43
-rw-r--r--pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-plugin.c24
-rw-r--r--pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-plugin.h17
-rw-r--r--pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-sync.c746
-rw-r--r--pigeonhole/src/plugins/imap-filter-sieve/Makefile.am26
-rw-r--r--pigeonhole/src/plugins/imap-filter-sieve/Makefile.in771
-rw-r--r--pigeonhole/src/plugins/imap-filter-sieve/cmd-filter-sieve.c403
-rw-r--r--pigeonhole/src/plugins/imap-filter-sieve/cmd-filter.c57
-rw-r--r--pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.c56
-rw-r--r--pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.h16
-rw-r--r--pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve.c1188
-rw-r--r--pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve.h97
-rw-r--r--pigeonhole/src/plugins/imap-filter-sieve/imap-filter.c273
-rw-r--r--pigeonhole/src/plugins/imap-filter-sieve/imap-filter.h43
-rw-r--r--pigeonhole/src/plugins/imapsieve/Makefile.am40
-rw-r--r--pigeonhole/src/plugins/imapsieve/Makefile.in864
-rw-r--r--pigeonhole/src/plugins/imapsieve/ext-imapsieve-common.h29
-rw-r--r--pigeonhole/src/plugins/imapsieve/ext-imapsieve-environment.c184
-rw-r--r--pigeonhole/src/plugins/imapsieve/ext-imapsieve.c168
-rw-r--r--pigeonhole/src/plugins/imapsieve/imap-sieve-plugin.c60
-rw-r--r--pigeonhole/src/plugins/imapsieve/imap-sieve-plugin.h11
-rw-r--r--pigeonhole/src/plugins/imapsieve/imap-sieve-storage.c1273
-rw-r--r--pigeonhole/src/plugins/imapsieve/imap-sieve-storage.h10
-rw-r--r--pigeonhole/src/plugins/imapsieve/imap-sieve.c940
-rw-r--r--pigeonhole/src/plugins/imapsieve/imap-sieve.h59
-rw-r--r--pigeonhole/src/plugins/imapsieve/sieve-imapsieve-plugin.c62
-rw-r--r--pigeonhole/src/plugins/imapsieve/sieve-imapsieve-plugin.h20
-rw-r--r--pigeonhole/src/plugins/lda-sieve/Makefile.am19
-rw-r--r--pigeonhole/src/plugins/lda-sieve/Makefile.in746
-rw-r--r--pigeonhole/src/plugins/lda-sieve/lda-sieve-plugin.c1128
-rw-r--r--pigeonhole/src/plugins/lda-sieve/lda-sieve-plugin.h11
-rw-r--r--pigeonhole/src/plugins/settings/Makefile.am12
-rw-r--r--pigeonhole/src/plugins/settings/Makefile.in737
-rw-r--r--pigeonhole/src/plugins/settings/pigeonhole-settings.c13
-rw-r--r--pigeonhole/src/plugins/sieve-extprograms/Makefile.am34
-rw-r--r--pigeonhole/src/plugins/sieve-extprograms/Makefile.in790
-rw-r--r--pigeonhole/src/plugins/sieve-extprograms/cmd-execute.c488
-rw-r--r--pigeonhole/src/plugins/sieve-extprograms/cmd-filter.c254
-rw-r--r--pigeonhole/src/plugins/sieve-extprograms/cmd-pipe.c457
-rw-r--r--pigeonhole/src/plugins/sieve-extprograms/ext-execute.c80
-rw-r--r--pigeonhole/src/plugins/sieve-extprograms/ext-filter.c80
-rw-r--r--pigeonhole/src/plugins/sieve-extprograms/ext-pipe.c114
-rw-r--r--pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-common.c648
-rw-r--r--pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-common.h107
-rw-r--r--pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-plugin.c68
-rw-r--r--pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-plugin.h20
-rw-r--r--pigeonhole/src/sieve-tools/Makefile.am59
-rw-r--r--pigeonhole/src/sieve-tools/Makefile.in863
-rw-r--r--pigeonhole/src/sieve-tools/sieve-dump.c97
-rw-r--r--pigeonhole/src/sieve-tools/sieve-filter.c614
-rw-r--r--pigeonhole/src/sieve-tools/sieve-test.c515
-rw-r--r--pigeonhole/src/sieve-tools/sievec.c157
-rw-r--r--pigeonhole/src/testsuite/Makefile.am74
-rw-r--r--pigeonhole/src/testsuite/Makefile.in869
-rw-r--r--pigeonhole/src/testsuite/cmd-test-binary.c208
-rw-r--r--pigeonhole/src/testsuite/cmd-test-config.c504
-rw-r--r--pigeonhole/src/testsuite/cmd-test-fail.c129
-rw-r--r--pigeonhole/src/testsuite/cmd-test-imap-metadata.c284
-rw-r--r--pigeonhole/src/testsuite/cmd-test-mailbox.c261
-rw-r--r--pigeonhole/src/testsuite/cmd-test-message.c569
-rw-r--r--pigeonhole/src/testsuite/cmd-test-result.c138
-rw-r--r--pigeonhole/src/testsuite/cmd-test-set.c161
-rw-r--r--pigeonhole/src/testsuite/cmd-test.c208
-rw-r--r--pigeonhole/src/testsuite/ext-testsuite.c175
-rw-r--r--pigeonhole/src/testsuite/testsuite-arguments.c190
-rw-r--r--pigeonhole/src/testsuite/testsuite-arguments.h6
-rw-r--r--pigeonhole/src/testsuite/testsuite-binary.c82
-rw-r--r--pigeonhole/src/testsuite/testsuite-binary.h17
-rw-r--r--pigeonhole/src/testsuite/testsuite-common.c374
-rw-r--r--pigeonhole/src/testsuite/testsuite-common.h193
-rw-r--r--pigeonhole/src/testsuite/testsuite-log.c319
-rw-r--r--pigeonhole/src/testsuite/testsuite-log.h26
-rw-r--r--pigeonhole/src/testsuite/testsuite-mailstore.c349
-rw-r--r--pigeonhole/src/testsuite/testsuite-mailstore.h40
-rw-r--r--pigeonhole/src/testsuite/testsuite-message.c339
-rw-r--r--pigeonhole/src/testsuite/testsuite-message.h44
-rw-r--r--pigeonhole/src/testsuite/testsuite-objects.c369
-rw-r--r--pigeonhole/src/testsuite/testsuite-objects.h83
-rw-r--r--pigeonhole/src/testsuite/testsuite-result.c206
-rw-r--r--pigeonhole/src/testsuite/testsuite-result.h25
-rw-r--r--pigeonhole/src/testsuite/testsuite-script.c256
-rw-r--r--pigeonhole/src/testsuite/testsuite-script.h22
-rw-r--r--pigeonhole/src/testsuite/testsuite-settings.c96
-rw-r--r--pigeonhole/src/testsuite/testsuite-settings.h12
-rw-r--r--pigeonhole/src/testsuite/testsuite-smtp.c176
-rw-r--r--pigeonhole/src/testsuite/testsuite-smtp.h35
-rw-r--r--pigeonhole/src/testsuite/testsuite-substitutions.c253
-rw-r--r--pigeonhole/src/testsuite/testsuite-substitutions.h23
-rw-r--r--pigeonhole/src/testsuite/testsuite-variables.c183
-rw-r--r--pigeonhole/src/testsuite/testsuite-variables.h11
-rw-r--r--pigeonhole/src/testsuite/testsuite.c256
-rw-r--r--pigeonhole/src/testsuite/tst-test-error.c273
-rw-r--r--pigeonhole/src/testsuite/tst-test-multiscript.c155
-rw-r--r--pigeonhole/src/testsuite/tst-test-result-action.c268
-rw-r--r--pigeonhole/src/testsuite/tst-test-result-execute.c96
-rw-r--r--pigeonhole/src/testsuite/tst-test-script-compile.c144
-rw-r--r--pigeonhole/src/testsuite/tst-test-script-run.c198
-rw-r--r--pigeonhole/stamp.h.in1
-rw-r--r--pigeonhole/tests/comparators/i-ascii-casemap.svtest39
-rw-r--r--pigeonhole/tests/comparators/i-octet.svtest37
-rw-r--r--pigeonhole/tests/compile/compile.svtest16
-rw-r--r--pigeonhole/tests/compile/errors.svtest395
-rw-r--r--pigeonhole/tests/compile/errors/address-part.sieve17
-rw-r--r--pigeonhole/tests/compile/errors/address.sieve71
-rw-r--r--pigeonhole/tests/compile/errors/comparator.sieve21
-rw-r--r--pigeonhole/tests/compile/errors/encoded-character.sieve23
-rw-r--r--pigeonhole/tests/compile/errors/envelope.sieve23
-rw-r--r--pigeonhole/tests/compile/errors/fileinto.sieve38
-rw-r--r--pigeonhole/tests/compile/errors/header.sieve57
-rw-r--r--pigeonhole/tests/compile/errors/if.sieve78
-rw-r--r--pigeonhole/tests/compile/errors/keep.sieve14
-rw-r--r--pigeonhole/tests/compile/errors/lexer.sieve68
-rw-r--r--pigeonhole/tests/compile/errors/match-type.sieve7
-rw-r--r--pigeonhole/tests/compile/errors/out-address.sieve33
-rw-r--r--pigeonhole/tests/compile/errors/parser.sieve78
-rw-r--r--pigeonhole/tests/compile/errors/require.sieve42
-rw-r--r--pigeonhole/tests/compile/errors/size.sieve47
-rw-r--r--pigeonhole/tests/compile/errors/stop.sieve33
-rw-r--r--pigeonhole/tests/compile/errors/tag.sieve16
-rw-r--r--pigeonhole/tests/compile/errors/typos.sieve29
-rw-r--r--pigeonhole/tests/compile/errors/unsupported.sieve30
-rw-r--r--pigeonhole/tests/compile/recover.svtest50
-rw-r--r--pigeonhole/tests/compile/recover/commands-endblock.sieve27
-rw-r--r--pigeonhole/tests/compile/recover/commands-semicolon.sieve16
-rw-r--r--pigeonhole/tests/compile/recover/tests-endcomma.sieve17
-rw-r--r--pigeonhole/tests/compile/redirect.sieve23
-rw-r--r--pigeonhole/tests/compile/trivial.sieve17
-rw-r--r--pigeonhole/tests/compile/warnings.svtest8
-rw-r--r--pigeonhole/tests/compile/warnings/eof.sieve2
-rw-r--r--pigeonhole/tests/compile/warnings/invalid-headers.sieve14
-rw-r--r--pigeonhole/tests/control-if.svtest292
-rw-r--r--pigeonhole/tests/control-stop.svtest29
-rw-r--r--pigeonhole/tests/deprecated/imapflags/errors.svtest24
-rw-r--r--pigeonhole/tests/deprecated/imapflags/errors/conflict-ihave.sieve6
-rw-r--r--pigeonhole/tests/deprecated/imapflags/errors/conflict.sieve4
-rw-r--r--pigeonhole/tests/deprecated/imapflags/execute.svtest92
-rw-r--r--pigeonhole/tests/deprecated/imapflags/execute/flags.sieve12
-rw-r--r--pigeonhole/tests/deprecated/imapflags/execute/mark.sieve11
-rw-r--r--pigeonhole/tests/deprecated/notify/basic.svtest59
-rw-r--r--pigeonhole/tests/deprecated/notify/denotify.svtest279
-rw-r--r--pigeonhole/tests/deprecated/notify/errors.svtest33
-rw-r--r--pigeonhole/tests/deprecated/notify/errors/conflict-ihave.sieve8
-rw-r--r--pigeonhole/tests/deprecated/notify/errors/conflict.sieve4
-rw-r--r--pigeonhole/tests/deprecated/notify/errors/options.sieve11
-rw-r--r--pigeonhole/tests/deprecated/notify/execute.svtest25
-rw-r--r--pigeonhole/tests/deprecated/notify/execute/duplicates.sieve4
-rw-r--r--pigeonhole/tests/deprecated/notify/mailto.svtest317
-rw-r--r--pigeonhole/tests/execute/actions.svtest80
-rw-r--r--pigeonhole/tests/execute/actions/fileinto.sieve17
-rw-r--r--pigeonhole/tests/execute/actions/redirect.sieve17
-rw-r--r--pigeonhole/tests/execute/address-normalize.svtest46
-rw-r--r--pigeonhole/tests/execute/errors-cpu-limit.svtest363
-rw-r--r--pigeonhole/tests/execute/errors.svtest152
-rw-r--r--pigeonhole/tests/execute/errors/action-duplicates.sieve4
-rw-r--r--pigeonhole/tests/execute/errors/actions-limit.sieve35
-rw-r--r--pigeonhole/tests/execute/errors/conflict-reject-fileinto.sieve5
-rw-r--r--pigeonhole/tests/execute/errors/conflict-reject-keep.sieve4
-rw-r--r--pigeonhole/tests/execute/errors/conflict-reject-redirect.sieve4
-rw-r--r--pigeonhole/tests/execute/errors/cpu-limit.sieve145
-rw-r--r--pigeonhole/tests/execute/errors/fileinto-bad-utf8.sieve7
-rw-r--r--pigeonhole/tests/execute/errors/fileinto-invalid-name.sieve5
-rw-r--r--pigeonhole/tests/execute/errors/fileinto.sieve3
-rw-r--r--pigeonhole/tests/execute/errors/redirect-limit.sieve5
-rw-r--r--pigeonhole/tests/execute/examples.svtest115
-rw-r--r--pigeonhole/tests/execute/mailstore.svtest84
-rw-r--r--pigeonhole/tests/execute/smtp.svtest449
-rw-r--r--pigeonhole/tests/extensions/body/basic.svtest97
-rw-r--r--pigeonhole/tests/extensions/body/content.svtest332
-rw-r--r--pigeonhole/tests/extensions/body/errors.svtest19
-rw-r--r--pigeonhole/tests/extensions/body/errors/syntax.sieve38
-rw-r--r--pigeonhole/tests/extensions/body/match-values.svtest55
-rw-r--r--pigeonhole/tests/extensions/body/raw.svtest85
-rw-r--r--pigeonhole/tests/extensions/body/text.svtest225
-rw-r--r--pigeonhole/tests/extensions/date/basic.svtest73
-rw-r--r--pigeonhole/tests/extensions/date/date-parts.svtest120
-rw-r--r--pigeonhole/tests/extensions/date/zones.svtest76
-rw-r--r--pigeonhole/tests/extensions/duplicate/errors.svtest54
-rw-r--r--pigeonhole/tests/extensions/duplicate/errors/conflict-vnd.sieve4
-rw-r--r--pigeonhole/tests/extensions/duplicate/errors/conflict.sieve4
-rw-r--r--pigeonhole/tests/extensions/duplicate/errors/syntax-vnd.sieve19
-rw-r--r--pigeonhole/tests/extensions/duplicate/errors/syntax.sieve54
-rw-r--r--pigeonhole/tests/extensions/duplicate/execute-vnd.svtest20
-rw-r--r--pigeonhole/tests/extensions/duplicate/execute.svtest41
-rw-r--r--pigeonhole/tests/extensions/editheader/addheader.svtest833
-rw-r--r--pigeonhole/tests/extensions/editheader/alternating.svtest181
-rw-r--r--pigeonhole/tests/extensions/editheader/deleteheader.svtest1115
-rw-r--r--pigeonhole/tests/extensions/editheader/errors.svtest164
-rw-r--r--pigeonhole/tests/extensions/editheader/errors/command-syntax.sieve42
-rw-r--r--pigeonhole/tests/extensions/editheader/errors/field-name-runtime.sieve6
-rw-r--r--pigeonhole/tests/extensions/editheader/errors/field-name.sieve19
-rw-r--r--pigeonhole/tests/extensions/editheader/errors/field-value.sieve15
-rw-r--r--pigeonhole/tests/extensions/editheader/errors/runtime-error.sieve6
-rw-r--r--pigeonhole/tests/extensions/editheader/errors/size-limit-runtime.sieve46
-rw-r--r--pigeonhole/tests/extensions/editheader/errors/size-limit.sieve43
-rw-r--r--pigeonhole/tests/extensions/editheader/execute.svtest57
-rw-r--r--pigeonhole/tests/extensions/editheader/execute/multiscript-after.sieve4
-rw-r--r--pigeonhole/tests/extensions/editheader/execute/multiscript-before.sieve4
-rw-r--r--pigeonhole/tests/extensions/editheader/execute/multiscript-personal.sieve4
-rw-r--r--pigeonhole/tests/extensions/editheader/protected.svtest173
-rw-r--r--pigeonhole/tests/extensions/editheader/utf8.svtest97
-rw-r--r--pigeonhole/tests/extensions/encoded-character.svtest180
-rw-r--r--pigeonhole/tests/extensions/enotify/basic.svtest15
-rw-r--r--pigeonhole/tests/extensions/enotify/encodeurl.svtest359
-rw-r--r--pigeonhole/tests/extensions/enotify/errors.svtest45
-rw-r--r--pigeonhole/tests/extensions/enotify/errors/from-mailto.sieve7
-rw-r--r--pigeonhole/tests/extensions/enotify/errors/options.sieve18
-rw-r--r--pigeonhole/tests/extensions/enotify/errors/uri-mailto.sieve20
-rw-r--r--pigeonhole/tests/extensions/enotify/errors/uri.sieve5
-rw-r--r--pigeonhole/tests/extensions/enotify/execute.svtest99
-rw-r--r--pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex1.sieve26
-rw-r--r--pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex2.sieve22
-rw-r--r--pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex3.sieve31
-rw-r--r--pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex5.sieve11
-rw-r--r--pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex6.sieve5
-rw-r--r--pigeonhole/tests/extensions/enotify/execute/duplicates.sieve4
-rw-r--r--pigeonhole/tests/extensions/enotify/mailto.svtest541
-rw-r--r--pigeonhole/tests/extensions/enotify/notify_method_capability.svtest12
-rw-r--r--pigeonhole/tests/extensions/enotify/valid_notify_method.svtest31
-rw-r--r--pigeonhole/tests/extensions/envelope.svtest244
-rw-r--r--pigeonhole/tests/extensions/environment/basic.svtest33
-rw-r--r--pigeonhole/tests/extensions/environment/rfc.svtest28
-rw-r--r--pigeonhole/tests/extensions/ihave/errors.svtest19
-rw-r--r--pigeonhole/tests/extensions/ihave/errors/error.sieve3
-rw-r--r--pigeonhole/tests/extensions/ihave/execute.svtest23
-rw-r--r--pigeonhole/tests/extensions/ihave/execute/ihave.sieve7
-rw-r--r--pigeonhole/tests/extensions/ihave/restrictions.svtest14
-rw-r--r--pigeonhole/tests/extensions/imap4flags/basic.svtest332
-rw-r--r--pigeonhole/tests/extensions/imap4flags/execute.svtest68
-rw-r--r--pigeonhole/tests/extensions/imap4flags/execute/flags-side-effect.sieve18
-rw-r--r--pigeonhole/tests/extensions/imap4flags/flagstore.svtest146
-rw-r--r--pigeonhole/tests/extensions/imap4flags/flagstring.svtest82
-rw-r--r--pigeonhole/tests/extensions/imap4flags/hasflag.svtest91
-rw-r--r--pigeonhole/tests/extensions/imap4flags/multiscript.svtest55
-rw-r--r--pigeonhole/tests/extensions/imap4flags/multiscript/fileinto.sieve4
-rw-r--r--pigeonhole/tests/extensions/imap4flags/multiscript/group-spam.sieve14
-rw-r--r--pigeonhole/tests/extensions/imap4flags/multiscript/sent-store.sieve7
-rw-r--r--pigeonhole/tests/extensions/imap4flags/multiscript/setflag.sieve3
-rw-r--r--pigeonhole/tests/extensions/imap4flags/multiscript/spam.sieve8
-rw-r--r--pigeonhole/tests/extensions/include/errors.svtest149
-rw-r--r--pigeonhole/tests/extensions/include/errors/action-conflicts.sieve4
-rw-r--r--pigeonhole/tests/extensions/include/errors/circular-1.sieve5
-rw-r--r--pigeonhole/tests/extensions/include/errors/circular-2.sieve5
-rw-r--r--pigeonhole/tests/extensions/include/errors/circular-3.sieve5
-rw-r--r--pigeonhole/tests/extensions/include/errors/depth-limit.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/errors/generic.sieve7
-rw-r--r--pigeonhole/tests/extensions/include/errors/global-namespace.sieve13
-rw-r--r--pigeonhole/tests/extensions/include/errors/include-limit.sieve6
-rw-r--r--pigeonhole/tests/extensions/include/errors/scriptname.sieve25
-rw-r--r--pigeonhole/tests/extensions/include/errors/variables-inactive.sieve7
-rw-r--r--pigeonhole/tests/extensions/include/errors/variables.sieve23
-rw-r--r--pigeonhole/tests/extensions/include/execute.svtest68
-rw-r--r--pigeonhole/tests/extensions/include/execute/actions-fileinto.sieve5
-rw-r--r--pigeonhole/tests/extensions/include/execute/namespace.sieve26
-rw-r--r--pigeonhole/tests/extensions/include/execute/optional.sieve5
-rw-r--r--pigeonhole/tests/extensions/include/included-global/namespace.dict4
-rw-r--r--pigeonhole/tests/extensions/include/included-global/namespace.sieve4
-rw-r--r--pigeonhole/tests/extensions/include/included-global/rfc-ex1-spam_tests.sieve7
-rw-r--r--pigeonhole/tests/extensions/include/included/action-fileinto.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/action-reject.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/actions-fileinto1.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/actions-fileinto2.sieve4
-rw-r--r--pigeonhole/tests/extensions/include/included/actions-fileinto3.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/circular-one.sieve5
-rw-r--r--pigeonhole/tests/extensions/include/included/circular-three-2.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/circular-three-3.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/circular-three.sieve7
-rw-r--r--pigeonhole/tests/extensions/include/included/circular-two-2.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/circular-two.sieve7
-rw-r--r--pigeonhole/tests/extensions/include/included/depth-limit-1.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/depth-limit-2.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/depth-limit-3.sieve1
-rw-r--r--pigeonhole/tests/extensions/include/included/namespace.dict4
-rw-r--r--pigeonhole/tests/extensions/include/included/namespace.sieve4
-rw-r--r--pigeonhole/tests/extensions/include/included/once-1.sieve9
-rw-r--r--pigeonhole/tests/extensions/include/included/once-2.sieve12
-rw-r--r--pigeonhole/tests/extensions/include/included/once-3.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/once-4.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/optional-1.sieve9
-rw-r--r--pigeonhole/tests/extensions/include/included/optional-2.sieve9
-rw-r--r--pigeonhole/tests/extensions/include/included/rfc-ex1-always_allow.sieve8
-rw-r--r--pigeonhole/tests/extensions/include/included/rfc-ex1-mailing_lists.sieve10
-rw-r--r--pigeonhole/tests/extensions/include/included/rfc-ex1-spam_tests.sieve10
-rw-r--r--pigeonhole/tests/extensions/include/included/rfc-ex2-spam_filter_script.sieve8
-rw-r--r--pigeonhole/tests/extensions/include/included/twice-1.sieve7
-rw-r--r--pigeonhole/tests/extensions/include/included/twice-2.sieve8
-rw-r--r--pigeonhole/tests/extensions/include/included/variables-included1.sieve7
-rw-r--r--pigeonhole/tests/extensions/include/included/variables-included2.sieve6
-rw-r--r--pigeonhole/tests/extensions/include/included/variables-included3.sieve8
-rw-r--r--pigeonhole/tests/extensions/include/once.svtest24
-rw-r--r--pigeonhole/tests/extensions/include/optional.svtest40
-rw-r--r--pigeonhole/tests/extensions/include/rfc-ex1-default.sieve6
-rw-r--r--pigeonhole/tests/extensions/include/rfc-ex2-default.sieve21
-rw-r--r--pigeonhole/tests/extensions/include/rfc.svtest13
-rw-r--r--pigeonhole/tests/extensions/include/twice.svtest20
-rw-r--r--pigeonhole/tests/extensions/include/variables.svtest29
-rw-r--r--pigeonhole/tests/extensions/index/basic.svtest93
-rw-r--r--pigeonhole/tests/extensions/index/errors.svtest20
-rw-r--r--pigeonhole/tests/extensions/index/errors/syntax.sieve26
-rw-r--r--pigeonhole/tests/extensions/mailbox/errors.svtest40
-rw-r--r--pigeonhole/tests/extensions/mailbox/errors/mailboxexists-bad-utf8.sieve9
-rw-r--r--pigeonhole/tests/extensions/mailbox/errors/syntax.sieve41
-rw-r--r--pigeonhole/tests/extensions/mailbox/execute.svtest80
-rw-r--r--pigeonhole/tests/extensions/metadata/errors.svtest56
-rw-r--r--pigeonhole/tests/extensions/metadata/errors/metadata-bad-utf8.sieve9
-rw-r--r--pigeonhole/tests/extensions/metadata/errors/metadataexists-bad-utf8.sieve9
-rw-r--r--pigeonhole/tests/extensions/metadata/errors/syntax.sieve53
-rw-r--r--pigeonhole/tests/extensions/metadata/execute.svtest145
-rw-r--r--pigeonhole/tests/extensions/mime/address.svtest281
-rw-r--r--pigeonhole/tests/extensions/mime/calendar-example.svtest129
-rw-r--r--pigeonhole/tests/extensions/mime/content-header.svtest161
-rw-r--r--pigeonhole/tests/extensions/mime/errors.svtest162
-rw-r--r--pigeonhole/tests/extensions/mime/errors/address-mime-tag.sieve38
-rw-r--r--pigeonhole/tests/extensions/mime/errors/break.sieve157
-rw-r--r--pigeonhole/tests/extensions/mime/errors/exists-mime-tag.sieve43
-rw-r--r--pigeonhole/tests/extensions/mime/errors/extracttext-nofep.sieve4
-rw-r--r--pigeonhole/tests/extensions/mime/errors/extracttext-novar.sieve6
-rw-r--r--pigeonhole/tests/extensions/mime/errors/extracttext.sieve42
-rw-r--r--pigeonhole/tests/extensions/mime/errors/foreverypart.sieve45
-rw-r--r--pigeonhole/tests/extensions/mime/errors/header-mime-tag.sieve100
-rw-r--r--pigeonhole/tests/extensions/mime/errors/limits-include.sieve6
-rw-r--r--pigeonhole/tests/extensions/mime/errors/limits.sieve13
-rw-r--r--pigeonhole/tests/extensions/mime/execute.svtest82
-rw-r--r--pigeonhole/tests/extensions/mime/execute/foreverypart.sieve14
-rw-r--r--pigeonhole/tests/extensions/mime/execute/mime.sieve69
-rw-r--r--pigeonhole/tests/extensions/mime/exists.svtest237
-rw-r--r--pigeonhole/tests/extensions/mime/extracttext.svtest143
-rw-r--r--pigeonhole/tests/extensions/mime/foreverypart.svtest178
-rw-r--r--pigeonhole/tests/extensions/mime/header.svtest444
-rw-r--r--pigeonhole/tests/extensions/mime/included/include-foreverypart.sieve44
-rw-r--r--pigeonhole/tests/extensions/mime/included/include-loop-2.sieve6
-rw-r--r--pigeonhole/tests/extensions/mime/included/include-loop-3.sieve6
-rw-r--r--pigeonhole/tests/extensions/mime/included/include-loop-4.sieve6
-rw-r--r--pigeonhole/tests/extensions/mime/included/include-loop-5.sieve9
-rw-r--r--pigeonhole/tests/extensions/regex/basic.svtest51
-rw-r--r--pigeonhole/tests/extensions/regex/errors.svtest29
-rw-r--r--pigeonhole/tests/extensions/regex/errors/compile.sieve25
-rw-r--r--pigeonhole/tests/extensions/regex/errors/runtime.sieve9
-rw-r--r--pigeonhole/tests/extensions/regex/match-values.svtest72
-rw-r--r--pigeonhole/tests/extensions/reject/execute.svtest34
-rw-r--r--pigeonhole/tests/extensions/reject/execute/basic.sieve8
-rw-r--r--pigeonhole/tests/extensions/reject/smtp.svtest56
-rw-r--r--pigeonhole/tests/extensions/relational/basic.svtest178
-rw-r--r--pigeonhole/tests/extensions/relational/comparators.svtest258
-rw-r--r--pigeonhole/tests/extensions/relational/errors.svtest33
-rw-r--r--pigeonhole/tests/extensions/relational/errors/syntax.sieve8
-rw-r--r--pigeonhole/tests/extensions/relational/errors/validation.sieve11
-rw-r--r--pigeonhole/tests/extensions/relational/rfc.svtest71
-rw-r--r--pigeonhole/tests/extensions/spamvirustest/errors.svtest15
-rw-r--r--pigeonhole/tests/extensions/spamvirustest/errors/syntax-errors.sieve19
-rw-r--r--pigeonhole/tests/extensions/spamvirustest/spamtest.svtest276
-rw-r--r--pigeonhole/tests/extensions/spamvirustest/spamtestplus.svtest136
-rw-r--r--pigeonhole/tests/extensions/spamvirustest/virustest.svtest143
-rw-r--r--pigeonhole/tests/extensions/special-use/errors.svtest38
-rw-r--r--pigeonhole/tests/extensions/special-use/errors/specialuse_exists-bad-utf8.sieve9
-rw-r--r--pigeonhole/tests/extensions/special-use/errors/syntax.sieve38
-rw-r--r--pigeonhole/tests/extensions/special-use/execute.svtest54
-rw-r--r--pigeonhole/tests/extensions/subaddress/basic.svtest111
-rw-r--r--pigeonhole/tests/extensions/subaddress/config.svtest85
-rw-r--r--pigeonhole/tests/extensions/subaddress/rfc.svtest59
-rw-r--r--pigeonhole/tests/extensions/vacation/errors.svtest19
-rw-r--r--pigeonhole/tests/extensions/vacation/errors/conflict-reject.sieve5
-rw-r--r--pigeonhole/tests/extensions/vacation/execute.svtest73
-rw-r--r--pigeonhole/tests/extensions/vacation/execute/action.sieve4
-rw-r--r--pigeonhole/tests/extensions/vacation/execute/no-handle.sieve10
-rw-r--r--pigeonhole/tests/extensions/vacation/execute/seconds.sieve4
-rw-r--r--pigeonhole/tests/extensions/vacation/message.svtest752
-rw-r--r--pigeonhole/tests/extensions/vacation/references.sieve4
-rw-r--r--pigeonhole/tests/extensions/vacation/reply.svtest536
-rw-r--r--pigeonhole/tests/extensions/vacation/smtp.svtest199
-rw-r--r--pigeonhole/tests/extensions/vacation/utf-8.svtest168
-rw-r--r--pigeonhole/tests/extensions/variables/basic.svtest223
-rw-r--r--pigeonhole/tests/extensions/variables/errors.svtest34
-rw-r--r--pigeonhole/tests/extensions/variables/errors/limits.sieve287
-rw-r--r--pigeonhole/tests/extensions/variables/errors/namespace.sieve8
-rw-r--r--pigeonhole/tests/extensions/variables/errors/set.sieve19
-rw-r--r--pigeonhole/tests/extensions/variables/limits.svtest435
-rw-r--r--pigeonhole/tests/extensions/variables/match.svtest365
-rw-r--r--pigeonhole/tests/extensions/variables/modifiers.svtest160
-rw-r--r--pigeonhole/tests/extensions/variables/quoting.svtest36
-rw-r--r--pigeonhole/tests/extensions/variables/regex.svtest35
-rw-r--r--pigeonhole/tests/extensions/variables/string.svtest37
-rw-r--r--pigeonhole/tests/extensions/vnd.dovecot/debug/execute.svtest6
-rw-r--r--pigeonhole/tests/extensions/vnd.dovecot/environment/basic.svtest29
-rw-r--r--pigeonhole/tests/extensions/vnd.dovecot/environment/variables.svtest18
-rw-r--r--pigeonhole/tests/extensions/vnd.dovecot/report/errors.svtest13
-rw-r--r--pigeonhole/tests/extensions/vnd.dovecot/report/errors/syntax.sieve28
-rw-r--r--pigeonhole/tests/extensions/vnd.dovecot/report/execute.svtest269
-rw-r--r--pigeonhole/tests/failures/fuzz1.svtest33
-rw-r--r--pigeonhole/tests/failures/fuzz2.svtest37
-rw-r--r--pigeonhole/tests/failures/fuzz3.svtest12
-rw-r--r--pigeonhole/tests/failures/mailbox-bad-utf8.svtest6
-rw-r--r--pigeonhole/tests/lexer.svtest39
-rw-r--r--pigeonhole/tests/match-types/contains.svtest81
-rw-r--r--pigeonhole/tests/match-types/is.svtest22
-rw-r--r--pigeonhole/tests/match-types/matches.svtest241
-rw-r--r--pigeonhole/tests/multiscript/basic.svtest91
-rw-r--r--pigeonhole/tests/multiscript/conflicts.svtest100
-rw-r--r--pigeonhole/tests/multiscript/fileinto-frop.sieve3
-rw-r--r--pigeonhole/tests/multiscript/fileinto-inbox.sieve4
-rw-r--r--pigeonhole/tests/multiscript/keep.sieve1
-rw-r--r--pigeonhole/tests/multiscript/notify.sieve3
-rw-r--r--pigeonhole/tests/multiscript/reject-1.sieve3
-rw-r--r--pigeonhole/tests/multiscript/reject-2.sieve3
-rw-r--r--pigeonhole/tests/multiscript/vacation.sieve3
-rwxr-xr-xpigeonhole/tests/plugins/extprograms/bin/addheader6
-rwxr-xr-xpigeonhole/tests/plugins/extprograms/bin/big8
-rwxr-xr-xpigeonhole/tests/plugins/extprograms/bin/cat3
-rwxr-xr-xpigeonhole/tests/plugins/extprograms/bin/cat-stdin3
-rwxr-xr-xpigeonhole/tests/plugins/extprograms/bin/crlf3
-rwxr-xr-xpigeonhole/tests/plugins/extprograms/bin/env3
-rwxr-xr-xpigeonhole/tests/plugins/extprograms/bin/frame7
-rwxr-xr-xpigeonhole/tests/plugins/extprograms/bin/modify8
-rwxr-xr-xpigeonhole/tests/plugins/extprograms/bin/program5
-rwxr-xr-xpigeonhole/tests/plugins/extprograms/bin/replace12
-rwxr-xr-xpigeonhole/tests/plugins/extprograms/bin/sleep103
-rwxr-xr-xpigeonhole/tests/plugins/extprograms/bin/sleep23
-rwxr-xr-xpigeonhole/tests/plugins/extprograms/bin/spamc6
-rwxr-xr-xpigeonhole/tests/plugins/extprograms/bin/stderr20
-rw-r--r--pigeonhole/tests/plugins/extprograms/errors.svtest32
-rw-r--r--pigeonhole/tests/plugins/extprograms/errors/arguments.sieve5
-rw-r--r--pigeonhole/tests/plugins/extprograms/errors/programname.sieve25
-rw-r--r--pigeonhole/tests/plugins/extprograms/execute/command.svtest27
-rw-r--r--pigeonhole/tests/plugins/extprograms/execute/errors.svtest53
-rw-r--r--pigeonhole/tests/plugins/extprograms/execute/errors/syntax.sieve38
-rw-r--r--pigeonhole/tests/plugins/extprograms/execute/errors/unknown-program.sieve3
-rw-r--r--pigeonhole/tests/plugins/extprograms/execute/errors/variables.sieve7
-rw-r--r--pigeonhole/tests/plugins/extprograms/execute/execute.svtest177
-rw-r--r--pigeonhole/tests/plugins/extprograms/filter/command.svtest10
-rw-r--r--pigeonhole/tests/plugins/extprograms/filter/errors.svtest39
-rw-r--r--pigeonhole/tests/plugins/extprograms/filter/errors/syntax.sieve22
-rw-r--r--pigeonhole/tests/plugins/extprograms/filter/errors/unknown-program.sieve3
-rw-r--r--pigeonhole/tests/plugins/extprograms/filter/execute.svtest213
-rw-r--r--pigeonhole/tests/plugins/extprograms/pipe/command.svtest10
-rw-r--r--pigeonhole/tests/plugins/extprograms/pipe/errors.svtest94
-rw-r--r--pigeonhole/tests/plugins/extprograms/pipe/errors/syntax.sieve22
-rw-r--r--pigeonhole/tests/plugins/extprograms/pipe/errors/timeout.sieve3
-rw-r--r--pigeonhole/tests/plugins/extprograms/pipe/errors/unknown-program.sieve3
-rw-r--r--pigeonhole/tests/plugins/extprograms/pipe/execute.svtest56
-rw-r--r--pigeonhole/tests/test-address.svtest434
-rw-r--r--pigeonhole/tests/test-allof.svtest446
-rw-r--r--pigeonhole/tests/test-anyof.svtest445
-rw-r--r--pigeonhole/tests/test-exists.svtest93
-rw-r--r--pigeonhole/tests/test-header.svtest280
-rw-r--r--pigeonhole/tests/test-size.svtest74
-rw-r--r--pigeonhole/tests/testsuite.svtest75
-rw-r--r--pigeonhole/update-version.sh64
942 files changed, 266274 insertions, 0 deletions
diff --git a/pigeonhole/AUTHORS b/pigeonhole/AUTHORS
new file mode 100644
index 0000000..88a2e4b
--- /dev/null
+++ b/pigeonhole/AUTHORS
@@ -0,0 +1,8 @@
+Stephan Bosch <stephan@rename-it.nl>
+
+This package is built for and partly based on the Dovecot Secure IMAP server
+written by:
+
+Timo Sirainen <tss@iki.fi>.
+
+Grepping 'patch by' from ChangeLog shows up more people.
diff --git a/pigeonhole/COPYING b/pigeonhole/COPYING
new file mode 100644
index 0000000..98aa091
--- /dev/null
+++ b/pigeonhole/COPYING
@@ -0,0 +1,4 @@
+See AUTHORS file for list of copyright holders.
+
+Everything is licenced under LGPLv2.1 (see COPYING.LGPL) unless otherwise
+mentioned at the beginning of the file.
diff --git a/pigeonhole/COPYING.LGPL b/pigeonhole/COPYING.LGPL
new file mode 100644
index 0000000..4362b49
--- /dev/null
+++ b/pigeonhole/COPYING.LGPL
@@ -0,0 +1,502 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/pigeonhole/ChangeLog b/pigeonhole/ChangeLog
new file mode 100644
index 0000000..5768a2d
--- /dev/null
+++ b/pigeonhole/ChangeLog
@@ -0,0 +1,38862 @@
+2023-08-30 15:48:42 +0300 Aki Tuomi <aki.tuomi@open-xchange.com> (f6cd4b8e)
+
+ configure: Set version to 0.5.21
+
+
+M configure.ac
+
+2023-08-30 15:46:29 +0300 Aki Tuomi <aki.tuomi@open-xchange.com> (bf473e5c)
+
+ NEWS: Add news for 0.5.21
+
+
+M NEWS
+
+2022-11-23 09:58:17 +0200 Aki Tuomi <aki.tuomi@open-xchange.com> (4d6323e5)
+
+ NEWS: Add news for 2.3.20
+
+
+M NEWS
+
+2022-05-04 15:04:01 +0300 Aki Tuomi <aki.tuomi@open-xchange.com> (65e5508b)
+
+ NEWS: Update date for 2.3.19 news
+
+
+M NEWS
+
+2022-04-26 09:45:26 +0300 Aki Tuomi <aki.tuomi@open-xchange.com> (6c340655)
+
+ NEWS: Add news for 0.5.19
+
+
+M NEWS
+
+2023-05-09 07:29:46 +0000 Marco Bettini <marco.bettini@open-xchange.com> (bea54d46)
+
+ lib-sieve: act_redirect_execute() - Pick Message-id even if invalid
+
+ This avoids adding another Message-id if one is already present but of bad
+ quality.
+
+M src/lib-sieve/cmd-redirect.c
+
+2023-06-20 01:13:08 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (8c3df357)
+
+ lib-sieve: util: edit-mail - Fix assert occurring when bad header is
+ encountered.
+
+ In that case, the header name and middle are empty, causing:
+
+ Panic: file edit-mail.c: line 820 (edit_mail_headers_parse): assertion
+ failed: (body_offset > 0)
+
+ Fixed by skipping the bad header for parsing altogether.
+
+M src/lib-sieve/util/edit-mail.c
+
+2023-03-30 01:58:09 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (ad58bdd4)
+
+ managesieve: Disable debug logging while dumping capability
+
+ It only causes confusing output.
+
+M src/managesieve/main.c
+
+2022-01-12 12:54:05 +0200 Aki Tuomi <aki.tuomi@open-xchange.com> (cf9d3352)
+
+ NEWS: Add news for 0.5.18
+
+
+M NEWS
+
+2022-02-05 17:14:16 +0200 Martti Rannanjärvi <martti.rannanjarvi@open-xchange.com> (7927a415)
+
+ managesieve-login: managesieve_proxy_parse_auth_reply() - Free input istream
+
+
+M src/managesieve-login/managesieve-proxy.c
+
+2022-01-21 12:31:43 +0200 Martti Rannanjärvi <martti.rannanjarvi@open-xchange.com> (ede85010)
+
+ configure.ac: Set pigeonhole version to 0.5.100
+
+ This is to match the version 2.3.100 used in core.
+
+M configure.ac
+
+2022-01-19 19:48:48 +0200 Aki Tuomi <aki.tuomi@open-xchange.com> (aba35b74)
+
+ configure.ac: Fix version to 2.3 dovecot
+
+
+M configure.ac
+
+2022-01-19 17:14:03 +0100 Timo Sirainen <timo.sirainen@open-xchange.com> (ca2cb5fb)
+
+ configure: Update version to 0.5.devel
+
+
+M configure.ac
+
+2021-11-30 12:50:17 +0200 Aki Tuomi <aki.tuomi@open-xchange.com> (c0951f32)
+
+ NEWS: Add news for 0.5.17.1
+
+
+M NEWS
+
+2021-09-28 12:57:33 +0300 Aki Tuomi <aki.tuomi@open-xchange.com> (8bf12bb7)
+
+ NEWS: Add news for 0.5.17
+
+
+M NEWS
+
+2021-12-03 09:05:16 +0200 Aki Tuomi <aki.tuomi@open-xchange.com> (df7907ae)
+
+ lib-sieve-tool: Sieve tools do not need SSL settings
+
+ Fixes argument list too long error.
+
+M src/lib-sieve-tool/sieve-tool.c
+
+2019-10-06 19:36:32 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (e8af1162)
+
+ lib-sieve: sieve-stringlist - Assert that index for the index stringlist is
+ not 0.
+
+
+M src/lib-sieve/sieve-stringlist.c
+
+2019-10-06 20:42:54 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (8c6a3928)
+
+ lib-sieve: index extension: Do not accept :index tag with zero value.
+
+
+M src/lib-sieve/plugins/index/tag-index.c
+M tests/extensions/index/errors.svtest
+M tests/extensions/index/errors/syntax.sieve
+
+2019-10-06 20:59:43 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (a46bb1a9)
+
+ lib-sieve: plugins: index: Reformat tag-index.c.
+
+
+M src/lib-sieve/plugins/index/tag-index.c
+
+2021-10-22 21:54:43 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (3e2a8df4)
+
+ managesieve-login: Pass forward_ passdb args using XCLIENT command.
+
+
+M src/managesieve-login/managesieve-proxy.c
+
+2021-10-22 21:51:08 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (a869b1a8)
+
+ managesieve-login: Add FORWARD for XCLIENT.
+
+ This allows passing passdb variables. They are prefixed with forward_ when
+ imported to extra fields.
+
+M src/managesieve-login/client.c
+
+2021-11-03 23:49:09 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (a1b4cea5)
+
+ managesieve-login: managesieve-proxy - Fix pipelining beyond AUTHENTICATE.
+
+ Upon login success, the next line was erroneously skipped.
+
+M src/managesieve-login/managesieve-proxy.c
+
+2021-06-22 17:06:58 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (b5e69c08)
+
+ managesieve-login: Reformat managesieve-proxy.c.
+
+
+M src/managesieve-login/managesieve-proxy.c
+
+2021-06-22 16:21:20 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (a38436fc)
+
+ managesieve-login: Reformat client.h.
+
+
+M src/managesieve-login/client.h
+
+2021-06-22 16:18:49 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (d92ad7b1)
+
+ managesieve-login: Reformat client.c.
+
+
+M src/managesieve-login/client.c
+
+2021-11-04 10:46:57 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (cbc1c489)
+
+ lib-sieve: util: edit-mail - Fix returning buffer-full condition when data
+ was read.
+
+ Fixes:
+
+ Panic: file istream-crlf.c: line 24 (i_stream_crlf_read_common): assertion
+ failed: (ret != -2) Panic: file istream.h: line 228 (i_stream_read_more):
+ assertion failed: (ret != -2)
+ (various other similar panics are possible)
+
+M src/lib-sieve/util/edit-mail.c
+M src/lib-sieve/util/test-edit-mail.c
+
+2020-08-26 00:38:15 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (b7b4d24d)
+
+ lib-sieve: util: Reformat test-edit-mail.c.
+
+
+M src/lib-sieve/util/test-edit-mail.c
+
+2020-08-26 00:00:04 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (ecc70828)
+
+ lib-sieve: util: Reformat edit-mail.h.
+
+
+M src/lib-sieve/util/edit-mail.h
+
+2020-08-25 23:55:28 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (a4a22309)
+
+ lib-sieve: util: Reformat edit-mail.c.
+
+
+M src/lib-sieve/util/edit-mail.c
+
+2021-11-02 09:54:08 -0400 Timo Sirainen <timo.sirainen@open-xchange.com> (29750ba5)
+
+ managesieve: Use MASTER_SERVICE_FLAG_DISABLE_SSL_SET when dumping capability
+
+ This prevents startup failures if ssl_ca has a large number of certificates.
+
+M src/managesieve/main.c
+
+2021-10-28 00:40:58 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (0b5e7b1a)
+
+ lib-sieve: sieve-result - Fix panic occurring upon temp fail after committed
+ keep-equivalent action.
+
+ The determination of whether a keep-equivalent action was already executed
+ is performed in sieve_result_implicit_keep_execute(), which can also be
+ called from sieve_result_implicit_keep_finalize(). But there, the
+ keep-equivalent status was checked before any call to
+ sieve_result_implicit_keep_execute(), which would thus yield the wrong
+ result.
+
+ This change also makes the associated debug message more specific (otherwise
+ two identical debug messages are logged) and an assert is added that makes
+ sure the keep-equivalent action is actually finalized when the implicit keep
+ was supposed to be finalized.
+
+ Panic was:
+
+ Panic: file sieve-result.c: line 1706 (sieve_result_implicit_keep_finalize):
+ assertion failed: (aexec_keep->state ==
+ SIEVE_ACTION_EXECUTION_STATE_EXECUTED)
+
+M src/lib-sieve/sieve-result.c
+
+2021-10-28 00:45:15 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (d1c44652)
+
+ lib-sieve: sieve-result - Move finalize debug message for implicit keep.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-09-20 22:09:48 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (27ab897f)
+
+ plugins: imapsieve: imap-sieve-storage - Make sure mail_set_uid() is never
+ called with uid=0.
+
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2021-08-04 13:06:23 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (c6d3cabf)
+
+ NEWS: Add news for 0.5.16
+
+
+M NEWS
+
+2021-06-11 11:58:05 +0300 Aki Tuomi <aki.tuomi@open-xchange.com> (216e41c2)
+
+ NEWS: Update release date
+
+
+M NEWS
+
+2021-04-22 15:20:32 +0300 Aki Tuomi <aki.tuomi@open-xchange.com> (ab56f331)
+
+ NEWS: Add news for 0.5.15
+
+
+M NEWS
+
+2021-09-17 11:40:41 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (837bd100)
+
+ lib-sieve: plugins: duplicate: ext-duplicate-common - Add debug messages for
+ action finish stage.
+
+
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+
+2021-06-08 03:50:53 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (5e66dfca)
+
+ lib-sieve: Adjust to changes in mail-duplicate API.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.h
+M src/lib-sieve/plugins/duplicate/tst-duplicate.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-execute.c
+M src/lib-sieve/sieve-execute.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-script.c
+
+2021-09-19 13:18:24 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (0f2c9569)
+
+ lib-sieve: Adjust to changes in Dovecot file-lock API.
+
+
+M src/lib-sieve/sieve-binary-file.c
+
+2021-09-16 20:04:06 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (86170b0f)
+
+ m4: dovecot.m4 - Sync with core
+
+
+M m4/dovecot.m4
+
+2021-07-21 00:07:21 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (79e51ecf)
+
+ lib-sieve: Disable CPU time limit by default when Sieve is executed in mail
+ storage.
+
+
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve.c
+
+2021-08-18 13:27:50 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (4596d399)
+
+ lib-sieve: sieve-result - Indicate in sieve_result_transaction_finalize()
+ debug message whether actions were committed.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-08-18 13:26:26 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (65d771c1)
+
+ lib-sieve: sieve-result - Indicate in sieve_result_transaction_execute()
+ debug message whether actions were executed.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-08-18 02:43:05 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (dbf5b62b)
+
+ lib-sieve: sieve-result - Add debug messages for temp failure handling.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-08-18 13:29:41 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (81bd53d6)
+
+ lib-sieve: sieve-result - Assert that implicit keep is executed in
+ sieve_result_implicit_keep_finalize().
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-08-18 02:54:25 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (293f0027)
+
+ lib-sieve: sieve-result - Fix resource leak occurring when implicit keep is
+ executed before temporary failure at commit.
+
+ In the commit phase the implicit keep was never finalized, meaning that it
+ was not rolled back and thus not cleaned up properly. This leads to a memory
+ leak and a mailbox reference leak. This in turn causes an assert crash at
+ the end of delivery when the mail user is destroyed.
+
+M src/lib-sieve/sieve-result.c
+
+2021-08-18 02:56:32 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (f2b81cc6)
+
+ lib-sieve: sieve-result - Fix handling of resource limit status after
+ implicit keep commit.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-08-18 02:46:18 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (92b4b06d)
+
+ lib-sieve: sieve-result - Skip implicit keep in execution stage upon temp
+ failure.
+
+ It will be executed in the commit phase if necessary; don't do it early; it
+ will only be rolled back.
+
+M src/lib-sieve/sieve-result.c
+
+2021-08-18 02:26:32 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (c84e6e5d)
+
+ lib-sieve: sieve-result - Move temp failure status checks into
+ sieve_result_implicit_keep_finalize().
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-08-18 02:07:01 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (10e347e3)
+
+ lib-sieve: sieve-result - Move temp failure status checks into
+ sieve_result_implicit_keep_execute().
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-08-18 01:40:57 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (291f2fdb)
+
+ lib-sieve: sieve-result - Remove success parameter from
+ sieve_result_implicit_keep_finalize().
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-08-18 01:44:23 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (54e020c1)
+
+ lib-sieve: sieve-result - Remove success parameter from
+ sieve_result_implicit_keep_execute().
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-08-17 19:09:13 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (9f300239)
+
+ lib-sieve: sieve-interpreter - Fix field mixup in debug message.
+
+
+M src/lib-sieve/sieve-interpreter.c
+
+2021-08-19 02:46:22 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (4c0acd83)
+
+ lib-sieve: sieve-binary-debug - Properly handle line decrements.
+
+
+M src/lib-sieve/sieve-binary-debug.c
+
+2021-08-19 02:20:37 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (2cb70c69)
+
+ lib-sieve: plugins: include: ext-include-common - Use ENUM_NEGATE() macro
+ where necessary.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2021-08-19 01:30:17 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (9222ce45)
+
+ lib-sieve: sieve-ast - Use sieve_number_t for number values.
+
+
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+
+2021-08-19 01:29:48 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (efdb74cf)
+
+ lib-sieve: sieve-lexer - Use sieve_number_t for number values.
+
+
+M src/lib-sieve/sieve-lexer.h
+
+2021-08-19 01:26:25 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (ee9f9be3)
+
+ lib-sieve: Add SIEVE_PRI_NUMBER definition.
+
+
+M src/lib-sieve/sieve-common.h
+
+2020-10-12 21:21:12 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (37dfe0d8)
+
+ lib-sieve: plugins: include: Reformat ext-include-common.c.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2020-03-09 23:55:33 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (031967f5)
+
+ lib-sieve: Reformat sieve-ast.h.
+
+
+M src/lib-sieve/sieve-ast.h
+
+2020-03-09 23:48:48 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (06213060)
+
+ lib-sieve: Reformat sieve-ast.c.
+
+
+M src/lib-sieve/sieve-ast.c
+
+2021-08-12 22:26:41 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (d6e0a9e3)
+
+ lib-sieve: cmd-redirect - Avoid cancelling implicit keep upon mail loop
+ detection.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2021-08-13 00:36:58 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (87df7e30)
+
+ lib-sieve: cmd-redirect - Move dupeid to action exection transaction struct.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2021-08-13 00:26:20 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (b25a511f)
+
+ lib-sieve: cmd-redirect - Move msg_id to action exection transaction struct.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2021-08-13 00:08:25 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (19335d87)
+
+ lib-sieve: Remove spurious whitespace in cmd-redirect.c.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2021-08-10 17:31:30 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (9e4160d6)
+
+ lib-sieve: sieve-result - Fix omission of action finalization happening upon
+ result execution failure.
+
+ This occurred because the code that checks for a deferred keep action in
+ sieve_result_implicit_keep_execute() could end up "finding" an action that
+ wasn't actually a deferred keep. That action was then erroneously promoted
+ to the FINALIZED state, which meant that commit/rollback was never executed.
+
+M src/lib-sieve/sieve-result.c
+
+2021-06-30 01:36:33 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (3f66b725)
+
+ lib-sieve: plugins: enotify: mailto: uri-mailto - Change _is_qchar() to
+ accept char parameter.
+
+ It is used like that everywhere and ubsan complains about passing char to
+ unsigned char parameter.
+
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+
+2020-03-26 17:21:07 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (a679bce4)
+
+ lib-sieve: plugins: enotify: mailto: Reformat uri-mailto.c.
+
+
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+
+2021-05-10 16:23:45 +0100 Siavash Tavakoli <siavash.tavakoli@open-xchange.com> (0aa68128)
+
+ sieve-dict: Adjust to core dict API changes
+
+
+M src/lib-sieve/storage/dict/sieve-dict-script.c
+M src/lib-sieve/storage/dict/sieve-dict-storage.c
+
+2021-06-02 23:19:46 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (7090e625)
+
+ lib-sieve: sieve-result - Never allow side-effect definition to be NULL.
+
+ This had no real purpose and could cause NULL pointer dereference.
+
+ Found by Clang scan-build.
+
+M src/lib-sieve/sieve-result.c
+
+2021-06-02 22:57:19 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (0dcf81e3)
+
+ lib-sieve: sieve-binary-file - Fix potential NULL pointer dereference in
+ sieve_binary_file_update_resource_usage().
+
+ Found by Clang scan-build.
+
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+
+2021-06-03 20:23:11 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (25c6a0a1)
+
+ lib-managesieve: managesieve-parser - Parse literal size using as same
+ algorithm as str_parse*().
+
+ This prevents wrapping the integer value and fixes an ubsan complaint.
+
+M src/lib-managesieve/managesieve-parser.c
+
+2021-06-03 19:52:58 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (d40dd502)
+
+ lib-managesieve: managesieve-parser - Fix 8 bit atom check to use unsigned
+ char.
+
+
+M src/lib-managesieve/managesieve-parser.c
+
+2021-06-03 19:46:14 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (691d8493)
+
+ lib-managesieve: Reformat managesieve-parser.h.
+
+
+M src/lib-managesieve/managesieve-parser.h
+
+2021-06-03 19:45:53 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (d4ef956d)
+
+ lib-managesieve: Reformat managesieve-parser.c.
+
+
+M src/lib-managesieve/managesieve-parser.c
+
+2020-03-09 11:13:52 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (7de596ba)
+
+ testsuite: Debug logging was unnecessarily growing data stack size
+
+
+M src/testsuite/testsuite-log.c
+
+2021-05-27 01:14:02 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (cc1d13f9)
+
+ lib-sieve: plugins: enotify: vmodf-encodeurl - Remove erroneous type cast.
+
+ Fixes ubsan runtime error.
+
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+
+2021-05-27 01:13:11 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (a98d9f59)
+
+ global: Fix negation with constants to match target type
+
+
+M src/lib-sieve/sieve-binary-file.c
+
+2021-05-27 01:10:22 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (b6955345)
+
+ global: Use ENUM_NEGATE() macro where necessary
+
+
+M src/lib-sieve/sieve-binary-file.c
+
+2021-04-22 23:06:48 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (37e62d89)
+
+ lib-sieve: sieve-result - Add debug messages for implicit keep execution.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-07 00:57:08 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (c3fdcb67)
+
+ lib-sieve: sieve-result - Add debug messages for result execution.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-07 01:18:26 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (eecaa6b5)
+
+ lib-sieve: sieve-action - Add debug messages for store action.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2021-04-07 01:12:45 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (5e8c385f)
+
+ lib-sieve: sieve - Add debug messages for multiscript execution.
+
+
+M src/lib-sieve/sieve.c
+
+2021-05-10 22:19:06 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (f577a53d)
+
+ lib-sieve: sieve-interpreter - Add status to debug message emitted when
+ script is finished.
+
+
+M src/lib-sieve/sieve-interpreter.c
+
+2021-05-10 21:56:31 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (12cf5cca)
+
+ lib-sieve: sieve - Add sieve_execution_exitcode_to_str().
+
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+
+2021-05-10 21:30:14 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (2d3c446f)
+
+ lib-sieve: sieve-result - Provide proper execution context for action side
+ effects.
+
+ This is currently not used, but prevents mishaps once such code is written.
+
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/special-use/tag-specialuse.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+
+2021-05-08 03:37:51 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (cd092803)
+
+ lib-sieve: sieve-result - Make execution struct available for action side
+ effects.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-05-10 20:40:00 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (224b393a)
+
+ lib-sieve: sieve-result - Always call the post_commit method of side-effects
+ if present.
+
+ This is not currently used, but the absence of the call could cause memory
+ leaks in the future.
+
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+
+2021-05-10 20:37:00 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (58486f18)
+
+ lib-sieve: sieve-result - Move side-effect execution activities to separate
+ functions.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-05-10 20:33:59 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (fb1e8fe0)
+
+ lib-sieve: sieve-result - Make calls to sieve_action_execution_pre/post()
+ more logical.
+
+ Call sieve_action_execution_pre() just before the first action activity and
+ always call sieve_action_execution_post() at the end of each action
+ activity. This makes things clearer and it makes the next commit easier.
+
+M src/lib-sieve/sieve-result.c
+
+2021-05-10 19:29:14 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (1583eea2)
+
+ lib-sieve: sieve-result - Remove code duplication between implicit keep and
+ normal action execution.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-26 03:31:30 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (e3135559)
+
+ lib-sieve: sieve-result - Move action execution state to a separate struct.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-05-10 12:07:58 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (ea20148c)
+
+ lib-sieve: sieve-result - Rename rac local variables to aexec.
+
+ Preparation for next commit.
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-11 00:23:48 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (49b0df02)
+
+ lib-sieve: sieve-actions - Remove parameter last from action finish method.
+
+
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+
+2021-04-23 10:59:35 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (b1720551)
+
+ lib-sieve: sieve-actions - Avoid logging about rolled-back successful
+ implicit keep.
+
+ This will now readily happen when executed (not committed) success implicit
+ keep is replaced by a failure implicit keep.
+
+M src/lib-sieve/sieve-actions.c
+
+2021-04-22 23:08:07 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (61a33b14)
+
+ lib-sieve: sieve-result - Commit actions only at the end of an execution
+ sequence.
+
+ Before, actions were executed and committed in full after each script in a
+ sequence. With this change, actions can still be rolled back until the end
+ of all Sieve script and action execution.
+
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2021-04-20 01:49:48 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (c11beda2)
+
+ lib-sieve: sieve-result - Add separate committed flag to struct
+ sieve_result_execution.
+
+ The committed flag is set when at least one action was committed
+ successfully. The existing executed flag is repurposed to signal successful
+ execution of at least one action. These flags are now also properly managed
+ for the keep action.
+
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2021-05-10 18:58:11 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (2c216d7c)
+
+ lib-sieve: sieve-result - Move local seen_delivery flag to struct
+ sieve_result_execution.
+
+ Allows doing the check in the action finalization function.
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-20 01:33:46 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (386f1636)
+
+ lib-sieve: sieve-result - Move executed_delivery flag to struct
+ sieve_result_execution.
+
+
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve.c
+
+2021-04-20 01:26:29 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (19e69f3b)
+
+ lib-sieve: sieve-result - Move executed flag to struct
+ sieve_result_execution.
+
+
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2021-04-16 01:06:28 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (0b19d378)
+
+ lib-sieve: sieve-result - Always iterate through all actions while
+ executing.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-20 02:00:29 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (21683788)
+
+ lib-sieve: sieve-result - Remove sieve_result_finish().
+
+ It is no longer used.
+
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2021-04-16 00:32:37 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (551293ad)
+
+ lib-sieve: sieve-result - Use proper state field for executed actions.
+
+
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+
+2021-04-11 22:42:49 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (c52ef960)
+
+ lib-sieve: sieve-result - Only perform implicit keep inside
+ sieve_result_execute().
+
+ Adds status parameter to sieve_result_execute().
+
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-result.c
+
+2021-04-11 11:51:33 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (3f01d89d)
+
+ lib-sieve: sieve-result - Avoid use of result->last_attempted_action in
+ sieve_result_print().
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-11 11:49:04 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (c4d89e43)
+
+ lib-sieve: sieve-result - Restructure sieve_result_print().
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-11 11:32:25 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (37047790)
+
+ lib-sieve: sieve-result - Use execution sequence counter to distinguish old
+ and new actions.
+
+
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2021-04-10 23:49:21 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (93ad05b4)
+
+ lib-sieve: sieve-result - Record per-action error handler.
+
+ Makes sure it is consistent for a later commit when action exection is more
+ fragmented.
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-10 23:39:50 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (32b8af52)
+
+ lib-sieve: sieve-result - Move execution status to struct
+ sieve_result_execution.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-10 23:14:18 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (891784ee)
+
+ lib-sieve: sieve-result - Record action execution status as full integer
+ status.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-10 22:14:38 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (508fa1f7)
+
+ lib-sieve: sieve-result - Move keep status to sieve_result_execution.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-10 21:15:00 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (df07ff62)
+
+ lib-sieve: sieve-result - Split _sieve_result_implicit_keep() into execute
+ and finalize phases.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-10 17:39:03 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (3abfdaf0)
+
+ lib-sieve: sieve-result - Move keep side effects to struct
+ sieve_result_execution.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-10 17:24:56 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (b5929739)
+
+ lib-sieve: sieve-result - Change rollback to success parameter in
+ _sieve_result_implicit_keep().
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-10 17:20:31 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (e43a4544)
+
+ lib-sieve: sieve-result - Always perform search for keep-equal actions
+ during implicit keep.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-10 15:31:04 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (55ef4edc)
+
+ lib-sieve: sieve-result - Move keep action context to struct
+ sieve_result_execution.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-10 15:22:09 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (4eb8298a)
+
+ lib-sieve: sieve-result - Move keep execute status to struct
+ sieve_result_execution.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-10 15:08:17 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (7b213ac4)
+
+ lib-sieve: sieve-result - Change action parameter of
+ sieve_action_execution_pre() to result action.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-10 14:58:51 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (001d4cab)
+
+ lib-sieve: sieve-result - Rename keep return argument for
+ sieve_result_execute() to keep_r.
+
+
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve.c
+M src/testsuite/testsuite-result.c
+
+2021-04-10 14:37:06 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (7ffdaf07)
+
+ lib-sieve: sieve-result - Move keep action to struct sieve_result_execution.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-05-10 01:24:09 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (e082eb15)
+
+ lib-sieve: sieve-result - Split off sieve_result_action_finish().
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-05-10 01:19:22 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (9a0ae786)
+
+ lib-sieve: sieve-result - Move sieve_result_action_commit_or_rollback().
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-05-10 01:17:55 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (d1bf5928)
+
+ lib-sieve: sieve-result - Move sieve_result_action_rollback().
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-05-10 01:16:40 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (ebea306b)
+
+ lib-sieve: sieve-result - Move sieve_result_action_commit().
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-10 13:55:20 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (aa524676)
+
+ lib-sieve: sieve-result - Split off sieve_result_action_execute().
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-05-10 00:14:18 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (10826af0)
+
+ lib-sieve: sieve-result - Split off sieve_result_action_start().
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-23 10:51:23 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (59809e2d)
+
+ lib-sieve: sieve-result - Consistently use sieve_action_execution_post() at
+ end of execution.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-10 13:19:27 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (228801cf)
+
+ lib-sieve: sieve-result - Rename sieve_result_finish_action_env() to
+ sieve_action_execution_post().
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-10 13:19:16 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (d523a01f)
+
+ lib-sieve: sieve-result - Rename sieve_result_prepare_action_env() to
+ sieve_action_execution_pre().
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-04-10 13:06:23 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (3081c100)
+
+ lib-sieve: sieve-result - Change execution API to use separate struct.
+
+
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve.c
+M src/testsuite/testsuite-result.c
+
+2021-04-09 02:12:53 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (e6af7659)
+
+ lib-sieve: sieve - Merge sieve_multiscript_tempfail() into
+ sieve_multiscript_finish().
+
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-script.c
+
+2021-04-23 10:40:21 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (c0384971)
+
+ lib-sieve: sieve - Make sieve_multiscript_finish/tempfail(NULL, ...) a
+ no-op.
+
+
+M src/lib-sieve/sieve.c
+
+2021-04-09 01:51:46 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (8bbcc9cd)
+
+ lib-sieve: sieve - Move multiscript API cleanup to separate function.
+
+
+M src/lib-sieve/sieve.c
+
+2021-05-21 02:57:04 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (14dc2bc1)
+
+ lib-sieve: sieve - Modify mscript->keep directly in
+ sieve_multiscript_execute/test().
+
+ Avoids unnecessary pointer parameter.
+
+M src/lib-sieve/sieve.c
+
+2021-05-21 01:44:57 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (85b3d400)
+
+ lib-sieve: sieve - Remove unused keep_r argument from execution functions.
+
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-script.c
+
+2021-04-08 23:52:35 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (84ad4043)
+
+ lib-sieve: sieve-result - Move result action keep field to public action
+ struct.
+
+
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+
+2021-04-11 12:09:15 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (9d5979b5)
+
+ lib-sieve: sieve-actions - Make sure mail error is handled properly in store
+ action.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2021-04-11 12:07:48 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (447cebed)
+
+ lib-sieve: sieve-actions - Restructure commit phase of store action.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2021-04-06 23:33:45 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (d8a8ebd0)
+
+ lib-sieve: sieve-actions - Move store transaction cleanup to separate
+ function.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2021-02-12 22:09:27 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (f015a391)
+
+ lib-sieve: sieve-actions - Move implicit keep handling to execute phase of
+ action execution.
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+
+2021-05-10 11:09:08 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (af0d634a)
+
+ lib-sieve: sieve-result - Rename first_/last_action to actions_head/_tail.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-03-29 00:10:04 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (6ca5e567)
+
+ plugins: sieve-extprograms: Reformat cmd-pipe.c.
+
+
+M src/plugins/sieve-extprograms/cmd-pipe.c
+
+2020-04-05 23:27:49 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (38380092)
+
+ lib-sieve: plugins: imap4flags: Reformat tag-flags.c.
+
+
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+
+2021-03-29 00:03:37 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (b73dc428)
+
+ lib-sieve: plugins: copy: Reformat ext-copy.c.
+
+
+M src/lib-sieve/plugins/copy/ext-copy.c
+
+2021-04-11 12:29:16 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (99f1c8a1)
+
+ lib-sieve: Reformat sieve-actions.c.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2020-08-25 22:22:10 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (a41f4337)
+
+ testsuite: testsuite-mailstore - Check mail index validity in
+ testsuite_mailstore_mail_index().
+
+ Providing an out-of-range index caused an assert panic.
+
+ Panic was:
+
+ Panic: file mail-index-transaction-update.c: line 19
+ (mail_index_transaction_lookup): assertion failed: (seq >= t->first_new_seq
+ && seq <= t->last_new_seq)
+
+M Makefile.am
+M src/testsuite/testsuite-mailstore.c
+A tests/failures/fuzz3.svtest
+
+2020-08-25 22:28:06 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (a5d77dca)
+
+ testsuite: testsuite-mailstore - Return struct testsuite_mailstore_mail from
+ testsuite_mailstore_open().
+
+ This is more flexible and needed in subsequent commit.
+
+M src/testsuite/testsuite-mailstore.c
+
+2021-04-20 02:07:23 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (c4322964)
+
+ lib-sieve: sieve-result - Prevent executing implicit keep upon resource
+ limit transgression.
+
+
+M src/lib-sieve/sieve-result.c
+
+2021-03-08 17:15:52 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (827cab0d)
+
+ managesieve: Fix crash when processing pipelined input after AUTHENTICATE
+
+ Attempting to pipeline any commands with the AUTHENTICATE command resulted
+ in crash.
+
+ Fixes: Panic: file istream.c: line 317 (i_stream_read_memarea): assertion
+ failed: (old_size <= _stream->pos - _stream->skip)
+
+M src/managesieve/main.c
+
+2021-03-08 17:12:08 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (bae10a75)
+
+ managesieve: Move finishing istream to client_create_finish()
+
+
+M src/managesieve/main.c
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+
+2021-02-24 19:08:33 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (953daba7)
+
+ plugins: sieve-extprograms: Adjust to program_client_run() API change
+
+
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+
+2021-02-13 00:00:49 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (151eec1e)
+
+ plugin tests: Do not use valgrind for child processes.
+
+ Those are currently exclusively system tools and we cannot control whether
+ those have memory leaks.
+
+M Makefile.am
+
+2021-02-13 00:00:28 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (3b375f86)
+
+ Update m4/dovecot.m4.
+
+
+M m4/dovecot.m4
+
+2020-04-08 09:39:20 -0400 Josef 'Jeff' Sipek <jeff.sipek@open-xchange.com> (8bc82b3b)
+
+ lib-sieve: Include year in log file header
+
+ Even on a well configured system, the log may accumulate the occasion error.
+ Because of the rare nature, it is impossible to know if the error from
+ yesterday is really a year old error that doesn't matter anymore.
+
+M src/lib-sieve/sieve-error.c
+
+2020-09-11 02:42:20 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (d07a8bae)
+
+ testsuite: testsuite-mailstore - Check validity of folder argument.
+
+ This is actually a secondary test. The command calling this should already
+ have checked this.
+
+M src/testsuite/testsuite-mailstore.c
+
+2020-09-11 02:41:34 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (6d4b1ea5)
+
+ testsuite: cmd-test-message - Properly check folder argument validity.
+
+
+M Makefile.am
+M src/testsuite/cmd-test-message.c
+A tests/failures/mailbox-bad-utf8.svtest
+
+2020-09-11 02:52:51 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (1a661ed1)
+
+ testsuite: testsuite-common - Make expected test failure more clear in the
+ output.
+
+
+M src/testsuite/testsuite-common.c
+
+2021-05-05 21:36:32 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (c70db20f)
+
+ global: Adjust to env_put() API change
+
+
+M src/lib-sieve/storage/ldap/sieve-ldap-storage-settings.c
+M src/managesieve-login/managesieve-login-settings-plugin.c
+
+2021-02-11 16:33:26 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (9c8c06f0)
+
+ global: Use array_foreach_elem() where possible
+
+
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/sieve-validator.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-delete.c
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2021-03-02 10:56:54 +0200 Aki Tuomi <aki.tuomi@open-xchange.com> (35dd5386)
+
+ NEWS: Update news for 0.5.14
+
+
+M NEWS
+
+2021-02-17 13:30:46 +0200 Aki Tuomi <aki.tuomi@open-xchange.com> (307bf115)
+
+ NEWS: Add news for 0.5.14.rc1
+
+
+M NEWS
+
+2021-04-13 17:24:01 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (26537156)
+
+ global: Adjust to buffer_t API change
+
+
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve/managesieve-settings.c
+
+2021-03-23 10:51:00 +0200 Aki Tuomi <aki.tuomi@open-xchange.com> (ad0d57b2)
+
+ managesieve: parent_event was renamed to event_parent
+
+
+M src/managesieve/main.c
+
+2020-04-16 11:09:17 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (1c7173a8)
+
+ global: Adjust to settings-parser API changes
+
+
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve/managesieve-capabilities.c
+M src/managesieve/managesieve-settings.c
+
+2021-03-15 18:27:02 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (0605bd02)
+
+ lib-sieve: sieve-interpreter - Adjust to cpu-limit API change
+
+
+M src/lib-sieve/sieve-interpreter.c
+
+2021-03-15 18:26:32 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (bd6e75f9)
+
+ lib-sieve: sieve-interpreter - Fix crash if max_cpu_time_secs==0
+
+
+M src/lib-sieve/sieve-interpreter.c
+
+2021-02-03 22:45:11 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (a7439203)
+
+ global: Use mailbox_get_last_internal_error()
+
+ mailbox_get_last_error() should be used only for client-visible errors. The
+ internal errors should be used for logging.
+
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/special-use/tst-specialuse-exists.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-storage-sync.c
+M src/lib-sieve/util/edit-mail.c
+M src/lib-sieve/util/mail-raw.c
+M src/lib-sieve/util/test-edit-mail.c
+M src/plugins/imapsieve/imap-sieve-storage.c
+M src/sieve-tools/sieve-filter.c
+
+2021-02-03 22:25:38 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (093fd3e5)
+
+ managesieve: Standardize disconnection log message
+
+
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/managesieve-client.c
+
+2021-02-03 22:16:30 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (8b58503f)
+
+ managesieve-login: Use client_destroy_iostream_error()
+
+
+M src/managesieve-login/client-authenticate.c
+
+2021-02-03 22:04:50 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (79a6118d)
+
+ managesieve-login: Replace "Aborted login" with "Disconnected: Aborted login
+ by logging out"
+
+
+M src/managesieve-login/client.c
+
+2021-02-03 22:02:00 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (2cd21f54)
+
+ managesieve-login: Remove duplicate "Disconnected: " log prefixes
+
+ client_destroy() already adds it.
+
+M src/managesieve-login/client-authenticate.c
+M src/managesieve-login/client.c
+
+2021-03-02 17:06:42 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (505b765c)
+
+ managesieve: Fix using mail_log_prefix when client is disconnected due to
+ server shutdown
+
+
+M src/managesieve/main.c
+M src/managesieve/managesieve-client.c
+
+2020-12-07 23:42:04 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (d99c69b8)
+
+ plugins: lda-sieve: Implement cumulative resource limits on script
+ execution.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2020-12-07 23:41:41 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (63fe1864)
+
+ plugins: imap-sieve: Implement cumulative resource limits on script
+ execution.
+
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2020-12-07 23:41:00 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (f9ebcd45)
+
+ plugins: imap-filter-sieve: Implement cumulative resource limits on script
+ execution.
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2020-12-04 12:19:28 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (8d6d9e9f)
+
+ lib-sieve: sieve-types - Add SIEVE_EXEC_RESOURCE_LIMIT exit code.
+
+ It indicates that script execution exceeded a resource limit (currently only
+ CPU time limit).
+
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-types.h
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite.c
+
+2020-12-04 03:47:04 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (c3807e32)
+
+ plugins: lda-sieve: Restructure lda_sieve_execute_script().
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2020-12-04 03:30:33 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (50fe61c8)
+
+ plugins: lda-sieve: Change return type of lda_sieve_execute_script*() to
+ int.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2020-12-04 03:17:17 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (4b5ced2c)
+
+ plugins: imap-filter-sieve: Restructure imap_sieve_filter_run_scripts().
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2020-12-04 03:12:01 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (0f5113e1)
+
+ plugins: imap-filter-sieve: Make temporary failure and corrupt binary errors
+ fatal.
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2020-12-04 03:08:12 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (9d2fa4de)
+
+ plugins: imap-filter-sieve: Add support for fatal script execute errors.
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+M src/plugins/imap-filter-sieve/imap-filter-sieve.h
+M src/plugins/imap-filter-sieve/imap-filter.c
+
+2021-01-04 16:09:00 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (3f007c7d)
+
+ plugins: imap-filter-sieve: Make sure an (internal) error message is
+ available for failed compile.
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2021-01-04 05:22:40 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (552611e2)
+
+ plugins: imap-filter-sieve: Fix useless addition of internal error message
+ to FILTER SIEVE errors.
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2020-12-04 02:54:58 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (f043569d)
+
+ plugins: imapsieve: Restructure imap_sieve_run_scripts().
+
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2020-12-04 02:45:50 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (d083bdab)
+
+ plugins: imapsieve: Make temporary failure and corrupt binary errors fatal.
+
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2020-12-04 02:36:36 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (dd1e4248)
+
+ plugins: imapsieve: Add support for fatal script execute errors.
+
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/imapsieve/imap-sieve.h
+
+2020-12-03 03:23:55 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (7f50cd8e)
+
+ lib-sieve: sieve-interpreter - Record last resource usage in struct
+ sieve_exec_status.
+
+
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-types.h
+
+2020-11-27 04:25:39 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (19fb7699)
+
+ lib-sieve: sieve-binary-dumper - Dump information from file header.
+
+
+M src/lib-sieve/sieve-binary-dumper.c
+
+2021-01-04 19:07:11 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (5a794cc8)
+
+ lib-sieve: sieve - Add sieve_check_executable().
+
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+
+2020-12-06 03:20:20 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (0c84d613)
+
+ lib-sieve: sieve - Add sieve_record_resource_usage().
+
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+
+2020-12-06 03:19:36 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (bcff0f7e)
+
+ lib-sieve: sieve - Check binary for resource limits before opening in
+ sieve_script_open().
+
+
+M src/lib-sieve/sieve.c
+
+2020-12-06 03:16:23 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (62f4b4fc)
+
+ lib-sieve: sieve-binary - Add sieve_binary_check_executable().
+
+ Checks whether binary is suitable for execution.
+
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary.h
+
+2020-12-08 01:27:54 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (54b120d4)
+
+ lib-sieve: sieve - Retain resource usage statistics across script recompile
+ in sieve_open*().
+
+
+M src/lib-sieve/sieve.c
+
+2020-12-10 00:54:37 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (015b1fda)
+
+ lib-sieve: sieve - Restructure sieve_open_script().
+
+ Move part within data stack frame to separate function.
+
+M src/lib-sieve/sieve.c
+
+2020-11-27 04:15:42 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (a01173c6)
+
+ lib-sieve: sieve-binary - Add support for recording cumulative resource
+ usage.
+
+ Currently, only CPU time is supported.
+
+M INSTALL
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-types.h
+
+2020-12-03 03:36:06 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (77d56fd5)
+
+ lib-sieve: sieve - Add API for resource usage manipulation and evaluation.
+
+
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+
+2020-12-23 03:05:12 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (0b9acda1)
+
+ lib-sieve: sieve-binary-file - Associate saved binary with save path if no
+ path is set.
+
+
+M src/lib-sieve/sieve-binary-file.c
+
+2020-11-27 02:50:06 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (0aaf8a2f)
+
+ lib-sieve: sieve-binary-file - Record file header in binary struct.
+
+
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.c
+
+2020-11-27 02:18:21 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (5e6e44c4)
+
+ lib-sieve: sieve-binary-file - Split off sieve_binary_fd_open().
+
+
+M src/lib-sieve/sieve-binary-file.c
+
+2020-11-27 00:10:14 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (489a8469)
+
+ lib-sieve: sieve-binary-file - Change binary file header format to include
+ header size and flags.
+
+
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.h
+
+2020-12-08 00:29:06 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (8b489404)
+
+ lib-sieve: sieve-binary-file - Move struct sieve_binary_header to
+ sieve-binary-private.h.
+
+
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+
+2020-11-27 00:10:14 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (3ce88199)
+
+ lib-sieve: sieve-binary-file - Split off sieve_binary_file_read_header().
+
+
+M src/lib-sieve/sieve-binary-file.c
+
+2020-11-27 01:23:34 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (16f2ef6e)
+
+ lib-sieve: sieve-binary-file - Add error_r return parameter to
+ _sieve_binary_open().
+
+
+M src/lib-sieve/sieve-binary-file.c
+
+2020-11-27 02:56:27 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (c89a110d)
+
+ lib-sieve: sieve-binary-file - Change return type of
+ sieve_binary_file_read().
+
+
+M src/lib-sieve/sieve-binary-file.c
+
+2020-11-27 02:01:12 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (3c438a32)
+
+ lib-sieve: sieve-binary-file - Remove unnecessary file load function
+ pointers.
+
+ There is only one implementation now.
+
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+
+2020-11-27 02:06:38 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (5c58aa91)
+
+ lib-sieve: sieve-binary-file - Change return type of
+ sieve_binary_file_open().
+
+
+M src/lib-sieve/sieve-binary-file.c
+
+2020-11-27 04:10:20 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (b729f228)
+
+ lib-sieve: sieve-binary-file - Make sieve_binary_file_close(NULL) a no-op.
+
+
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary.c
+
+2020-12-08 01:31:48 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (81b90f89)
+
+ lib-sieve: sieve - Change sieve_script_open() to use sieve_binary_close()
+ internally.
+
+
+M src/lib-sieve/sieve.c
+
+2020-11-27 03:46:02 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (99b4888a)
+
+ lib-sieve: sieve - Change sieve_close() to use sieve_binary_close()
+ internally.
+
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+
+2020-11-27 03:43:21 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (d9a02e46)
+
+ lib-sieve: sieve-binary - Add sieve_binary_close().
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+
+2020-11-27 03:33:23 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (710d01e5)
+
+ lib-sieve: sieve-binary - Make sieve_binary_unref(NULL) a no-op.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-script.c
+
+2020-10-28 20:16:17 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (68505e44)
+
+ lib-sieve: Enforce CPU time limit on Sieve script execution.
+
+
+M INSTALL
+M Makefile.am
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-settings.c
+A tests/execute/errors-cpu-limit.svtest
+A tests/execute/errors/cpu-limit.sieve
+
+2020-03-09 23:58:01 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (40b13e53)
+
+ lib-sieve: Reformat sieve-binary-dumper.h.
+
+
+M src/lib-sieve/sieve-binary-dumper.h
+
+2020-03-09 23:56:33 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (190727bb)
+
+ lib-sieve: Reformat sieve-binary-dumper.c.
+
+
+M src/lib-sieve/sieve-binary-dumper.c
+
+2020-11-27 03:58:45 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (dc3edc2b)
+
+ lib-sieve: Reformat sieve-binary-file.c.
+
+
+M src/lib-sieve/sieve-binary-file.c
+
+2020-03-12 03:39:36 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (715b95ce)
+
+ lib-sieve: Reformat sieve-settings.h.
+
+
+M src/lib-sieve/sieve-settings.h
+
+2020-03-12 03:37:15 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (3ee39f42)
+
+ lib-sieve: Reformat sieve-settings.c.
+
+
+M src/lib-sieve/sieve-settings.c
+
+2020-10-29 01:32:04 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (8463029f)
+
+ lib-sieve: Reformat sieve-limits.h.
+
+
+M src/lib-sieve/sieve-limits.h
+
+2020-03-24 17:25:52 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (7047a6d8)
+
+ lib-sieve: Reformat sieve.h.
+
+
+M src/lib-sieve/sieve.h
+
+2020-11-27 00:35:58 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (501c5700)
+
+ lib-sieve: Reformat sieve.c.
+
+
+M src/lib-sieve/sieve.c
+
+2020-04-08 16:19:18 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (457e2a4f)
+
+ lib-sieve: sieve-script - Fix leak of script object in
+ sieve_script_binary_dump_metadata().
+
+
+M src/lib-sieve/sieve-script.c
+
+2021-01-13 18:05:15 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (821a9516)
+
+ plugins: imap-filter-sieve: cmd-filter-sieve - Avoid using
+ imap_arg_as_nstring() in cmd_filter_sieve_script_parse_value_arg()
+
+ The argument can only be a quoted string here, so imap_arg_as_string() will
+ suffice.
+
+M src/plugins/imap-filter-sieve/cmd-filter-sieve.c
+
+2021-01-13 17:58:16 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (bba3a530)
+
+ plugins: imap-filter-sieve: cmd-filter-sieve - Do not allow NIL as script
+ name argument
+
+ This was not supposed to be accepted and led to unexpected behavior:
+
+ - FILTER SIEVE PERSONAL NIL was handled as FILTER SIEVE DELIVERY,
+ - FILTER SIEVE GLOBAL NIL caused an internal error.
+
+M src/plugins/imap-filter-sieve/cmd-filter-sieve.c
+
+2021-01-13 18:12:38 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (58d792cd)
+
+ plugins: imap-fitler-sieve: Reformat cmd-filter-sieve.c
+
+
+M src/plugins/imap-filter-sieve/cmd-filter-sieve.c
+
+2020-12-12 19:47:56 +0200 Aki Tuomi <aki.tuomi@open-xchange.com> (7a9a3219)
+
+ NEWS: Add news for 0.5.13
+
+
+M NEWS
+
+2020-11-10 11:46:47 +0200 Aki Tuomi <aki.tuomi@open-xchange.com> (8e405770)
+
+ m4: dovecot.m4 - Sync with core
+
+
+M m4/dovecot.m4
+
+2020-06-18 00:28:02 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (a1c1ca78)
+
+ lib-sieve: plugins: editheader: Fix infinite loop occurring when header
+ setting is invalid.
+
+
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M tests/extensions/editheader/protected.svtest
+
+2020-03-25 20:36:15 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (4187a868)
+
+ lib-sieve: plugins: editheader: Reformat ext-editheader-common.h.
+
+
+M src/lib-sieve/plugins/editheader/ext-editheader-common.h
+
+2020-03-25 20:33:38 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (879d2121)
+
+ lib-sieve: plugins: editheader: Reformat ext-editheader-common.c.
+
+
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+
+2020-06-11 20:53:26 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (fc605f10)
+
+ testsuite: cmd-test-mailbox - Check mailbox name validity.
+
+ Fixes assert failure occurring either at compiletime or at runtime
+ (depending on whether the value originates from variable).
+
+M src/testsuite/cmd-test-mailbox.c
+
+2020-06-11 20:53:24 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (5c0c25fd)
+
+ lib-sieve: plugins: special-use: tst-specialuse-exists - Check mailbox name
+ validity.
+
+ Fixes assert failure occurring either at compiletime or at runtime
+ (depending on whether the value originates from variable).
+
+M src/lib-sieve/plugins/special-use/tst-specialuse-exists.c
+M tests/extensions/special-use/errors.svtest
+A tests/extensions/special-use/errors/specialuse_exists-bad-utf8.sieve
+M tests/extensions/special-use/errors/syntax.sieve
+
+2020-06-11 20:53:23 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (c65f1c4c)
+
+ lib-sieve: plugins: mailbox: tst-mailboxexists - Check mailbox name validity
+ at runtime.
+
+ Fixes assert failure occurring at runtime (when value originates from
+ variable).
+
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M tests/extensions/mailbox/errors.svtest
+A tests/extensions/mailbox/errors/mailboxexists-bad-utf8.sieve
+
+2020-06-11 20:53:23 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (0659935e)
+
+ lib-sieve: ext-fileinto - Consistently use sieve_mailbox_check_name().
+
+
+M src/lib-sieve/ext-fileinto.c
+
+2020-06-11 22:33:36 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (dcb93b58)
+
+ tests: extensions: metadata: Add tests for bad UTF-8 in mailbox names.
+
+
+M tests/extensions/metadata/errors.svtest
+A tests/extensions/metadata/errors/metadata-bad-utf8.sieve
+A tests/extensions/metadata/errors/metadataexists-bad-utf8.sieve
+M tests/extensions/metadata/errors/syntax.sieve
+
+2020-06-11 21:56:44 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (f87ddf2b)
+
+ tests: extensions: mailbox: Add tests for syntax errors.
+
+
+M Makefile.am
+A tests/extensions/mailbox/errors.svtest
+A tests/extensions/mailbox/errors/syntax.sieve
+
+2020-06-11 21:35:47 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (b62d83a2)
+
+ tests: execute: Add tests for fileinto command executed with bad UTF-8 in
+ folder name.
+
+ Compile error is avoided by putting the mailbox name in a variable, which is
+ (currently) only evaluated at runtime.
+
+M tests/execute/errors.svtest
+A tests/execute/errors/fileinto-bad-utf8.sieve
+
+2020-06-11 21:26:56 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (cb916cca)
+
+ tests: compile: Add tests for fileinto command compile errors.
+
+
+M tests/compile/errors.svtest
+A tests/compile/errors/fileinto.sieve
+
+2020-06-11 20:53:22 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (01b3eaa3)
+
+ lib-sieve: sieve-actions - Fix error message in sieve_mailbox_check_name().
+
+
+M src/lib-sieve/sieve-actions.c
+
+2020-06-11 20:53:22 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (2085ed3d)
+
+ lib-sieve: plugins: metadata: tst-metadataexists - Fix warning message
+ prefix in tst_metadataexists_operation_execute().
+
+
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+
+2020-06-11 20:53:22 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (ac91b1fa)
+
+ testsuite: cmd-test-mailbox - Move runtime execution to separate functions.
+
+ Reduces code indent.
+
+M src/testsuite/cmd-test-mailbox.c
+
+2020-06-11 20:53:21 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (2ada0123)
+
+ lib-sieve: plugins: special-use: tst-specialuse-exists - Restructure
+ tst_specialuse_exists_operation_execute().
+
+ Reduces indent.
+
+M src/lib-sieve/plugins/special-use/tst-specialuse-exists.c
+
+2020-06-11 20:53:21 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (ceb4a50b)
+
+ lib-sieve: plugins: special-use: tst-specialuse-exists - Split off
+ tst_specialuse_exists_check_flag().
+
+ Reduces code indent.
+
+M src/lib-sieve/plugins/special-use/tst-specialuse-exists.c
+
+2020-06-11 20:53:20 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (3bf389e2)
+
+ lib-sieve: plugins: metadata: tst-metadataexists - Split off
+ tst_metadataexists_check_annotation().
+
+ Reduces code indent.
+
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+
+2020-06-11 20:53:20 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (d58ba0b3)
+
+ lib-sieve: plugins: mailbox: tst-mailboxexists - Restructure
+ tst_mailboxexists_operation_execute().
+
+ Reduces code indent.
+
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+
+2020-06-11 20:53:20 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (d27a2ca2)
+
+ lib-sieve: plugins: mailbox: tst-mailboxexists - Split off
+ tst_mailboxexists_test_mailbox().
+
+ Reduces code indent.
+
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+
+2020-06-11 20:53:19 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (06034e01)
+
+ lib-sieve: ext-fileinto - Improve error message for invalid folder name.
+
+
+M src/lib-sieve/ext-fileinto.c
+
+2020-06-11 20:53:19 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (3a8094f0)
+
+ lib-sieve: ext-fileinto - Always check validity of folder name at runtime.
+
+
+M src/lib-sieve/ext-fileinto.c
+
+2020-06-11 20:53:19 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (d09d71a8)
+
+ testsuite: cmd-test-mailbox - Fix comment in
+ cmd_test_mailbox_operation_execute().
+
+
+M src/testsuite/cmd-test-mailbox.c
+
+2020-06-11 20:53:18 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (aed6f90c)
+
+ lib-sieve: plugins: special-use: Reformat tst-specialuse-exists.c.
+
+
+M src/lib-sieve/plugins/special-use/tst-specialuse-exists.c
+
+2020-06-11 20:53:18 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (7793c0dc)
+
+ lib-sieve: plugins: metadata: Reformat tst-metadataexists.c.
+
+
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+
+2020-06-11 20:53:17 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (22e3c512)
+
+ lib-sieve: plugins: metadata: Reformat tst-metadata.c.
+
+
+M src/lib-sieve/plugins/metadata/tst-metadata.c
+
+2020-06-11 20:53:15 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (64ec8a73)
+
+ lib-sieve: plugins: mailbox: Reformat tst-mailboxexists.c.
+
+
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+
+2020-06-11 20:53:08 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (c80f315d)
+
+ lib-sieve: Reformat ext-fileinto.c.
+
+
+M src/lib-sieve/ext-fileinto.c
+
+2020-08-13 20:25:11 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (529fc691)
+
+ testsuite: cmd-test-fail - Remove unused _get_generator_context().
+
+
+M src/testsuite/cmd-test-fail.c
+
+2020-05-19 15:40:04 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (33c8d372)
+
+ lib-sieve: Adjust to message_parser_init() API change
+
+
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/sieve-message.c
+
+2020-06-30 11:53:28 +0300 Aki Tuomi <aki.tuomi@open-xchange.com> (cf9062c7)
+
+ NEWS: Add news for 0.5.11
+
+
+M NEWS
+
+2020-07-09 02:45:26 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (d8bd2c73)
+
+ lib-sieve: plugins: duplicate: Only save duplicate entry when the last
+ script executed successfully.
+
+ This prevents prematurely marking duplicates when errors occur during result
+ execution. Before, the pending duplicate database changes were committed
+ after each script executed in the sequence. If a later script failed,
+ duplicate tests would mark duplicate messages prematurely.
+
+ Disadvantage is that actions in earlier scripts that are shielded by a
+ duplicate test can be executed twice erroneously when errors occurred in
+ later scripts in the previous delivery. Still, unexpected duplicate action
+ execution is better than losing mail due to erroneous duplicate detections.
+
+ Fixing this properly requires extensively restructuring result execution.
+
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+
+2020-07-27 22:27:09 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (caca3091)
+
+ lib-sieve: sieve - Explicitly finish the result in
+ sieve_multiscript_finish().
+
+
+M src/lib-sieve/sieve.c
+
+2020-07-27 22:26:39 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (ab3bb29b)
+
+ lib-sieve: sieve-result - Add sieve_result_finish().
+
+
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2019-10-01 21:49:33 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (b3899bd5)
+
+ lib-sieve: sieve-actions - Add "last" parameter to action finish method.
+
+ This indicates whether the last script in the sequence is being executed.
+
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve.c
+M src/testsuite/testsuite-result.c
+
+2020-07-09 02:42:29 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (58d81c59)
+
+ lib-sieve: plugins: duplicate: ext-duplicate-common - Restructure
+ act_duplicate_mark_finish().
+
+
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+
+2020-06-08 19:26:58 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (d71045c1)
+
+ testsuite: Reliably terminate tests upon failure.
+
+ Before, it would only terminate the test when it failed explicitly using the
+ test_fail command.
+
+M Makefile.am
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+A tests/failures/fuzz1.svtest
+A tests/failures/fuzz2.svtest
+
+2020-06-10 12:27:08 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (6359033b)
+
+ testsuite: testsuite-mailstore - Preserve all allocated mails until result
+ is reset.
+
+ The actions contained in the result may keep references to the overriden
+ mail struct, so these need to be preserved.
+
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-result.c
+
+2020-06-08 19:26:50 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (2f20547d)
+
+ testsuite: testsuite-message - Preserve all allocated mails until result is
+ reset.
+
+ The actions contained in the result may keep references to the overriden
+ mail struct, so these need to be preserved.
+
+M src/testsuite/cmd-test-result.c
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite.c
+
+2020-06-08 19:26:47 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (c3fca0a1)
+
+ testsuite: Drop needless result reference in testsuite_run().
+
+ This holds a reference to the initial result, causing it to linger after
+ test_result_reset, thereby also holding a reference to the message context,
+ preventing it from being cleared. This in turn, can keep references to
+ modified message versions that cause the main message object to remain
+ referenced. This causes a panic in specific cases upon test_result_reset:
+
+ Panic: Input stream data unexpectedly has references
+
+M src/testsuite/testsuite.c
+M tests/extensions/editheader/execute.svtest
+
+2020-06-08 19:26:45 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (4635acae)
+
+ testsuite: Properly check address value parsed from message.
+
+ Caused a panic when input was not valid. This is only relevant to the test
+ suite and doesn't occur anywhere else (apart from the previous similar
+ commit for lib-sieve-tool).
+
+ Panic was:
+
+ Panic in file smtp-address.c: line 684 (smtp_address_write): assertion
+ failed: (smtp_char_is_qpair(*p))`
+
+M src/testsuite/testsuite-message.c
+M tests/extensions/vacation/smtp.svtest
+
+2020-06-10 13:02:10 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (39e9b39e)
+
+ lib-sieve-tool: sieve-tool - Properly check address value parsed from
+ message.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+
+2020-06-08 19:26:42 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (89ddd79d)
+
+ lib-sieve-tool: Add sieve_tool_get_mail_raw_user().
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+
+2020-06-08 19:26:40 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (571964e9)
+
+ lib-sieve: sieve-interpreter - Add sieve_interpreter_program_jump_to().
+
+
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+
+2020-06-08 19:26:38 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (b5ccedae)
+
+ lib-sieve: sieve-interpreter - Split off
+ sieve_interpreter_do_program_jump().
+
+
+M src/lib-sieve/sieve-interpreter.c
+
+2020-06-08 19:26:35 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (3e0a599e)
+
+ lib-sieve: sieve-interpreter - Split off
+ sieve_interpreter_check_program_jump().
+
+
+M src/lib-sieve/sieve-interpreter.c
+
+2020-06-08 19:26:33 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (ad7bb544)
+
+ lib-sieve: sieve-interpreter - Restructure sieve_interpreter_program_jump().
+
+
+M src/lib-sieve/sieve-interpreter.c
+
+2020-06-08 19:26:30 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (cba117cc)
+
+ lib-sieve: sieve-interpreter - Drop needless result reference in
+ sieve_interpreter_run().
+
+ It is immediately referenced in sieve_interpreter_continue(), called from
+ there.
+
+M src/lib-sieve/sieve-interpreter.c
+
+2020-06-08 19:26:19 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (de09a841)
+
+ lib-sieve: sieve-address - Require error_r parameters to not be NULL.
+
+ The error string is currently always used and it must be, so there is no
+ need to allow for the error_r paramerter to be NULL and unused.
+
+M src/lib-sieve/sieve-address.c
+
+2020-07-30 23:33:04 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (2028ada8)
+
+ testsuite: Add support for test cases with expected failure.
+
+
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite.c
+
+2020-06-09 12:43:16 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (2f645637)
+
+ testsuite: Reformat cmd-test.c.
+
+
+M src/testsuite/cmd-test.c
+
+2020-06-09 12:37:48 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (ecc4a3ac)
+
+ testsuite: Reformat cmd-test-result.c.
+
+
+M src/testsuite/cmd-test-result.c
+
+2020-06-09 12:32:42 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (6d250020)
+
+ testsuite: Reformat cmd-test-message.c.
+
+
+M src/testsuite/cmd-test-message.c
+
+2020-06-09 12:15:54 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (2dbd2890)
+
+ testsuite: Reformat cmd-test-mailbox.c.
+
+
+M src/testsuite/cmd-test-mailbox.c
+
+2020-06-09 12:08:22 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (89dd012a)
+
+ testsuite: Reformat cmd-test-fail.c.
+
+
+M src/testsuite/cmd-test-fail.c
+
+2020-06-09 12:00:28 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (bc26d8b6)
+
+ testsuite: Reformat testsuite-mailstore.h.
+
+
+M src/testsuite/testsuite-mailstore.h
+
+2020-06-09 12:00:13 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (ad35af9c)
+
+ testsuite: Reformat testsuite-mailstore.c.
+
+
+M src/testsuite/testsuite-mailstore.c
+
+2020-06-09 02:36:54 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (0324c6dd)
+
+ testsuite: Reformat testsuite-common.c.
+
+
+M src/testsuite/testsuite-common.c
+
+2020-06-09 02:30:42 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (f5a7bbb0)
+
+ testsuite: Reformat testsuite-common.h.
+
+
+M src/testsuite/testsuite-common.h
+
+2020-06-09 11:51:38 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (6dc7b477)
+
+ lib-sieve-tool: Reformat sieve-tool.h.
+
+
+M src/lib-sieve-tool/sieve-tool.h
+
+2020-06-09 11:51:09 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (76d6da31)
+
+ lib-sieve-tool: Reformat sieve-tool.c.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+
+2020-03-09 10:50:07 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (fc8940b1)
+
+ lib-sieve: Reformat sieve-address.h.
+
+
+M src/lib-sieve/sieve-address.h
+
+2020-03-09 10:49:57 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (f8effd5c)
+
+ lib-sieve: Reformat sieve-address.c.
+
+
+M src/lib-sieve/sieve-address.c
+
+2020-06-11 14:49:24 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (0cf888a0)
+
+ lib-sieve: plugins: relational: Fix segfault occurring in
+ mcht_relational_validate().
+
+ The segfault happens when this match type is the last argument of the test
+ command. This situation is not possible in a valid script; positional
+ arguments are normally present after that, which would prevent the segfault.
+ A variant of this bug occurs when the match type also has no argument of its
+ own. In either case the segfault is caused by referring to absent tag
+ arguments, which causes a NULL dereference.
+
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M tests/extensions/relational/errors.svtest
+A tests/extensions/relational/errors/syntax.sieve
+
+2020-06-17 23:54:17 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (0b96fb53)
+
+ lib-sieve: plugins: relational: Reformat ext-relational-common.h.
+
+
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+
+2020-06-17 23:53:56 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (81083e3e)
+
+ lib-sieve: plugins: relational: Reformat ext-relational-common.c.
+
+
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+
+2020-05-20 02:03:17 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (1b9b5ce2)
+
+ tests: plugins: extprograms: pipe/errors.svtest - Fix "Timeout" test.
+
+
+M tests/plugins/extprograms/pipe/errors.svtest
+
+2020-05-07 14:44:12 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (1a8be20e)
+
+ managesieve-login: proxy - Forward remote AUTHENTICATE TRYLATER failures
+
+
+M src/managesieve-login/managesieve-proxy.c
+
+2020-05-06 20:37:03 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (bb5c14a1)
+
+ managesieve-login: proxy: Reconnect on temporary authentication failures
+
+
+M src/managesieve-login/managesieve-proxy.c
+
+2020-05-07 15:01:43 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (613eb103)
+
+ managesieve-login: proxy - Parse AUTHENTICATE reply more correctly
+
+ It's still not fully correct, but we don't have existing code that supports
+ parsing it.
+
+M src/managesieve-login/managesieve-proxy.c
+
+2020-05-06 20:40:14 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (b817b261)
+
+ managesieve-login: Adjust to proxy_error() -> proxy_failed() API change
+
+
+M src/managesieve-login/client.c
+M src/managesieve-login/managesieve-proxy.c
+M src/managesieve-login/managesieve-proxy.h
+
+2020-05-06 18:10:30 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (27bb1903)
+
+ managesieve-login: Replace e_error()+client_proxy_failed() calls with
+ login_proxy_failed()
+
+
+M src/managesieve-login/managesieve-proxy.c
+
+2020-05-06 16:54:15 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (7a6cc989)
+
+ managesieve-login: Remove redundant/early freeing of proxy_password
+
+
+M src/managesieve-login/managesieve-proxy.c
+
+2020-02-18 23:27:03 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (038274fe)
+
+ global: Properly parse Message-ID header.
+
+ Use mail_get_message_id() instead of just mail_get_first_header().
+
+M src/lib-sieve/plugins/duplicate/tst-duplicate.c
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-message.c
+
+2020-04-21 18:31:13 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (72bed3a5)
+
+ testsuite: testsuite-message - Give all global variables a "testsuite_"
+ prefix.
+
+
+M src/testsuite/testsuite-message.c
+
+2020-04-21 18:27:33 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (06b29fd6)
+
+ testsuite: Reformat testsuite-message.h.
+
+
+M src/testsuite/testsuite-message.h
+
+2020-04-21 18:25:38 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (6b2bc756)
+
+ testsuite: Reformat testsuite-message.c.
+
+
+M src/testsuite/testsuite-message.c
+
+2020-04-21 23:15:52 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (1bcf28c8)
+
+ managesieve: Fix debug event's printf format type
+
+
+M src/managesieve/cmd-havespace.c
+
+2020-04-24 13:05:01 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (6c81309a)
+
+ managesieve-login: Correctly adjust to core login-common API changes.
+
+ Previous commit was accidentally for an earlier version of the API change.
+
+M src/managesieve-login/client.c
+
+2020-04-10 01:02:50 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (568c72e7)
+
+ managesieve-login: Adjust to core login-common API changes.
+
+
+M src/managesieve-login/client.c
+M src/managesieve-login/managesieve-proxy.c
+
+2020-04-05 01:25:02 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (464a0f92)
+
+ lib-sieve: Use "sieve" category as parent for "sieve-*" categories
+
+
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-execute.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-storage.c
+
+2020-03-11 15:43:47 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (7b97795e)
+
+ managesieve: Change managesieve_max_line_length setting type to "size"
+
+
+M src/managesieve/managesieve-settings.c
+M src/managesieve/managesieve-settings.h
+
+2020-03-24 17:59:18 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (ff7d9089)
+
+ global: Remove dead assignments
+
+ Found by latest clang scan-build.
+
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/sieve-message.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+
+2020-03-24 17:56:20 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (da702576)
+
+ plugins: imap-filter-sieve: SIEVE SCRIPT - Reorder if checks to remove
+ unnecessary indenting
+
+ Nothing changes in the code logic.
+
+M src/plugins/imap-filter-sieve/cmd-filter-sieve.c
+
+2020-03-24 17:44:18 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (f69f9fe1)
+
+ plugins: imap-filter-sieve: SIEVE SCRIPT - Cleanup istream return value
+ checking
+
+ The old code seems to have worked correctly already, but now it's a bit
+ clearer how it was intended to work.
+
+M src/plugins/imap-filter-sieve/cmd-filter-sieve.c
+
+2020-03-24 17:40:28 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (919704e7)
+
+ lib-sieve: plugins: body: Fix compiler warning
+
+ Fixes "warning: cast to smaller integer type" with new clang.
+
+M src/lib-sieve/plugins/body/tst-body.c
+
+2020-03-17 09:33:24 -0400 Josef 'Jeff' Sipek <jeff.sipek@open-xchange.com> (301a5c44)
+
+ global: use %zu directly instead of PRIuSIZE_T
+
+
+M src/lib-managesieve/managesieve-arg.c
+M src/lib-managesieve/managesieve-quote.c
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+M src/managesieve/cmd-havespace.c
+M src/managesieve/managesieve-quota.c
+M src/plugins/imap-filter-sieve/cmd-filter-sieve.c
+M src/plugins/imap-filter-sieve/imap-filter.c
+
+2020-03-09 14:54:04 +0200 Aki Tuomi <aki.tuomi@open-xchange.com> (5992e367)
+
+ NEWS: Fix news for 0.5.10
+
+
+M NEWS
+
+2020-03-03 13:59:43 +0200 Aki Tuomi <aki.tuomi@open-xchange.com> (2e6a4515)
+
+ NEWS: Add news for v0.5.10
+
+
+M NEWS
+
+2019-11-29 13:38:53 +0200 Aki Tuomi <aki.tuomi@open-xchange.com> (9c520dcf)
+
+ NEWS: Add news for v0.5.9
+
+
+M NEWS
+
+2019-11-29 13:34:40 +0200 Aki Tuomi <aki.tuomi@open-xchange.com> (fec11941)
+
+ NEWS: Sync missing news from v0.5.7-v0.5.8
+
+
+M NEWS
+
+2020-02-07 11:21:15 +0200 Aki Tuomi <aki.tuomi@open-xchange.com> (3bcdac3a)
+
+ Update m4 from core
+
+
+M m4/dovecot.m4
+
+2020-01-24 23:43:57 +0200 Timo Sirainen <timo.sirainen@open-xchange.com> (7b16a827)
+
+ lib-sieve: Replace gettimeofday() calls with i_gettimeofday()
+
+
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+
+2020-01-07 22:16:19 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (408aa45c)
+
+ plugins: imap-filter-sieve: Add IMAP UID prefix to result action log
+ messages.
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2020-01-07 22:15:38 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (d6b55a3d)
+
+ plugins: imapsieve: Add IMAP UID prefix to result action log messages.
+
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2020-01-07 22:21:19 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (4610f795)
+
+ plugins: lda-sieve: Also amend debug messages with Message-ID prefix.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2020-01-07 22:10:21 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (818655d4)
+
+ plugins: imapsieve: Make current mail available in struct
+ imap_sieve_context.
+
+
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/imapsieve/imap-sieve.h
+
+2020-01-07 22:07:46 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (fa882b62)
+
+ plugins: imap-filter-sieve: Make current mail available in struct
+ imap_filter_sieve_context.
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+M src/plugins/imap-filter-sieve/imap-filter-sieve.h
+
+2020-01-07 22:13:53 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (895b035a)
+
+ lib-sieve: Add flag that determines whether result actions are logged as
+ debug or info.
+
+ Default is now debug logging, which is used for the IMAP plugins. The LDA
+ Sieve plugin uses info logging.
+
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-types.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+
+2020-01-05 17:54:20 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (23de7368)
+
+ sieve-tools: Reformat sieve-filter.c.
+
+
+M src/sieve-tools/sieve-filter.c
+
+2020-01-05 17:27:02 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (8df0409c)
+
+ sieve-tools: Reformat sieve-test.c.
+
+
+M src/sieve-tools/sieve-test.c
+
+2019-10-06 17:13:02 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (f5993afe)
+
+ plugins: imapsieve: imap-sieve-storage - Fix bug in composing the sorted
+ rule array.
+
+ When no insertion point was found, it would always insert the new rule at
+ the beginning, rather than at the end.
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2019-12-11 10:23:45 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (4efeaa21)
+
+ lib-sieve: plugins: vacation: cmd-vacation - Perform all address comparisons
+ case-insensitively.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M tests/extensions/vacation/reply.svtest
+
+2019-12-10 21:46:53 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (87d7c1ee)
+
+ lib-sieve: plugins: vacation: cmd-vacation - Consolidate message address
+ comparison in separate function.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2019-12-08 13:40:28 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (ef3509c3)
+
+ lib-sieve: plugins: vacation: cmd-vacation - Restructure
+ _get_full_reply_recipient().
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2019-12-08 13:29:24 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (400566cc)
+
+ lib-sieve: plugins: vacation: cmd-vacation - Restructure
+ _contains_my_address().
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2019-11-27 15:45:25 -0500 Josef 'Jeff' Sipek <jeff.sipek@open-xchange.com> (2774971b)
+
+ sieve: Change rename event's script name fields for consistency
+
+ Core is using {old,new}_foo for the RENAME IMAP command event, so let's
+ follow suit.
+
+M src/lib-sieve/sieve-script.c
+
+2019-11-27 15:27:57 -0500 Josef 'Jeff' Sipek <jeff.sipek@open-xchange.com> (3fcbfe87)
+
+ managesieve: Change rename event's script name fields for consistency
+
+ Core is using {old,new}_foo for the RENAME IMAP command event, so let's
+ follow suit.
+
+M src/managesieve/cmd-renamescript.c
+
+2019-11-13 15:17:18 -0500 Josef 'Jeff' Sipek <jeff.sipek@open-xchange.com> (e0d24a23)
+
+ global: Remove sieve_ event field prefixes
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-storage.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-setactive.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+
+2019-11-13 14:57:30 -0500 Josef 'Jeff' Sipek <jeff.sipek@open-xchange.com> (0828b452)
+
+ global: Remove managesieve_ event field prefixes
+
+
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-havespace.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/cmd-setactive.c
+M src/managesieve/managesieve-client.c
+
+2018-08-28 23:02:03 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (775c6d60)
+
+ plugins: imap-filter-sieve: Add headers to trace log file.
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2019-10-29 10:16:10 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (71853c63)
+
+ plugins: imap-filter-sieve: Restructure imap_filter_sieve_init_trace_log().
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2018-08-28 23:01:44 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (4f77ad35)
+
+ plugins: imapsieve: Add headers to trace log file.
+
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2019-10-29 10:06:09 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (e8ddc4a0)
+
+ plugins: imapsieve: Restructure imap_sieve_run_init_trace_log().
+
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2018-08-28 23:00:46 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (c338c755)
+
+ plugins: lda-sieve: Add header to trace log file.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2019-10-29 10:01:55 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (e22d9fff)
+
+ plugins: lda-sieve: Initialize trace log in a separate function.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2018-08-28 23:22:30 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (43eb04ee)
+
+ plugins: imap-filter-sieve: Create a single trace file for a single IMAP
+ command.
+
+ Before, it created a separate trace file for each individual filtered
+ message.
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+M src/plugins/imap-filter-sieve/imap-filter-sieve.h
+
+2018-08-28 23:08:06 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (d285de14)
+
+ plugins: imapsieve: Create a single trace file for a single IMAP command.
+
+ Before, it created a separate trace file for each individual filtered
+ message.
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2018-08-29 00:21:22 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (035f23f0)
+
+ plugins: imap-filter-sieve: Make filter context available in Sieve context.
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+M src/plugins/imap-filter-sieve/imap-filter-sieve.h
+
+2018-08-28 22:01:38 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (12178738)
+
+ lib-sieve: Add sieve_trace_log_printf(), which allows writing to the trace
+ log directly.
+
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+
+2018-08-28 21:43:14 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (806ac6d5)
+
+ lib-sieve: Remove optional label from trace log file name.
+
+ It is generally a bad idea to add a potentially unlimited string to a
+ filename, especially when it contains a mailbox name.
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2019-10-29 21:48:40 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (9c24ea28)
+
+ plugins: imapsieve: Reformat imap-sieve.c.
+
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2019-10-28 22:40:17 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (fbfd773f)
+
+ managesieve: cmd-setactive - Add event fields for compile errors and
+ warnings.
+
+
+M src/managesieve/cmd-setactive.c
+
+2019-10-28 22:33:50 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (d558b050)
+
+ managesieve: cmd-setactive - Add "error" event field for all error events.
+
+ Before, only storage errors had the "error" field set.
+
+M src/managesieve/cmd-setactive.c
+
+2019-10-28 22:38:08 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (31b09187)
+
+ managesieve: cmd-putscript - Add event fields for compile errors and
+ warnings.
+
+
+M src/managesieve/cmd-putscript.c
+
+2019-10-28 22:32:33 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (abd18dbc)
+
+ managesieve: cmd-putscript - Add "error" event field for all error events.
+
+ Before, only storage errors had the "error" field set.
+
+M src/managesieve/cmd-putscript.c
+
+2019-10-28 22:21:59 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (9cfb06c7)
+
+ managesieve: managesieve-quota - Add "error" field for the command event
+ when the quota check fails.
+
+
+M src/managesieve/managesieve-quota.c
+
+2019-10-28 22:17:49 +0100 Stephan Bosch <stephan.bosch@open-xchange.com> (75da0600)
+
+ managesieve: managesieve-client - Rename "args" command event field to
+ "managesieve_command_args".
+
+ This makes more sense with the managesieve_command_name field.
+
+M src/managesieve/managesieve-client.c
+
+2019-10-22 21:47:23 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (1dc7b2bc)
+
+ managesieve: Emit command events.
+
+
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-havespace.c
+M src/managesieve/cmd-listscripts.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/cmd-setactive.c
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+M src/managesieve/managesieve-quota.c
+
+2019-10-23 22:16:22 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (286bb6f1)
+
+ managesieve: cmd-putscript - Handle storage error in a common function.
+
+
+M src/managesieve/cmd-putscript.c
+
+2019-10-23 22:11:47 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (06793ee3)
+
+ managesieve: managesieve-quota - Use command context rather than client as
+ parameter.
+
+
+M src/managesieve/cmd-havespace.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/managesieve-quota.c
+M src/managesieve/managesieve-quota.h
+
+2019-10-16 23:58:23 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (969386f5)
+
+ managesieve: managesieve-client - Use client event for Sieve storage.
+
+
+M src/managesieve/managesieve-client.c
+
+2018-08-02 10:01:04 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (6e17ae3d)
+
+ managesieve: Add client_command_context.event and use it as global event
+ while running.
+
+
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+
+2018-08-02 09:44:12 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (94c84bed)
+
+ managesieve: Add client.event and use it as mail_*user's parent event.
+
+
+M src/managesieve/main.c
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+M src/managesieve/managesieve-common.h
+
+2019-10-17 23:28:31 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (292a46a9)
+
+ managesieve: Store command args to client command contexts for debugging
+ purposes.
+
+
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+
+2019-10-24 01:04:39 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (cc73a587)
+
+ lib-sieve: sieve-storage - Emit events for saving Sieve scripts.
+
+
+M src/lib-sieve/sieve-storage-private.h
+M src/lib-sieve/sieve-storage.c
+
+2019-10-24 00:41:00 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (2ae307bd)
+
+ lib-sieve: sieve-storage - Emit event for storage deactivation.
+
+
+M src/lib-sieve/sieve-storage.c
+
+2019-10-24 14:37:04 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (af2b31cc)
+
+ lib-sieve: sieve-storage - Better keep track of whether saving a script has
+ failed.
+
+
+M src/lib-sieve/sieve-storage.c
+
+2019-10-23 23:41:10 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (c0c04bbc)
+
+ lib-sieve: sieve-script - Emit events for various script manipulations.
+
+
+M src/lib-sieve/sieve-script.c
+
+2019-10-23 23:45:16 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (69959aad)
+
+ lib-sieve: sieve-script - Split off sieve_script_copy_from_default() from
+ sieve_script_rename().
+
+
+M src/lib-sieve/sieve-script.c
+
+2019-10-23 22:50:05 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (a8f74fee)
+
+ lib-sieve: sieve-script - Add more event fields.
+
+
+M src/lib-sieve/sieve-script.c
+
+2019-10-23 22:57:34 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (2b0bdd68)
+
+ lib-sieve: sieve-script - Use sieve-storage event as event parent.
+
+
+M src/lib-sieve/sieve-script.c
+
+2019-10-24 00:16:43 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (397a184b)
+
+ lib-sieve: sieve-storage - Add more event fields.
+
+
+M src/lib-sieve/sieve-storage.c
+
+2019-10-24 00:07:00 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (f832fcf5)
+
+ lib-sieve: sieve-storage - Add sieve-storage event category.
+
+
+M src/lib-sieve/sieve-storage.c
+
+2019-10-24 15:21:56 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (9326853d)
+
+ lib-sieve: sieve-storage - Restructure alloc/free of script save context.
+
+
+M src/lib-sieve/sieve-storage-private.h
+M src/lib-sieve/sieve-storage.c
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+M src/lib-sieve/storage/file/sieve-file-storage.h
+
+2019-10-17 23:26:05 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (a69a0c1d)
+
+ lib-managesieve: managesieve-arg - Add functions for converting an argument
+ list to a string.
+
+
+M src/lib-managesieve/managesieve-arg.c
+M src/lib-managesieve/managesieve-arg.h
+
+2019-10-22 22:34:56 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (527e75dc)
+
+ managesieve: cmd-deletescript - Restructure cmd_deletescript().
+
+
+M src/managesieve/cmd-deletescript.c
+
+2019-10-22 21:51:29 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (90262f2e)
+
+ managesieve: cmd-setactive - Remove empty line from
+ cmd_setactive_activate().
+
+
+M src/managesieve/cmd-setactive.c
+
+2019-10-22 22:28:08 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (ed8cfba4)
+
+ lib-sieve: sieve-script - sieve_script_unref(NULL) should be a no-op.
+
+
+M src/lib-sieve/sieve-script.c
+
+2019-10-22 20:31:42 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (0e2806aa)
+
+ lib-managesieve: Reformat managesieve-arg.c.
+
+
+M src/lib-managesieve/managesieve-arg.c
+
+2019-10-22 20:27:52 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (a71cf469)
+
+ lib-managesieve: Reformat managesieve-arg.h.
+
+
+M src/lib-managesieve/managesieve-arg.h
+
+2019-10-20 14:49:48 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (1f6c2662)
+
+ managesieve: cmd-setactive - Restructure cmd_setactive().
+
+
+M src/managesieve/cmd-setactive.c
+
+2019-10-20 14:37:58 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (5b0b3317)
+
+ managesieve: cmd-putscript - Restructure cmd_putscript_finish_parsing().
+
+
+M src/managesieve/cmd-putscript.c
+
+2019-10-20 14:14:34 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (6efa7b09)
+
+ managesieve: cmd-capability - Restructure cmd_capability().
+
+
+M src/managesieve/cmd-capability.c
+
+2019-10-20 14:10:59 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (ae9301db)
+
+ managesieve: managesieve-quota - Restructure managesieve_quota_check_all().
+
+
+M src/managesieve/managesieve-quota.c
+
+2019-10-20 14:06:38 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (5d231d8e)
+
+ managesieve: Reformat managesieve-commands.c.
+
+
+M src/managesieve/managesieve-commands.c
+
+2019-10-20 14:05:09 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (21d3fba3)
+
+ managesieve: Reformat managesieve-settings.c.
+
+
+M src/managesieve/managesieve-settings.c
+
+2019-10-20 14:03:22 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (f2f157a3)
+
+ managesieve: Reformat managesieve-capabilities.c.
+
+
+M src/managesieve/managesieve-capabilities.c
+
+2019-10-20 14:00:59 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (24bd78e0)
+
+ managesieve: Reformat managesieve-quota.h.
+
+
+M src/managesieve/managesieve-quota.h
+
+2019-10-20 14:00:16 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (2ae19412)
+
+ managesieve: Reformat managesieve-quota.c.
+
+
+M src/managesieve/managesieve-quota.c
+
+2019-10-20 13:57:32 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (6d6603da)
+
+ managesieve: Reformat cmd-setactive.c.
+
+
+M src/managesieve/cmd-setactive.c
+
+2019-10-20 13:53:05 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (1ee76ad6)
+
+ managesieve: Reformat cmd-renamescript.c.
+
+
+M src/managesieve/cmd-renamescript.c
+
+2019-10-20 13:52:22 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (60d31c4a)
+
+ managesieve: Reformat cmd-putscript.c.
+
+
+M src/managesieve/cmd-putscript.c
+
+2019-10-20 13:43:51 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (4b3e8629)
+
+ managesieve: Reformat cmd-noop.c.
+
+
+M src/managesieve/cmd-noop.c
+
+2019-10-20 13:43:08 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (55507ca6)
+
+ managesieve: Reformat cmd-logout.c.
+
+
+M src/managesieve/cmd-logout.c
+
+2019-10-20 13:42:39 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (36babb7a)
+
+ managesieve: Reformat cmd-capability.c.
+
+
+M src/managesieve/cmd-capability.c
+
+2019-10-20 13:39:24 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (c42bf0f9)
+
+ managesieve: Reformat cmd-listscripts.c.
+
+
+M src/managesieve/cmd-listscripts.c
+
+2019-10-20 13:38:13 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (e214f94e)
+
+ managesieve: Reformat cmd-havespace.c.
+
+
+M src/managesieve/cmd-havespace.c
+
+2019-10-20 13:36:41 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (d11a7ee3)
+
+ managesieve: Reformat cmd-getscript.c.
+
+
+M src/managesieve/cmd-getscript.c
+
+2019-10-20 13:33:04 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (44a58eee)
+
+ managesieve: Reformat cmd-deletescript.c.
+
+
+M src/managesieve/cmd-deletescript.c
+
+2019-10-16 23:04:49 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (4e47d097)
+
+ managesieve: Reformat main.c.
+
+
+M src/managesieve/main.c
+
+2019-10-16 22:59:17 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (e75d0fe3)
+
+ managesieve: Reformat managesieve-client.h.
+
+
+M src/managesieve/managesieve-client.h
+
+2019-10-16 22:55:46 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (41778e8d)
+
+ managesieve: Reformat managesieve-client.c.
+
+
+M src/managesieve/managesieve-client.c
+
+2019-10-13 13:52:59 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (de1f2da7)
+
+ lib-sieve: plugins: special-use: tag-special-use - Fix handling of variable
+ argument.
+
+ The use of a variable substitution erroneously produced a runtime syntax
+ error.
+
+M src/lib-sieve/plugins/special-use/tag-specialuse.c
+M tests/extensions/special-use/execute.svtest
+
+2019-10-13 13:36:51 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (5abbfb0f)
+
+ lib-sieve: plugins: special-use: tag-special-use - Fix error message
+ prefixes.
+
+
+M src/lib-sieve/plugins/special-use/tag-specialuse.c
+
+2019-10-13 13:34:13 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (024dd76e)
+
+ lib-sieve: plugins: special-use: ext-special-use-common.h - Fix comment.
+
+
+M src/lib-sieve/plugins/special-use/ext-special-use-common.h
+
+2019-10-13 13:30:36 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (e4d5748f)
+
+ lib-sieve: plugins: special-use: ext-special-use - Fix extension status
+ information.
+
+
+M src/lib-sieve/plugins/special-use/ext-special-use.c
+
+2019-10-10 15:36:28 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (fa3da3a5)
+
+ lib-sieve: sieve-actions - Fix autocreate and autosubscribe for keep and
+ fileinto actions.
+
+ This was broken by recent adjustments to changes in Dovecot lib-storage API.
+
+M src/lib-sieve/sieve-actions.c
+
+2016-10-03 16:51:46 +0200 Stephan Bosch <stephan@dovecot.fi> (1cda7a5b)
+
+ lib-sieve: Implement support for the "special-use" extension.
+
+
+M Makefile.am
+M configure.ac
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/special-use/Makefile.am
+A src/lib-sieve/plugins/special-use/ext-special-use-common.c
+A src/lib-sieve/plugins/special-use/ext-special-use-common.h
+A src/lib-sieve/plugins/special-use/ext-special-use.c
+A src/lib-sieve/plugins/special-use/tag-specialuse.c
+A src/lib-sieve/plugins/special-use/tst-specialuse-exists.c
+M src/lib-sieve/sieve-extensions.c
+A tests/extensions/special-use/errors.svtest
+A tests/extensions/special-use/errors/syntax.sieve
+A tests/extensions/special-use/execute.svtest
+
+2017-10-02 00:20:19 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (3acd20dd)
+
+ lib-sieve: store action: Don't open the mailbox until act_store_execute().
+
+ This allows side-effects to open a different mailbox than what is allocated
+ initially in act_store_start().
+
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/sieve-actions.c
+
+2017-10-02 01:07:59 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (2298ecf1)
+
+ lib-sieve: store action: Properly allocate error in act_store_start().
+
+
+M src/lib-sieve/sieve-actions.c
+
+2017-10-02 00:59:49 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (5d3b67f3)
+
+ lib-sieve: store action: Allow side-effects to change the mailbox identifier
+ used in action logging.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+
+2017-10-02 00:47:40 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (afa5e258)
+
+ lib-sieve: plugins: mailbox: tag-mailbox-create - Add variable for
+ trans->box in seff_mailbox_create_pre_execute().
+
+
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+
+2017-10-02 00:45:15 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (763607ed)
+
+ lib-sieve: sieve-actions - Add variable for trans->box in
+ act_store_execute().
+
+
+M src/lib-sieve/sieve-actions.c
+
+2017-10-02 00:39:34 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (550f90f5)
+
+ lib-sieve: sieve-actions - Move recording of the last used storage to an
+ earlier instance.
+
+
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/sieve-actions.c
+
+2017-10-02 00:13:28 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (b29e683d)
+
+ lib-sieve: store action: Improve sieve_act_store_get_storage_error().
+
+ Use mailbox_get_last_error() shorthand rather than
+ mail_storage_get_last_error().
+
+M src/lib-sieve/sieve-actions.c
+
+2017-10-02 00:06:54 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (b540702e)
+
+ lib-sieve: store action: Move checking of keywords to the result execution.
+
+ This way, the mailbox does not need to be opened until result execution.
+
+M src/lib-sieve/sieve-actions.c
+
+2017-10-01 23:56:17 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (f578b181)
+
+ lib-sieve: plugins: mailbox: Use the new mailbox_alloc_for_user() for the
+ mailboxexists test.
+
+ By setting the MAILBOX_FLAG_POST_SESSION flag, this makes sure the result
+ of this test closely matches what would happen for a real delivery action
+ using
+ "fileinto".
+
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+
+2017-10-01 23:46:46 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (b111fa06)
+
+ lib-sieve: plugins: mailbox: tag-mailbox-create - Improve error handling.
+
+
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+
+2017-10-01 20:57:38 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (94f8e03a)
+
+ lib-sieve: sieve-result - Sort action side effects based on precedence
+ value.
+
+ This way, the execution order can be made explicit.
+
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+
+2019-10-10 00:49:08 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (2208be4e)
+
+ lib-sieve: sieve-error - Add sieve_error_from_external() utility function
+ and use it.
+
+
+M src/lib-sieve/plugins/metadata/tst-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-script.c
+
+2019-10-03 13:46:06 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (f69e172a)
+
+ lib-sieve: Adjust to changes in Dovecot mailbox_alloc*() API.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2019-10-03 21:08:54 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (cf851a45)
+
+ lib-sieve: sieve-message - Adjust to changes in Dovecot struct smtp_address.
+
+
+M src/lib-sieve/sieve-message.c
+
+2018-09-18 23:54:18 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (72868144)
+
+ plugins: imap-filter-sieve: Fix mixup between tag and problem part of the
+ FILTER response for compile error.
+
+
+M src/plugins/imap-filter-sieve/cmd-filter-sieve.c
+
+2018-09-18 23:45:41 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (e8b9f4da)
+
+ plugins: imap-filter-sieve: Perform main initialization of Sieve script
+ execution environment only once.
+
+ This way, any configuration errors can be reported as a single FILTER ERRORS
+ response, rather than a FILTERED ERRORS response for each filtered message.
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+M src/plugins/imap-filter-sieve/imap-filter-sieve.h
+M src/plugins/imap-filter-sieve/imap-filter.c
+
+2018-09-18 22:39:38 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (6aecd317)
+
+ plugins: imap-filter-sieve: Make sure user gets to see at least one error
+ when script execution fails.
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2019-05-17 10:39:25 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (10c5cbe8)
+
+ lib-managesieve: Make sure str_unescape() won't be writing past allocated
+ memory
+
+ The previous commit should already prevent this, but this makes sure it
+ can't become broken in the future either. It makes the performance a tiny
+ bit worse, but that's not practically noticeable.
+
+M src/lib-managesieve/managesieve-parser.c
+
+2019-05-10 19:43:55 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (16e047c5)
+
+ lib-managesieve: Don't accept strings with NULs
+
+ ManageSieve doesn't allow NULs in strings.
+
+ This fixes a bug with unescaping a string with NULs: str_unescape() could
+ have been called for memory that points outside the allocated string,
+ causing heap corruption. This could cause crashes or theoretically even
+ result in remote code execution exploit.
+
+ Found by Nick Roessler and Rafi Rubin
+
+M src/lib-managesieve/managesieve-parser.c
+
+2018-08-17 10:00:09 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (5cd8cfc1)
+
+ lib-sieve: duplicate extension: Fix caching of duplicate checks to also
+ compare the actual hashes.
+
+ Before, it only compared the handles, which would cause duplicate tests with
+ different values to be cached as the same duplicate test.
+
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+
+2019-08-12 22:35:51 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (36ff477b)
+
+ managesieve-login: Remove duplicate code denying anonymous logins.
+
+ Also explicitly initialize login_binary->anonymous_login_acceptable to FALSE
+ to make clear that anonymous logins are intentionally not allowed for
+ ManageSieve.
+
+M src/managesieve-login/client-authenticate.c
+M src/managesieve-login/client.c
+
+2019-08-09 01:06:59 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (fcb23499)
+
+ managesieve-login: client.c - Use designated initializer for struct
+ client_vfuncs.
+
+
+M src/managesieve-login/client.c
+
+2019-07-31 22:50:57 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (e7babff7)
+
+ lib-sieve: sieve-result - Assert that an action name is available in
+ _sieve_result_add_action().
+
+ Addresses a Coverity report.
+
+M src/lib-sieve/sieve-result.c
+
+2019-07-31 22:37:47 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (8cfd3ff6)
+
+ global: Rename all sieve action events to a uniform "sieve_action_finished".
+
+ The action name can be determined from the sieve_action_name field that
+ existed before.
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/sieve-actions.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+
+2019-07-31 22:35:20 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (a16a56d8)
+
+ lib-sieve: plugins: enotify: ext-enotify-common - Add
+ sieve_enotify_create_finish_event().
+
+
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+
+2019-07-31 22:17:46 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (4d033fa2)
+
+ lib-sieve: sieve-action - Add sieve_action_create_finish_event().
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+
+2019-07-31 22:14:45 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (a69c8364)
+
+ lib-sieve: sieve-action - Drop unused definition of
+ sieve_action_get_location() from header file.
+
+
+M src/lib-sieve/sieve-actions.h
+
+2019-07-07 14:34:41 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (f64bd39b)
+
+ plugins: imap-filter-sieve: imap-filter-sieve - Use imap client event as
+ parent for sieve event.
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2019-07-07 14:33:49 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (ae080252)
+
+ plugins: imapsieve: imap-sieve - Use imap client event as parent for sieve
+ event.
+
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2019-07-07 14:33:01 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (2e459125)
+
+ plugins: lda-sieve: lda-sieve-plugin - Use deliver event as parent for sieve
+ event.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2019-06-28 21:20:45 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (ed58d960)
+
+ lib-sieve: Emit named event for successfully executed actions.
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/sieve-actions.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+
+2019-07-06 23:03:02 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (f459db4c)
+
+ lib-sieve: sieve-interpreter - Emit events for start and finish of script
+ runtime.
+
+
+M src/lib-sieve/sieve-interpreter.c
+
+2019-07-03 13:44:15 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (0e68299a)
+
+ lib-sieve: sieve-error - Drop error handler hierarchy.
+
+ It is no longer used.
+
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+
+2019-07-03 13:34:35 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (04f40d52)
+
+ lib-sieve: sieve-error - Drop prefix error handler.
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+
+2019-07-07 13:19:19 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (77a7010c)
+
+ lib-sieve: plugins: enotify: Add sieve_enotify_event_log().
+
+
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+
+2019-07-19 21:18:49 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (b3fb5d5d)
+
+ lib-sieve: plugins: enotify: mailto: Use event API to handle the "mailto
+ URI" log prefix.
+
+
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+
+2019-07-19 21:18:08 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (399c1c53)
+
+ lib-sieve: plugins: enotify: Use event API to handle the notify
+ command/action log prefix.
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+
+2019-07-19 20:27:08 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (c562b1ff)
+
+ lib-sieve: plugins: enotify: mailto: uri-mailto - Restructure error
+ handling.
+
+ Avoid using a Sieve error handler directly.
+
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
+
+2019-07-03 21:58:39 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (6f744723)
+
+ lib-sieve: sieve-result - Handle action log prefix at a central location
+ using the event.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/sieve-result.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+
+2019-07-03 21:57:32 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (9a048328)
+
+ lib-sieve: sieve-error - Compose both the event and the error handler log
+ message once using the event API.
+
+
+M src/lib-sieve/sieve-error.c
+
+2019-07-03 17:06:44 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (8f6ccd14)
+
+ lib-sieve: sieve-error - Change error handler log function to accept direct
+ message string.
+
+ Before, it used format string and arguments.
+
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/testsuite/testsuite-log.c
+
+2019-07-03 13:32:01 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (9178d40f)
+
+ plugins: lda-sieve: Drop custom action error handler.
+
+
+M src/plugins/lda-sieve/Makefile.am
+D src/plugins/lda-sieve/lda-sieve-log.c
+D src/plugins/lda-sieve/lda-sieve-log.h
+
+2019-07-03 13:29:11 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (b0354cc1)
+
+ sieve-tools: sieve-test - Use the new result message amendment callback
+ rather than the prefix error handler.
+
+
+M src/sieve-tools/sieve-test.c
+
+2019-07-03 13:26:28 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (9712e4dd)
+
+ sieve-tools: sieve-filter - Use the new result message amendment callback
+ rather than the prefix error handler.
+
+
+M src/sieve-tools/sieve-filter.c
+
+2019-07-03 13:24:01 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (c209f9ab)
+
+ plugins: lda-sieve: Use the new result message amendment callback rather
+ than a special error handler.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2019-07-03 13:20:14 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (359188af)
+
+ lib-sieve: sieve-result - Add support for amending result log messages.
+
+
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-types.h
+
+2019-06-27 13:35:55 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (bff3aee2)
+
+ lib-sieve: sieve-result - Allow specifying an explicit name for actions
+ added to the result.
+
+ Before it always used the name of the action definition, which is confusing
+ e.g. for the keep and fileinto actions, which both map to the same "store"
+ action definition.
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/plugins/sieve-extprograms/cmd-pipe.c
+
+2019-06-28 21:15:14 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (1d85af11)
+
+ lib-sieve: sieve-result - Add sieve_result_event_log*().
+
+ This allows logging action messages through a different (child) event.
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2019-07-03 13:37:51 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (4cd9b2c2)
+
+ lib-sieve: sieve-error - Add sieve_event_log().
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+
+2019-07-03 13:08:54 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (14fcdf1f)
+
+ lib-sieve: sieve-error - Make enum sieve_error_flags public.
+
+
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.h
+
+2019-06-22 22:12:37 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (8dd08fcd)
+
+ lib-sieve: sieve-result - Define "sieve-action" event category.
+
+ Applies to Sieve actions being executed.
+
+M src/lib-sieve/sieve-result.c
+
+2019-06-22 09:38:13 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (c52d25ad)
+
+ lib-sieve: sieve-interpreter - Define "sieve-runtime" event category.
+
+ Applies to Sieve scripts being evaluated before the actual action execution.
+
+M src/lib-sieve/sieve-interpreter.c
+
+2019-06-22 09:27:15 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (b538ebba)
+
+ lib-sieve: sieve-execute - Define "sieve-execute" event category.
+
+ Applies to Sieve scripts being executed in general.
+
+M src/lib-sieve/sieve-execute.c
+
+2019-06-22 09:25:06 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (054c2e85)
+
+ lib-sieve: Define "sieve" event category.
+
+
+M src/lib-sieve/sieve.c
+
+2019-06-22 18:05:17 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (cddd93d2)
+
+ lib-sieve: sieve-result - Use action event for all action execution log
+ messages.
+
+
+M src/lib-sieve/sieve-result.c
+
+2019-06-22 18:03:13 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (8e4bf3f6)
+
+ lib-sieve: sieve-result - Add event support for individual actions.
+
+
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+
+2019-06-22 10:44:34 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (e937ff93)
+
+ lib-sieve: sieve-interpreter - Use runtime event for all runtime log
+ messages.
+
+
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/tst-size.c
+
+2019-06-22 10:43:51 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (d6e84096)
+
+ lib-sieve: sieve-error - Add support for logging through events other than
+ the main instance event.
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+
+2019-06-22 09:43:10 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (692f6ca4)
+
+ lib-sieve: sieve-result - Add event support to action execute environment.
+
+
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+
+2019-06-22 09:30:39 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (39b6eb9c)
+
+ lib-sieve: sieve-runtime - Add event support to runtime environment.
+
+
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-runtime.h
+
+2019-06-22 09:16:16 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (b539a50f)
+
+ lib-sieve: sieve-execute - Add event support to execute environment.
+
+
+M src/lib-sieve/sieve-execute.c
+M src/lib-sieve/sieve-execute.h
+
+2019-07-07 13:36:55 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (2f398324)
+
+ lib-sieve: Add username field to main instance event.
+
+
+M src/lib-sieve/sieve.c
+
+2019-06-22 11:40:49 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (318c6a61)
+
+ lib-sieve: sieve-actions - Remove action argument from action and
+ side-effect definition functions.
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+
+2019-06-22 11:15:51 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (62913ca7)
+
+ lib-sieve: sieve-actions - Add current action to action execution
+ environment.
+
+
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+
+2019-06-21 00:23:43 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (90ba06f3)
+
+ lib-sieve: Handle init/deinit of execute context in separate functions.
+
+ Always associate a pool with the execute context.
+
+M src/lib-sieve/Makefile.am
+A src/lib-sieve/sieve-execute.c
+M src/lib-sieve/sieve-execute.h
+M src/lib-sieve/sieve.c
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-script.c
+
+2019-06-22 18:01:20 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (ada6ab95)
+
+ lib-sieve: sieve-action - Add sieve_action_name() macro.
+
+
+M src/lib-sieve/sieve-actions.h
+
+2019-07-06 23:04:55 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (f77fb4c7)
+
+ lib-sieve: sieve-interpreter - Turn bools in struct sieve_interpreter into
+ bit fields.
+
+
+M src/lib-sieve/sieve-interpreter.c
+
+2019-06-22 09:46:32 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (1db9c46a)
+
+ lib-sieve: sieve-result - Make direct result pointer avalable as local
+ variable in sieve_result_unref().
+
+
+M src/lib-sieve/sieve-result.c
+
+2019-07-16 23:59:09 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (5a00d2ff)
+
+ lib-sieve: sieve-erorr - Add sieve_internal_error_params() and use it.
+
+ This allows passing error parameters struct from sieve_critical*().
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+
+2019-06-29 09:59:18 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (7a677e81)
+
+ lib-sieve: sieve-error - Compose message prefixes in a single place for all
+ error handler variants.
+
+
+M src/lib-sieve/sieve-error.c
+
+2019-06-28 21:07:05 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (e1d909c5)
+
+ lib-sieve: sieve-error - Remove varexpand error handler.
+
+ It is no longer used.
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+
+2019-07-03 21:23:34 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (688f8a2e)
+
+ testsuite: testsuite-log - Change error message structure to match rest of
+ Pigeonhole.
+
+
+M src/testsuite/testsuite-log.c
+
+2019-06-22 16:41:16 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (6b5cb2e5)
+
+ testsuite: testsuite-log - Uninstall testsuite error handler upon deinit.
+
+ This prevents segfaults e.g. when dovecot/lib wants to log errors at
+ lib_deinit().
+
+M src/testsuite/testsuite-log.c
+
+2019-07-17 12:33:09 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (382b1eac)
+
+ doveadm-sieve: Shared attribute iteration shouldn't list Sieve scripts
+
+ Trying to get them as shared instead of as private resulted in failure.
+
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+
+2019-07-09 22:39:35 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (c7c3e55a)
+
+ lib-sieve: plugins: vnd.dovecot: report: cmd-report - Fix resource leak
+ occurring when the SMTP submission fails.
+
+ Properly abort the SMTP transaction upon failure.
+
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+
+2019-07-09 22:38:14 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (65491e1b)
+
+ lib-sieve: plugins: vacation: cmd-vacation - Fix resource leak occurring
+ when the SMTP submission fails.
+
+ Properly abort the SMTP transaction upon failure.
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2019-07-09 22:36:15 +0200 Stephan Bosch <stephan.bosch@open-xchange.com> (2fda1f95)
+
+ lib-sieve: cmd-redirect - Fix resource leak occurring when the SMTP
+ submission fails.
+
+ Properly abort the SMTP transaction upon failure.
+
+M src/lib-sieve/cmd-redirect.c
+
+2019-06-17 23:26:25 +0300 Martti Rannanjärvi <martti.rannanjarvi@open-xchange.com> (b1198f7b)
+
+ lib-sieve: storage: file: sieve-file-storage-save - Fix error message to
+ include the intended path value rather than NULL.
+
+
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+
+2019-06-18 10:59:24 +0300 Martti Rannanjärvi <martti.rannanjarvi@open-xchange.com> (cf66d379)
+
+ lib-sieve: Expand SMTP_ADDRESS_LITERAL() macro
+
+ This makes the use of compound literal explicit.
+
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-message.c
+
+2019-06-18 10:56:11 +0300 Martti Rannanjärvi <martti.rannanjarvi@open-xchange.com> (68472b3c)
+
+ testsuite: Fix invalid compound literal use
+
+ The lifetime of compound literals changes in gcc 9, and the old one
+ segfaults there.
+
+M src/testsuite/testsuite-message.c
+
+2019-06-18 10:40:52 +0300 Martti Rannanjärvi <martti.rannanjarvi@open-xchange.com> (70834d27)
+
+ testsuite: Expand SMTP_ADDRESS_LITERAL() macro
+
+ This makes the use of compound literal explicit.
+
+M src/testsuite/testsuite-message.c
+
+2019-05-27 20:48:43 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (d30a8dee)
+
+ lib-sieve: Use common context for both script evaluation and action
+ execution.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+M src/lib-sieve/plugins/duplicate/tst-duplicate.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/ihave/tst-ihave.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/metadata/tst-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-items.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-common.h
+A src/lib-sieve/sieve-execute.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/tst-size.c
+M src/plugins/imapsieve/ext-imapsieve-environment.c
+M src/plugins/sieve-extprograms/cmd-execute.c
+M src/plugins/sieve-extprograms/cmd-filter.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite.c
+
+2019-05-27 22:45:15 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (3ca5c4ed)
+
+ testsuite: Reformat cmd-test-config.c.
+
+
+M src/testsuite/cmd-test-config.c
+
+2019-05-27 20:50:04 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (159e8e9e)
+
+ testsuite: Reformat testsuite-result.h.
+
+
+M src/testsuite/testsuite-result.h
+
+2019-05-27 20:45:49 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (2a3b0472)
+
+ testsuite: Reformat testsuite-result.c.
+
+
+M src/testsuite/testsuite-result.c
+
+2019-05-27 21:01:23 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (75a5b17f)
+
+ testsuite: Reformat testsuite-script.h.
+
+
+M src/testsuite/testsuite-script.h
+
+2019-05-27 20:33:51 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (b46bd650)
+
+ testsuite: Reformat testsuite-script.c.
+
+
+M src/testsuite/testsuite-script.c
+
+2019-05-27 20:23:36 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (e2700a46)
+
+ testsuite: Reformat testsuite.c.
+
+
+M src/testsuite/testsuite.c
+
+2019-05-28 21:49:40 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (02b7ad0c)
+
+ plugins: sieve-extprograms: Reformat cmd-pipe.c.
+
+
+M src/plugins/sieve-extprograms/cmd-pipe.c
+
+2019-05-28 21:33:38 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (49e2334c)
+
+ plugins: sieve-extprograms: Reformat cmd-filter.c.
+
+
+M src/plugins/sieve-extprograms/cmd-filter.c
+
+2019-05-28 21:14:46 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (a8bf5d38)
+
+ plugins: sieve-extprograms: Reformat cmd-execute.c.
+
+
+M src/plugins/sieve-extprograms/cmd-execute.c
+
+2019-05-28 20:43:04 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (647e7c67)
+
+ plugins: imapsieve: Reformat ext-imapsieve-environment.c.
+
+
+M src/plugins/imapsieve/ext-imapsieve-environment.c
+
+2019-05-30 01:03:01 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (9f696496)
+
+ lib-sieve: plugins: vnd.dovecot: report: Reformat cmd-report.c.
+
+
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+
+2019-05-30 00:31:18 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (588d8322)
+
+ lib-sieve: plugins: vnd.dovecot: environment: Reformat
+ ext-vnd-environment-items.c.
+
+
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-items.c
+
+2019-05-30 00:27:49 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (9692ec74)
+
+ lib-sieve: plugins: variables: Reformat ext-variables-common.h.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+
+2019-05-30 00:23:33 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (efc85b7c)
+
+ lib-sieve: plugins: variables: Reformat ext-variables-common.c.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+
+2019-05-30 00:00:07 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (22212e16)
+
+ lib-sieve: plugins: vacation: Reformat cmd-vacation.c.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2019-05-29 23:13:41 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (f339c68d)
+
+ lib-sieve: plugins: vacation: Reformat ext-vacation.c.
+
+
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+
+2019-05-29 02:04:44 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (afebb6bb)
+
+ lib-sieve: plugins: notify: Reformat cmd-notify.c.
+
+
+M src/lib-sieve/plugins/notify/cmd-notify.c
+
+2019-05-29 02:08:57 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (7fb079f3)
+
+ lib-sieve: plugins: notify: Reformat ext-notify-common.h.
+
+
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+
+2019-05-29 01:40:17 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (e1f0de5c)
+
+ lib-sieve: plugins: notify: Reformat ext-notify-common.c.
+
+
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+
+2019-05-29 01:29:24 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (4bb6061e)
+
+ lib-sieve: plugins: metadata: Reformat tst-metadataexists.c.
+
+
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+
+2019-05-29 01:14:51 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (4135e8f4)
+
+ lib-sieve: plugins: metadata: Reformat tst-metadata.c.
+
+
+M src/lib-sieve/plugins/metadata/tst-metadata.c
+
+2019-05-29 00:54:28 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (ca727928)
+
+ lib-sieve: plugins: mailbox: Reformat tst-mailboxexists.c.
+
+
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+
+2019-05-29 00:37:52 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (42ade3f1)
+
+ lib-sieve: plugins: mailbox: Reformat tag-mailbox-create.c.
+
+
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+
+2019-05-29 23:03:23 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (6f2ea423)
+
+ lib-sieve: plugins: include: Reformat ext-include-common.h.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.h
+
+2019-05-29 00:24:20 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (7f516a65)
+
+ lib-sieve: plugins: include: Reformat ext-include-common.c.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2019-05-28 23:55:49 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (ee7fef8e)
+
+ lib-sieve: plugins: ihave: Reformat tst-ihave.c.
+
+
+M src/lib-sieve/plugins/ihave/tst-ihave.c
+
+2019-05-29 22:57:26 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (dc00dd6a)
+
+ lib-sieve: plugins: environment: Reformat ext-environment-common.h.
+
+
+M src/lib-sieve/plugins/environment/ext-environment-common.h
+
+2019-05-28 23:44:48 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (8f68dd73)
+
+ lib-sieve: plugins: environment: Reformat ext-environment-common.c.
+
+
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+
+2019-05-28 23:33:04 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (633ba5fc)
+
+ lib-sieve: plugins: enotify: Reformat cmd-notify.c.
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+
+2019-05-29 22:54:29 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (e86147eb)
+
+ lib-sieve: plugins: enotify: Reformat ext-enotify-common.h.
+
+
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+
+2019-05-28 23:13:24 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (15f41903)
+
+ lib-sieve: plugins: enotify: Reformat ext-enotify-common.c.
+
+
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+
+2019-05-28 22:26:46 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (71604b93)
+
+ lib-sieve: plugins: duplicate: Reformat tst-duplicate.c.
+
+
+M src/lib-sieve/plugins/duplicate/tst-duplicate.c
+
+2019-05-29 02:10:24 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (441a41fb)
+
+ lib-sieve: plugins: duplicate: Reformat ext-duplicate-common.h.
+
+
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.h
+
+2019-05-28 22:06:34 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (b895fd46)
+
+ lib-sieve: plugins: duplicate: Reformat ext-duplicate-common.c.
+
+
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+
+2019-05-27 22:28:11 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (1884824f)
+
+ lib-sieve: Reformat tst-size.c.
+
+
+M src/lib-sieve/tst-size.c
+
+2019-05-27 22:16:48 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (dcb7aafa)
+
+ lib-sieve: Reformat ext-reject.c.
+
+
+M src/lib-sieve/ext-reject.c
+
+2019-05-27 21:58:48 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (3ff73e55)
+
+ lib-sieve: Reformat ext-envelope.c.
+
+
+M src/lib-sieve/ext-envelope.c
+
+2019-05-27 21:34:59 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (7ae7d35e)
+
+ lib-sieve: Reformat cmd-redirect.c.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2019-05-27 21:19:33 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (caf973d4)
+
+ lib-sieve: Reformat cmd-discard.c.
+
+
+M src/lib-sieve/cmd-discard.c
+
+2019-05-22 23:35:14 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (cd091d47)
+
+ lib-sieve: Reformat sieve-actions.c.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2019-05-22 22:55:46 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (eff1beea)
+
+ lib-sieve: Reformat sieve-actions.h.
+
+
+M src/lib-sieve/sieve-actions.h
+
+2019-05-27 09:43:25 +0300 Aki Tuomi <aki.tuomi@open-xchange.com> (0e91911d)
+
+ doveadm-sieve: Fix script synchronization
+
+ When dsyncing, this codepath is always called with prefix "". There is no
+ point checking the prefix at all.
+
+ Broken in 479c5e57046dec76078597df844daccbfc0eb75f
+
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+
+2019-05-16 10:44:12 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (cf4e2004)
+
+ doc: example-config: Remove recipient_delimiter
+
+ It defaults to the global recipient_delimiter, which should always be used
+ anyway. Don't add confusion by documenting the legacy setting that only
+ exists for backwards compatibility.
+
+M doc/example-config/conf.d/90-sieve.conf
+
+2019-05-09 13:38:15 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (83ff4c7f)
+
+ doc: draft-bosch-imap-filter-sieve-00.txt - update FILTERED replies and
+ editheader+keep
+
+
+M doc/rfc/draft-bosch-imap-filter-sieve-00.txt
+
+2019-05-15 13:25:44 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (a77eb7f0)
+
+ lib-sieve: sieve-error - Simplify if-statement for global logging
+ sieve_direct_logv().
+
+ Use local variables to pre-declare conditions that are used more than once.
+
+M src/lib-sieve/sieve-error.c
+
+2019-05-14 23:22:09 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (260d7bb5)
+
+ lib-sieve: sieve-error - Fix NULL value dereference in sieve_direct_logv().
+
+ Caused by recent event API changes.
+
+M src/lib-sieve/sieve-error.c
+
+2019-05-15 13:13:37 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (d26d5726)
+
+ lib-sieve: sieve-error - Restore condition that got erroneously removed in
+ sieve_direct_logv().
+
+
+M src/lib-sieve/sieve-error.c
+
+2019-05-15 13:10:55 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (6488fd4e)
+
+ lib-sieve: sieve-error - Merge nested if-statements in sieve_direct_logv().
+
+
+M src/lib-sieve/sieve-error.c
+
+2019-05-14 13:00:42 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (71a49a1f)
+
+ Fix compilation for GCC 4.
+
+ Caused by recent event API changes.
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-validator.c
+
+2019-05-09 20:39:31 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (436599b7)
+
+ lib-sieve: sieve_message_parts_add_missing() - Fix NULL checks to make
+ scan-build happy
+
+
+M src/lib-sieve/sieve-message.c
+
+2019-05-09 13:20:29 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (6aae4545)
+
+ plugins: imap-filter-sieve: Fix accessing uninitialized variable
+
+ It happened only when returning error, so the caller wouldn't have cared
+ about it anyway. This makes static analyzers happier though.
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2019-04-29 15:02:12 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (23f7375d)
+
+ plugins: imap-filter-sieve: Send FILTERED reply only if the filter did
+ changes
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+M src/plugins/imap-filter-sieve/imap-filter-sieve.h
+M src/plugins/imap-filter-sieve/imap-filter.c
+
+2019-05-02 16:01:42 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (ef6614a0)
+
+ plugins: imap-filter-sieve: Cleanup - write FILTERED reply to string first
+
+ Simplifies the next commit.
+
+M src/plugins/imap-filter-sieve/imap-filter.c
+
+2019-04-29 15:00:39 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (50dfe260)
+
+ plugins: imap-filter-sieve: Handle each mail in a separate data stack frame
+
+ Avoids growing memory usage excessively when filtering a lot of mails.
+
+M src/plugins/imap-filter-sieve/imap-filter.c
+
+2019-04-29 14:59:10 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (f3d98102)
+
+ plugins: imap-filter-sieve: Don't delete mails if script gets aborted
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2019-04-29 14:57:56 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (176c337e)
+
+ lib-sieve: Add sieve_exec_status.significant_action_executed
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-types.h
+
+2019-04-29 14:57:25 +0300 Timo Sirainen <timo.sirainen@open-xchange.com> (b7a7e767)
+
+ lib-sieve: Fix minor logic bug in handling duplicate keep actions
+
+ This didn't seem to result in any visible bugs though.
+
+M src/lib-sieve/sieve-result.c
+
+2019-03-11 00:07:20 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (37d93ef3)
+
+ lib-sieve: sieve-error - Change master logging to use event API.
+
+
+M src/lib-sieve/sieve-error.c
+
+2019-04-07 12:51:42 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (5e320859)
+
+ lib-sieve: Drop system error handler.
+
+
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-log.c
+
+2019-04-24 17:58:50 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (2da440e8)
+
+ lib-sieve: sieve-error - Always use master log for system/global log
+ messages.
+
+
+M src/lib-sieve/sieve-error.c
+
+2019-04-24 19:06:58 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (5f508971)
+
+ lib-sieve: sieve-error - Move logging to master log to a separate function.
+
+
+M src/lib-sieve/sieve-error.c
+
+2019-04-07 11:02:51 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (a21fe6e2)
+
+ lib-sieve: sieve-error - Add flag that marks whether error handler logs to
+ master log.
+
+ This is needed to avoid duplicating log lines there when the system log
+ handler is removed from the Sieve context.
+
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+
+2019-04-07 10:51:32 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (c37c6e9c)
+
+ lib-sieve: sieve-error - Reorder struct definitions.
+
+
+M src/lib-sieve/sieve-error-private.h
+
+2019-03-11 00:19:09 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (2bb479d4)
+
+ lib-sieve: sieve-error - Remove prefix support from master error handler.
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-activate.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-put.c
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2019-04-23 20:32:25 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (a2744819)
+
+ lib-sieve: sieve-error - Make c-source filename and line number available to
+ error handlers.
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+
+2019-04-24 18:31:09 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (052097be)
+
+ lib-sieve: sieve-error - Rename sieve_vcritical() to sieve_criticalv().
+
+ This way, it matches the new sieve_logv().
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-result.c
+
+2019-04-23 19:47:48 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (516333d3)
+
+ lib-sieve: sieve-error - Add log_type to struct sieve_error_params.
+
+ This reduces the number of log functions for the error handler from four to
+ just one.
+
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-validator.c
+M src/plugins/lda-sieve/lda-sieve-log.c
+M src/testsuite/testsuite-log.c
+
+2019-04-24 14:38:55 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (f055883a)
+
+ lib-sieve: sieve-error - Move location log parameter to a generic parameters
+ struct.
+
+
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-validator.c
+M src/plugins/lda-sieve/lda-sieve-log.c
+M src/testsuite/testsuite-log.c
+
+2019-03-10 23:58:10 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (f73ce51d)
+
+ lib-sieve: Drop sieve_sys_* log functions.
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+
+2019-04-09 19:48:39 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (162ce2cb)
+
+ lib-sieve: sieve-script - Drop sieve_script_sys_*() log functions.
+
+
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+
+2019-04-09 19:27:03 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (fa020da2)
+
+ lib-sieve: sieve-storage - Drop sieve_storage_sys_*() log functions.
+
+
+M src/lib-sieve/sieve-storage-private.h
+M src/lib-sieve/sieve-storage.c
+
+2019-03-10 21:53:31 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (7507ddc6)
+
+ plugins: imap-filter-sieve: imap-filter-sieve - Replace sieve_sys_*() with
+ e_*().
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2019-03-10 21:38:25 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (d1b6776e)
+
+ plugins: imapsieve: imap-sieve - Replace sieve_sys_*() with e_*().
+
+
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/imapsieve/sieve-imapsieve-plugin.c
+
+2019-03-10 21:18:57 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (94d131e4)
+
+ plugins: lda-sieve: lda-sieve-plugin - Replace sieve_sys_*() with e_*().
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2019-04-09 19:47:57 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (61a9770a)
+
+ lib-sieve: Replace sieve_script_sys_debug() with e_debug().
+
+
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/storage/dict/sieve-dict-script.c
+M src/lib-sieve/storage/file/sieve-file-script.c
+M src/lib-sieve/storage/ldap/sieve-ldap-script.c
+
+2019-04-09 19:46:28 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (f114f313)
+
+ lib-sieve: Replace sieve_script_sys_error() with e_error().
+
+
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/storage/dict/sieve-dict-script.c
+M src/lib-sieve/storage/file/sieve-file-script.c
+M src/lib-sieve/storage/ldap/sieve-ldap-script.c
+
+2019-04-09 19:26:14 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (dbdfb777)
+
+ lib-sieve: Replace sieve_storage_sys_debug() with e_debug().
+
+
+M src/lib-sieve/sieve-storage-sync.c
+M src/lib-sieve/sieve-storage.c
+M src/lib-sieve/storage/dict/sieve-dict-storage.c
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.c
+
+2019-04-09 19:25:19 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (168eca74)
+
+ lib-sieve: Replace sieve_storage_sys_info() with e_info().
+
+
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+
+2019-04-09 19:24:02 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (586d4629)
+
+ lib-sieve: Replace sieve_storage_sys_warning() with e_warning().
+
+
+M src/lib-sieve/sieve-storage-sync.c
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+M src/lib-sieve/storage/file/sieve-file-storage-quota.c
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+
+2019-04-09 19:21:44 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (17b4a1f5)
+
+ lib-sieve: Replace sieve_storage_sys_error() with e_error().
+
+
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-storage.c
+M src/lib-sieve/storage/file/sieve-file-script-sequence.c
+M src/lib-sieve/storage/file/sieve-file-storage-list.c
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage-settings.c
+
+2019-04-09 18:37:07 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (ae6a3742)
+
+ lib-sieve: Replace sieve_sys_debug() with e_debug().
+
+
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-storage.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.c
+
+2019-04-09 18:36:40 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (62998517)
+
+ lib-sieve: Replace sieve_sys_info() with e_info().
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-storage.c
+
+2019-04-09 18:34:51 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (6a024d83)
+
+ lib-sieve: Replace sieve_sys_warning() with e_warning().
+
+
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/sieve-address-source.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-storage.c
+
+2019-04-09 18:31:50 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (fcaffaff)
+
+ lib-sieve: Replace sieve_sys_error() with e_error().
+
+
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-storage.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/tst-size.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-message.c
+
+2019-05-01 00:16:44 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (8ba34ff6)
+
+ lib-sieve: sieve-binary - Replace sieve_sys_error() with e_error().
+
+
+M src/lib-sieve/sieve-binary-file.c
+
+2019-04-30 23:43:12 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (0a812d89)
+
+ lib-sieve: sieve-binary - Replace sieve_sys_debug() with e_debug().
+
+
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary.c
+
+2019-04-30 23:22:56 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (01329495)
+
+ lib-sieve: sieve-binary - Add support for event API.
+
+
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.c
+
+2019-04-09 19:44:21 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (6f26baaa)
+
+ lib-sieve: sieve-script - Add support for event API.
+
+
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+
+2019-04-09 19:13:04 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (a4376980)
+
+ lib-sieve: sieve-storage - Add support for event API.
+
+
+M src/lib-sieve/sieve-storage-private.h
+M src/lib-sieve/sieve-storage.c
+M src/lib-sieve/storage/data/sieve-data-script.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+
+2019-03-10 15:57:26 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (2b5aa172)
+
+ lib-sieve: sieve - Add sieve_get_event().
+
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+
+2019-02-17 15:56:18 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (c09e6095)
+
+ lib-sieve: Add support for event API.
+
+
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+
+2019-03-10 23:05:59 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (d5b8eee6)
+
+ testsuite: testsuite-log - Handle log messages generated outside a sieve
+ error handler.
+
+
+M src/testsuite/testsuite-log.c
+
+2019-05-03 02:11:03 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (9f86c469)
+
+ lib-sieve: sieve-binary-file - Use binary rather than Sieve instance in
+ struct sieve_binary_file.
+
+
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+
+2019-05-03 02:30:19 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (1513486b)
+
+ lib-sieve: sieve-binary-file - Refactor sieve_binary_file_close().
+
+
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+
+2019-05-03 01:51:36 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (5dcb88e8)
+
+ lib-sieve: sieve-binary-file - Make sieve_binary_file_open() static.
+
+
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+
+2019-05-01 09:40:03 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (6d4720e7)
+
+ lib-sieve: Reformat sieve-binary-dumper.c.
+
+
+M src/lib-sieve/sieve-binary-dumper.c
+
+2019-05-01 09:31:28 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (2a006148)
+
+ lib-sieve: Reformat sieve-binary-debug.c.
+
+
+M src/lib-sieve/sieve-binary-debug.c
+
+2019-05-01 09:23:14 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (887eb103)
+
+ lib-sieve: Reformat sieve-binary-code.c.
+
+
+M src/lib-sieve/sieve-binary-code.c
+
+2019-05-01 01:25:03 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (8efd7cb7)
+
+ lib-sieve: Reformat sieve-binary-file.c.
+
+
+M src/lib-sieve/sieve-binary-file.c
+
+2019-05-01 00:53:25 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (c816308f)
+
+ lib-sieve: Reformat sieve-binary-private.h.
+
+
+M src/lib-sieve/sieve-binary-private.h
+
+2019-05-01 00:44:05 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (717a7ea5)
+
+ lib-sieve: Reformat sieve-binary.h.
+
+
+M src/lib-sieve/sieve-binary.h
+
+2019-05-01 00:34:45 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (7448d1dc)
+
+ lib-sieve: Reformat sieve-binary.c.
+
+
+M src/lib-sieve/sieve-binary.c
+
+2019-04-30 14:26:16 +0300 Aki Tuomi <aki.tuomi@open-xchange.com> (9dab95d8)
+
+ NEWS: Add news for v0.5.6
+
+
+M NEWS
+
+2019-04-24 08:57:05 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (9c6b1051)
+
+ lib-sieve: sieve-parser - Remove unnecessary forward declaration of error
+ handling functions.
+
+
+M src/lib-sieve/sieve-parser.c
+
+2019-04-24 08:55:04 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (069d5af9)
+
+ lib-sieve: sieve-lexer - Remove unnecessary forward declaration of error
+ handling functions.
+
+
+M src/lib-sieve/sieve-lexer.c
+
+2019-04-24 09:12:16 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (aaca4777)
+
+ lib-sieve: sieve-validator - Remove spurious declaration of
+ sieve_validator_critical().
+
+
+M src/lib-sieve/sieve-validator.h
+
+2019-04-24 09:08:02 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (4019a724)
+
+ lib-sieve: sieve-validator - Reorder error handling functions.
+
+
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+
+2019-04-24 08:48:42 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (7fc3b2cb)
+
+ lib-sieve: sieve-generator - Reorder error handling functions.
+
+
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+
+2019-04-19 00:02:47 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (c69def7c)
+
+ lib-sieve: sieve-error - Move sieve_internal_error().
+
+
+M src/lib-sieve/sieve-error.c
+
+2019-04-18 23:26:31 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (eb6aac65)
+
+ lib-sieve: sieve-validator - Move error handling to the end of the file.
+
+
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+
+2019-04-18 22:21:18 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (16fb21b1)
+
+ lib-sieve: sieve-generator - Move error handling to the end of the file.
+
+
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+
+2019-04-18 21:45:17 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (a894b255)
+
+ lib-sieve: sieve-interpreter - Move error handling to the end of the file.
+
+
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+
+2019-03-10 15:41:34 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (6a82c9b4)
+
+ lib-sieve: sieve-binary-file - Remove unused code.
+
+
+M src/lib-sieve/sieve-binary-file.c
+
+2019-04-19 01:08:27 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (79090306)
+
+ lib-sieve: sieve-result - Move error handling to the end of the file.
+
+
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2019-04-24 23:32:04 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (b1cd6b68)
+
+ plugins: imap-filter-sieve: Reformat imap-filter-sieve.c.
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2019-04-24 23:18:38 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (9bf576f4)
+
+ plugins: imapsieve: Reformat imap-sieve.h.
+
+
+M src/plugins/imapsieve/imap-sieve.h
+
+2019-04-24 23:15:33 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (696d562e)
+
+ plugins: imapsieve: Reformat imap-sieve.c.
+
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2019-04-24 21:33:22 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (8e528bc2)
+
+ plugins: lda-sieve: Reformat lda-sieve-plugin.c.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2019-04-24 18:38:42 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (d3a0bda4)
+
+ plugins: lda-sieve: Reformat lda-sieve-log.h.
+
+
+M src/plugins/lda-sieve/lda-sieve-log.h
+
+2019-04-24 18:37:48 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (3fcf493e)
+
+ plugins: lda-sieve: Reformat lda-sieve-log.c.
+
+
+M src/plugins/lda-sieve/lda-sieve-log.c
+
+2019-04-24 18:19:33 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (f32d00e2)
+
+ testsuite: Reformat testsuite-log.h.
+
+
+M src/testsuite/testsuite-log.h
+
+2019-04-24 18:18:14 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (eb521641)
+
+ testsuite: Reformat testsuite-log.c.
+
+
+M src/testsuite/testsuite-log.c
+
+2019-04-24 16:50:03 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (b79f8fb4)
+
+ lib-sieve: Reformat sieve-parser.h.
+
+
+M src/lib-sieve/sieve-parser.h
+
+2019-04-24 16:47:20 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (25ed1cdc)
+
+ lib-sieve: Reformat sieve-parser.c.
+
+
+M src/lib-sieve/sieve-parser.c
+
+2019-04-24 16:22:46 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (7f643de2)
+
+ lib-sieve: Reformat sieve-lexer.h.
+
+
+M src/lib-sieve/sieve-lexer.h
+
+2019-04-24 16:17:16 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (924bb302)
+
+ lib-sieve: Reformat sieve-lexer.c.
+
+
+M src/lib-sieve/sieve-lexer.c
+
+2019-04-19 01:03:47 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (36c6424a)
+
+ lib-sieve: Reformat sieve-result.h.
+
+
+M src/lib-sieve/sieve-result.h
+
+2019-04-19 00:57:27 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (00aac7d7)
+
+ lib-sieve: Reformat sieve-result.c.
+
+
+M src/lib-sieve/sieve-result.c
+
+2019-04-18 23:23:51 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (160d8f6d)
+
+ lib-sieve: Reformat sieve-validator.h.
+
+
+M src/lib-sieve/sieve-validator.h
+
+2019-04-18 23:14:19 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (2c40f4df)
+
+ lib-sieve: Reformat sieve-validator.c.
+
+
+M src/lib-sieve/sieve-validator.c
+
+2019-04-18 22:18:02 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (e24fa365)
+
+ lib-sieve: Reformat sieve-generator.h.
+
+
+M src/lib-sieve/sieve-generator.h
+
+2019-04-18 22:11:08 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (0014106f)
+
+ lib-sieve: Reformat sieve-generator.c.
+
+
+M src/lib-sieve/sieve-generator.c
+
+2019-04-18 21:42:13 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (088814fe)
+
+ lib-sieve: Reformat sieve-interpreter.h.
+
+
+M src/lib-sieve/sieve-interpreter.h
+
+2019-04-18 21:32:04 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (37c40ce1)
+
+ lib-sieve: Reformat sieve-interpreter.c.
+
+
+M src/lib-sieve/sieve-interpreter.c
+
+2019-04-18 23:49:40 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (fa530f84)
+
+ lib-sieve: Reformat sieve-error-private.h.
+
+
+M src/lib-sieve/sieve-error-private.h
+
+2019-04-10 21:12:33 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (89a0b67f)
+
+ lib-sieve: Reformat sieve-error.h.
+
+
+M src/lib-sieve/sieve-error.h
+
+2019-04-10 21:55:25 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (b95ae584)
+
+ lib-sieve: Reformat sieve-error.c.
+
+
+M src/lib-sieve/sieve-error.c
+
+2019-04-10 20:40:57 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (12514b42)
+
+ lib-sieve: Reformat sieve-script-private.h.
+
+
+M src/lib-sieve/sieve-script-private.h
+
+2019-04-10 20:37:13 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (6ab4da37)
+
+ lib-sieve: Reformat sieve-script.c.
+
+
+M src/lib-sieve/sieve-script.c
+
+2019-04-10 20:16:59 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (fa418a65)
+
+ lib-sieve: Reformat sieve-script.h.
+
+
+M src/lib-sieve/sieve-script.h
+
+2019-04-10 10:06:37 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (8a011cbb)
+
+ lib-sieve: Reformat sieve-storage-private.h.
+
+
+M src/lib-sieve/sieve-storage-private.h
+
+2019-04-10 09:42:24 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (4c7d8a4e)
+
+ lib-sieve: Reformat sieve-storage.c.
+
+
+M src/lib-sieve/sieve-storage.c
+
+2019-04-10 08:57:59 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (34ee26e0)
+
+ lib-sieve: Reformat sieve-storage.h.
+
+
+M src/lib-sieve/sieve-storage.h
+
+2019-03-10 16:40:03 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (8dc19b49)
+
+ lib-sieve: Reformat sieve.c.
+
+
+M src/lib-sieve/sieve.c
+
+2019-03-10 16:39:17 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (7ee00844)
+
+ lib-sieve: Reformat sieve.h.
+
+
+M src/lib-sieve/sieve.h
+
+2019-04-26 09:37:51 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (19969c5f)
+
+ lib-sieve: sieve-storage: Fix memory leak occurring in
+ sieve_storage_check_script_direct().
+
+
+M src/lib-sieve/sieve-storage.c
+
+2019-04-25 23:04:23 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (ab0fcec5)
+
+ plugins: imap-filter-sieve: imap-filter-sieve - Fix memory leak of global
+ script storage.
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2019-04-07 19:38:07 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (73ce81a2)
+
+ plugins: doveadm-sieve: doveadm-sieve-cmd-put - Fix script memory leak
+ occurring when saved script is also activated.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-put.c
+
+2019-04-26 11:33:38 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (078ff7fb)
+
+ lib-sieve: sieve-script - Fix script memory leak occurring when renamed
+ script is also activated.
+
+
+M src/lib-sieve/sieve-script.c
+
+2019-04-07 18:52:51 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (2fbd34a5)
+
+ lib-sieve: sieve-storage - Fix script memory leak occurring when saved
+ script is implicitly activated.
+
+
+M src/lib-sieve/sieve-storage.c
+
+2019-03-04 19:59:08 +0200 Aki Tuomi <aki.tuomi@open-xchange.com> (64f480ae)
+
+ NEWS: Update master news file
+
+ Add NEWS from releases to master branch too
+
+M NEWS
+
+2019-01-24 22:46:09 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (77cc9328)
+
+ lib-sieve: Prevent execution of implicit keep upon temporary failure
+ occurring at runtime.
+
+
+M src/lib-sieve/sieve.c
+
+2019-02-13 23:26:09 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (54febd73)
+
+ Adjust to changes in Dovecot SMTP submit API.
+
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2019-01-16 08:51:09 -0500 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> (65a6af4b)
+
+ global: hash_table_destroy(NULL) is a no-op
+
+ @@ expression E;
+ @@
+
+ - if (hash_table_is_created(E)) {
+ - hash_table_destroy(&E);
+ - }
+ + hash_table_destroy(&E);
+
+M src/lib-sieve/sieve-result.c
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2018-12-12 18:46:50 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (43f5835b)
+
+ lib-sieve: redirect action: Assert that dupeid is not NULL when
+ act_redirect_get_duplicate_id() is successful.
+
+ Addresses scan-build report.
+
+M src/lib-sieve/cmd-redirect.c
+
+2018-12-12 18:45:00 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (114fe5f6)
+
+ lib-sieve: redirect action: Fix lack of NULL checking in new
+ X-Sieve-Redirected-From header comparisons.
+
+ Problem found by scan-build.
+
+M src/lib-sieve/cmd-redirect.c
+
+2018-12-11 10:43:37 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (5b813421)
+
+ plugins: imapsieve: Remove useless NULL check for exec_status.
+
+ In this context, it can never be NULL and the check confuses Coverity.
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2018-12-11 10:41:51 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (993bb23b)
+
+ plugins: imap-filter-sieve: Remove useless NULL check for exec_status.
+
+ In this context, it can never be NULL and the check confuses Coverity.
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2018-12-11 17:29:18 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (78f5952c)
+
+ lib-sieve: redirect action: Implement additional protection against mail
+ loops.
+
+ Also check the X-Sieve-Redirected-From header for our own e-mail addresses.
+ This header is added by the redirect action itself and in a mail loop it
+ would see that same header with that same content. This is less reliable
+ than the other mail loop detection (sender may set such a header), so,
+ unlike the existing loop detection based on the duplicate db, the implicit
+ keep is not canceled when the new loop detection is triggered.
+
+M src/lib-sieve/cmd-redirect.c
+M tests/execute/smtp.svtest
+
+2018-12-11 17:27:20 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (c42bbea8)
+
+ lib-sieve: redirect action: Put msgdata->mail in local variable in
+ act_redirect_get_duplicate_id().
+
+ Serves as an abbreviation.
+
+M src/lib-sieve/cmd-redirect.c
+
+2018-12-11 17:26:56 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (f0639f18)
+
+ lib-sieve: redirect action: Move composition of duplicate database ID to
+ separate function.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2018-12-11 20:28:51 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (4cf91044)
+
+ lib-sieve: redirect action: Give log messages emitted during execution a
+ uniform prefix.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2018-12-11 17:25:12 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (51d87ff8)
+
+ lib-sieve: redirect action: Report errors on original message in
+ act_redirect_commit().
+
+ It was errorneously using the (potentially) modified mail struct for error
+ reporting.
+
+M src/lib-sieve/cmd-redirect.c
+
+2018-12-11 17:24:38 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (8a8f9c1e)
+
+ lib-sieve: redirect action: Update coding style of act_redirect_commit().
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2018-12-11 20:25:12 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (b8f5acd7)
+
+ lib-sieve: redirect action: Update coding style of act_redirect_send().
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2018-12-11 17:23:06 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (607a95e8)
+
+ lib-sieve: editheader extension: Protect the X-Sieve-Redirected-From header
+ against modification.
+
+ This prevents users from messing with redirect loop detection.
+
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+
+2018-12-11 12:53:13 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (7b862820)
+
+ plugins: sieve-extprograms: Use sieve_ prefix consistently for sieve
+ elements visible as exported symbols.
+
+ This fixes a symbol clash with the imap-filter-sieve plugin. Both modules
+ had the symbol "cmd_filter".
+
+M src/plugins/sieve-extprograms/cmd-execute.c
+M src/plugins/sieve-extprograms/cmd-filter.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+M src/plugins/sieve-extprograms/ext-execute.c
+M src/plugins/sieve-extprograms/ext-filter.c
+M src/plugins/sieve-extprograms/ext-pipe.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.h
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.c
+
+2018-12-05 10:57:37 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (fa6bec03)
+
+ plugins: imapsieve: Expunge discarded messages when
+ imapsieve_expunge_discarded=yes.
+
+
+M doc/plugins/imapsieve.txt
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2018-12-05 10:08:18 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (9ac4e5b7)
+
+ plugins: imap-filter-sieve: Properly discard the originally stored message
+ when a modified version is stored by Sieve.
+
+ The Sieve interpreter can return a flag that indicates whether the original
+ message should be kept, but that was not actually being used.
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2018-12-04 23:45:01 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (5513cea1)
+
+ plugins: imapsieve: Properly discard the originally stored message when a
+ modified version is stored by Sieve.
+
+ The Sieve interpreter can return a flag that indicates whether the original
+ message should be kept, but that was not actually being used.
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2018-12-04 15:45:01 +0200 sergey <sergey@dom.org> (1d23ca49)
+
+ lib-sieve: Create empty mail_keywords structure for keywords updating when
+ there are no keywords
+
+
+M src/lib-sieve/sieve-actions.c
+
+2018-11-26 09:44:49 +0200 Aki Tuomi <aki.tuomi@dovecot.fi> (8f7d3958)
+
+ configure: Stop using DOVECOT_CFLAGS and LDFLAGS
+
+ Instead use the detected ones.
+
+M configure.ac
+
+2018-11-26 09:44:40 +0200 Aki Tuomi <aki.tuomi@dovecot.fi> (a0a8f36a)
+
+ m4: Update dovecot.m4 from upstream
+
+
+M m4/dovecot.m4
+
+2018-09-26 02:40:36 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (65909cfa)
+
+ Don't try to send stats from Sieve command line tools (which includes
+ testsuite).
+
+
+M src/lib-sieve-tool/sieve-tool.c
+
+2018-09-26 02:27:27 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (4c24c5bb)
+
+ global: Don't try to send stats from unit tests.
+
+
+M src/lib-sieve/util/test-edit-mail.c
+
+2018-09-05 21:27:58 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (8b9cf579)
+
+ lib-sieve: Adjust to changes in Dovecot regarding the postmaster_address
+ setting.
+
+
+M src/lib-sieve/sieve.c
+
+2018-09-06 19:53:33 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (a931fc35)
+
+ managesieve: Don't enable stats when dumping capability
+
+ Otherwise stats process startup can get into a loop.
+
+M src/managesieve/main.c
+
+2018-08-30 02:44:26 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (97cfb22e)
+
+ plugins: imap-filter-sieve: Add assertion on attempting to execute at least
+ one script.
+
+ Coverity complains about last_script possibly being empty in
+ imap_sieve_filter_run_scripts(), which is actually not possible, since the
+ function would not be called if there is no script to execute. Added
+ assertion to make that clear.
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2018-08-30 02:39:25 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (3dce3817)
+
+ plugins: imap-filter-sieve: Fix segfault occurring in recently added debug
+ message.
+
+ The debug message pertains to skipping secondary scripts that failed to
+ compile. This debug message will not actually be triggered in the current
+ implementation, but this will become problematic in the future.
+
+ Problem found by Coverity.
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2018-08-26 17:26:05 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (41b9adcb)
+
+ plugins: imap-filter-sieve: Fix assertion panic occurring after script
+ compile error.
+
+ Compile errors occurring for Sieve scripts uploaded in multiple TCP frames
+ were not handled correctly.
+
+M src/plugins/imap-filter-sieve/cmd-filter-sieve.c
+
+2018-08-26 16:51:29 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (c7a83a3d)
+
+ plugins: imap-filter-sieve: Ignore secondary scripts that failed to compile.
+
+ The IMAP FILTER=SIEVE capability does not execute more than a single script
+ yet, but once it does, it should not assert fail on secondary scripts that
+ failed to compile.
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2018-08-15 16:09:41 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (7877454e)
+
+ lib-sieve: util: Add tests for rfc2822_header_write().
+
+
+M src/lib-sieve/util/Makefile.am
+A src/lib-sieve/util/test-rfc2822.c
+
+2018-08-15 15:41:36 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (5c8583f8)
+
+ lib-sieve: util: rfc2822: Prevent writing header lines with trailing
+ whitespace in rfc2822_header_append().
+
+
+M src/lib-sieve/util/rfc2822.c
+
+2018-08-15 15:35:17 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (41107911)
+
+ lib-sieve: util: rfc2822: Fix assert panic occurring in
+ rfc2822_header_append().
+
+ Panic was: "Buffer write out of range"
+
+ With some rather weird (sender-provided!) input, the header folding
+ algorithm got confused, causing a pointer to the start of the current line
+ to exceed the parsing pointer. This caused str_append_data() to be called
+ with a negative size. Added an assertion to make any future similar problems
+ more obvious.
+
+M src/lib-sieve/util/rfc2822.c
+
+2018-08-10 11:46:00 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (c7bd7456)
+
+ plugins: imap-filter-sieve: Fix FILTER SIEVE SCRIPT command parsing.
+
+ After finishing reading the Sieve script, the command parsing sometimes
+ didn't continue with the search arguments. This is a time-critical bug that
+ likely only occurs when the Sieve script is sent in the next TCP frame.
+
+M src/plugins/imap-filter-sieve/cmd-filter-sieve.c
+
+2018-08-09 13:04:27 +0300 Aki Tuomi <aki.tuomi@dovecot.fi> (99af69d5)
+
+ lib-sieve: Return test suite result in test-edit-mail
+
+
+M src/lib-sieve/util/test-edit-mail.c
+
+2018-08-05 13:54:06 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (e51a625a)
+
+ plugins: imapsieve: Fix assert panic occurring when a COPY event is
+ triggered on a virtual mailbox.
+
+ Occurs when several mails from different backend mailboxes are involved in
+ the COPY event. Fixed by using mail_save_context->>copy_src_mail in
+ mailbox_copy() instead of the mail argument. The latter can point to the
+ backend mailbox for virtual mailboxes, which makes no sense to the imapsieve
+ plugin as it expects only one source mailbox.
+
+ Panic was:
+
+ Panic: file imap-sieve-storage.c: line 337
+ (imap_sieve_add_mailbox_copy_event): assertion failed: (ismt->src_box ==
+ NULL || ismt->src_box == src_mail->box)
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2018-07-07 17:51:42 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (5c77bc11)
+
+ lib-sieve: vacation extension: Make construction of default message subject
+ configurable.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M tests/extensions/vacation/message.svtest
+
+2018-07-07 17:01:17 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (081eac2b)
+
+ lib-sieve: vacation extension: Move construction of default subject to
+ separate function.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2018-07-18 17:54:51 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (98e9ee54)
+
+ Adjust to changes in Dovecot message_address_parse() API.
+
+ Change was:
+
+ lib-mail: message_address_parse() - Change fill_missing parameter to flags
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-address.c
+M src/testsuite/testsuite-message.c
+
+2018-07-01 20:52:47 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (870855ed)
+
+ doc: Add documentation and specification for the IMAP FILTER=SIEVE plugin to
+ distribution.
+
+
+M doc/plugins/Makefile.am
+M doc/rfc/Makefile.am
+
+2018-06-28 20:03:11 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (97b8287e)
+
+ test suite: enotify extension: Add tests for interaction between
+ ":encodeurl" and variable size limits.
+
+
+M tests/extensions/enotify/encodeurl.svtest
+
+2018-06-28 00:29:15 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (ffa42e6e)
+
+ test suite: variables extension: Add tests for variable size limits.
+
+
+A tests/extensions/variables/limits.svtest
+
+2018-06-27 09:39:49 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (16ac8900)
+
+ lib-sieve: enotify extension: Improve handling of variable size limit for
+ ":encodeurl" variable modifier.
+
+
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+
+2018-06-27 09:38:45 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (734292d4)
+
+ lib-sieve: variables extension: Improve handling of variable size limit for
+ ":quotewildcard" modifier.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+
+2018-06-27 09:37:47 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (61baadef)
+
+ lib-sieve: variables extension: Add pointer to variables extension to
+ modifier instance.
+
+
+M src/lib-sieve/plugins/mime/cmd-extracttext.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2018-06-27 09:33:52 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (3ffb5a4d)
+
+ lib-sieve: variables extension: Pass modifier to modifier's modify method.
+
+
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2018-06-27 09:26:31 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (2998ab7e)
+
+ lib-sieve: variables extension: Add sieve_variables_get_max_variable_size()
+ to public API.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2018-06-01 00:30:06 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (daf4a721)
+
+ lib-sieve: variables extension: Respect UTF-8 character sequence boundaries
+ when truncating variables.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+
+2018-06-27 09:44:08 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (92caa9e2)
+
+ lib-sieve: enotify extension: Make modify method of ":encodeurl" variable
+ modifier static.
+
+
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+
+2018-06-28 20:02:04 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (b54bd368)
+
+ lib-sieve: variables extension: Make modify methods of pre-defined modifiers
+ static.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+
+2018-06-13 00:49:54 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (97dc5366)
+
+ managesieve: Free sieve instance when performing dump-capability
+
+ Makes it easier to run with valgrind.
+
+M src/managesieve/main.c
+M src/managesieve/managesieve-capabilities.c
+
+2018-06-12 18:52:03 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (5d2c3130)
+
+ doveadm sieve plugin: Fix memory leak for "sieve get" command
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-get.c
+
+2018-06-01 10:08:36 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (eceb19e7)
+
+ plugins: imap_filter_sieve: Put more effort in reconstructing a valid rcpt
+ address for the envelope.
+
+ The sieve_user_email setting provides a fallback for when there is no
+ Delivered-To header.
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve.c
+
+2018-05-28 14:12:49 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (678a14d7)
+
+ lib-sieve: script storage: Fix leaking mailbox if opening INBOX fails
+
+
+M src/lib-sieve/sieve-storage-sync.c
+
+2018-05-27 10:40:42 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (69cfb80b)
+
+ plugins: imap_filter_sieve: Implement the UID FILTER command.
+
+ Although it was documented and implemented in essence, it was not actually
+ available.
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.c
+
+2018-05-26 18:11:19 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (6535eab7)
+
+ doc: imap_filter_sieve plugin specification: Updated Dovecot Oy office
+ address.
+
+
+M doc/rfc/draft-bosch-imap-filter-sieve-00.txt
+
+2018-05-26 16:39:00 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (30c40f7e)
+
+ imap-filter-sieve: Fix FILTER to work correctly with pipelining
+
+ Fixes e.g. FILTER+LOGOUT pipelining crash: Panic: file imap-sync.c: line 832
+ (cmd_sync_delayed_real): assertion failed: (client->mailbox != NULL)
+
+M src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.c
+
+2018-05-12 00:56:19 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (ddab597c)
+
+ tests: address test: Add tests for invalid addresses with UTF-8 in the
+ localpart.
+
+
+M tests/test-address.svtest
+
+2018-05-11 23:44:37 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (cdb1a656)
+
+ lib-sieve: Add more trace debugging output for address list iteration.
+
+
+M src/lib-sieve/sieve-address.c
+
+2018-05-11 23:57:26 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (b58515a7)
+
+ lib-sieve: Check iterated addresses in address list for validity as an SMTP
+ address.
+
+
+M src/lib-sieve/sieve-address.c
+
+2018-05-12 00:08:19 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (9755beaf)
+
+ lib-sieve: Try to skip individual invalid addresses while iterating an
+ address list.
+
+ Before, the whole address list (header value) was returned as an invalid
+ address, ignoring any valid addresses it may still have contained.
+
+M src/lib-sieve/sieve-address.c
+
+2018-05-02 23:48:30 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (6fe1b102)
+
+ plugins: Implement the vendor-defined IMAP FILTER=SIEVE capability.
+
+ It adds the ability to manually invoke Sieve filtering in IMAP.
+
+M INSTALL
+M TODO
+M configure.ac
+A doc/plugins/imap_filter_sieve.txt
+A doc/rfc/draft-bosch-imap-filter-sieve-00.txt
+M src/plugins/Makefile.am
+A src/plugins/imap-filter-sieve/Makefile.am
+A src/plugins/imap-filter-sieve/cmd-filter-sieve.c
+A src/plugins/imap-filter-sieve/cmd-filter.c
+A src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.c
+A src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.h
+A src/plugins/imap-filter-sieve/imap-filter-sieve.c
+A src/plugins/imap-filter-sieve/imap-filter-sieve.h
+A src/plugins/imap-filter-sieve/imap-filter.c
+A src/plugins/imap-filter-sieve/imap-filter.h
+
+2018-05-07 11:04:09 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (a15235f0)
+
+ plugins: imapsieve: Make sure responses are never sent.
+
+ Use the new SIEVE_EXECUTE_FLAG_SKIP_RESPONSES flag to prevent any unforseen
+ mishaps.
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2018-05-07 11:03:01 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (2a39311d)
+
+ lib-sieve: Add SIEVE_EXECUTE_FLAG_SKIP_RESPONSES execute flag.
+
+ This causes the reject and vacation response actions to be skipped without
+ error.
+
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-types.h
+
+2018-05-02 23:46:27 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (fa816c6b)
+
+ lib-sieve: Add support for compiling Sieve scripts from an input stream.
+
+
+M configure.ac
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-storage-private.h
+M src/lib-sieve/storage/Makefile.am
+A src/lib-sieve/storage/data/Makefile.am
+A src/lib-sieve/storage/data/sieve-data-script.c
+A src/lib-sieve/storage/data/sieve-data-storage.c
+A src/lib-sieve/storage/data/sieve-data-storage.h
+
+2018-05-02 23:40:51 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (52085ae9)
+
+ lib-sieve: Allow sieve_script_binary_save() error_r parameter to be NULL.
+
+
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+
+2018-04-17 20:48:56 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (483d8a74)
+
+ lib-sieve: Always check the result returned from
+ smtp_address_init_from_msg().
+
+
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2018-05-02 13:46:15 +0300 Phil Carmody <phil@dovecot.fi> (518dc8b6)
+
+ ldap - fix stupid typo
+
+ Signed-off-by: Phil Carmody <phil@dovecot.fi>
+
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+
+2018-04-28 23:29:55 +0300 Phil Carmody <phil@dovecot.fi> (b86696e2)
+
+ global: expand default temporary pool sizes
+
+ The tests blow through these limits all of the time, which makes the logs
+ very noisy. These three cases are about 4/5ths of the test logs. Presumably
+ they're the ones that are also most often needing expansion in real world
+ use too.
+
+ Signed-off-by: Phil Carmody <phil@dovecot.fi>
+
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/storage/file/sieve-file-script.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+
+2018-04-28 23:11:40 +0300 Phil Carmody <phil@dovecot.fi> (45bc4fb6)
+
+ global: replace verbose strncmp()s with simpler str_begin()s
+
+ Signed-off-by: Phil Carmody <phil@dovecot.fi>
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+
+2018-04-27 17:28:03 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (51b7c26e)
+
+ lib-sieve: util: test-edit-mail: Determine test directory at the beginning
+ of all tests.
+
+ It is the initial working directory and that may change during testing, so
+ it is not a good idea to determine this per test.
+
+M src/lib-sieve/util/test-edit-mail.c
+
+2018-04-25 21:23:49 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (d51e6851)
+
+ lib-sieve: util: test-edit-mail: Fix unused variable warning reported by
+ GCC.
+
+
+M src/lib-sieve/util/test-edit-mail.c
+
+2018-04-18 10:16:29 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (890c6e26)
+
+ lib-sieve: util: edit-mail: Fix assert panic occurring when streaming large
+ headers.
+
+ The problem mainly arose because the stream buffer position was used to
+ determine how much was written, while the stream buffer position is
+ potentially decreased by i_stream_try_alloc().
+
+ Panic was:
+
+ Panic: file istream.c: line 197 (i_stream_read): assertion failed:
+ ((size_t)ret+old_size == _stream->pos - _stream->skip)
+
+M src/lib-sieve/util/edit-mail.c
+M src/lib-sieve/util/test-edit-mail.c
+
+2018-04-25 14:22:37 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (f0963ac9)
+
+ global: Replace str_append_n() with str_append_data().
+
+ The str_append_n() function is now deprecated. At no occasion, the occurence
+ of NUL in the data is possible or relevant, so each instance is replaced
+ with str_append_data() rather than str_append_max().
+
+M src/lib-managesieve/managesieve-quote.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/mime/cmd-extracttext.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+M src/lib-sieve/util/edit-mail.c
+M src/lib-sieve/util/rfc2822.c
+M src/lib-sieve/util/test-edit-mail.c
+M src/managesieve-login/client-authenticate.c
+M src/testsuite/testsuite-arguments.c
+
+2018-04-24 00:24:52 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (a82f2c3a)
+
+ lib-sieve: Never return SIEVE_EXEC_FAILURE from
+ sieve_multiscript_run_discard().
+
+ Always return SIEVE_EXEC_KEEP_FAILED instead.
+
+M src/lib-sieve/sieve.c
+
+2018-04-24 00:24:38 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (86827c4a)
+
+ lib-sieve: Never return SIEVE_EXEC_FAILURE from keep action.
+
+ Always return SIEVE_EXEC_KEEP_FAILED instead.
+
+M src/lib-sieve/sieve-result.c
+
+2018-04-16 21:49:08 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (f27aa69b)
+
+ tests: vacation extension: Add tests for configuring the subject codepoint
+ limit.
+
+
+M tests/extensions/vacation/message.svtest
+
+2018-04-16 20:42:46 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (ffbcd3bf)
+
+ lib-sieve: vacation extension: Make codepoint limit for subject header
+ configurable.
+
+
+M doc/extensions/vacation.txt
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+
+2018-04-16 20:41:59 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (e4b03a69)
+
+ tests: vacation extension: Add tests for the truncation of long subject
+ lines.
+
+
+M tests/extensions/vacation/message.svtest
+
+2018-04-16 19:49:15 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (f99afb6d)
+
+ lib-sieve: vacation extension: Enforce subject header limit in Unicode
+ codepoints rather than bytes.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2018-04-13 02:50:46 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (0712e678)
+
+ tests: envelope extension: Adjust to changes in Dovecot SMTP address parser.
+
+
+M tests/extensions/envelope.svtest
+
+2018-03-06 23:17:14 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (e15c66c9)
+
+ lib-sieve: Adjusted to changes in Dovecot message address to SMTP address
+ conversion.
+
+ This conversion now includes a check that may fail. Pigeonhole currently
+ only uses this functionality to obtain an SMTP version of the postmaster
+ address. This code is now consolidated in the sieve_get_postmaster_smtp()
+ function, which provides postmaster address as an SMTP address.
+
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/sieve-address-source.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve.c
+
+2018-03-29 00:07:47 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (9f09b81e)
+
+ lda-sieve plugin: Do not execute the sieve_discard script when an error
+ occurs.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2018-03-29 00:13:34 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (b06b775c)
+
+ lib-sieve: Never return TRUE from sieve_multiscript_will_discard() when
+ status is not successful.
+
+ Errors will trigger an implicit keep, not discard.
+
+M src/lib-sieve/sieve.c
+
+2018-02-15 09:06:26 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (3846eb3e)
+
+ lib-sieve: variables extension: Fix duplicate const in definition of
+ sieve_variables_modifier array.
+
+ This is wrong and leads to Clang compiler warnings.
+
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2018-03-06 23:52:40 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (5a71e7be)
+
+ lib-sieve: Do not allow UTF-8 in localpart in addresses parsed from Sieve
+ script.
+
+
+M src/lib-sieve/sieve-address.c
+M tests/compile/errors.svtest
+M tests/compile/errors/out-address.sieve
+
+2018-03-07 21:52:46 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (2c1c4220)
+
+ plugins: imapsieve: Don't log messages that disappear concurrently as an
+ error.
+
+ This is now logged as a debug message instead.
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2018-03-05 22:57:22 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (00190f91)
+
+ lib-sieve: util: edit-mail: Remove useless assignment.
+
+ This is a remnant of an older implementation and now triggered a scan-build
+ report.
+
+M src/lib-sieve/util/edit-mail.c
+
+2018-03-05 23:13:06 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (ab1f9582)
+
+ Update Dovecot version from v2.2 to v2.4.
+
+
+M README
+M configure.ac
+M doc/man/doveadm-sieve.1.in
+M doc/man/pigeonhole.7.in
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-filter.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+
+2018-03-03 10:12:28 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (91920140)
+
+ lib-sieve: Fix assert panic occurring when used command has external tag,
+ but is not registered.
+
+ This occurred for example when the "fileinto" command is used with only the
+ "copy" extension in the require line.
+
+ Panic message was:
+
+ Panic: file hash.c: line 263 (hash_table_insert_node): assertion failed:
+ (opcode == HASH_TABLE_OP_UPDATE)
+
+M src/lib-sieve/sieve-validator.c
+
+2018-03-03 10:28:07 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (095b2e12)
+
+ testsuite: Make SMTP actions also work inside executed sieve scripts.
+
+
+M src/testsuite/testsuite-script.c
+
+2018-03-03 12:50:28 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (17ae453d)
+
+ lib-sieve: util: Created basic test suite for edit-mail.
+
+ Previously, this was only tested implicitly in the Sieve test suite. Now, it
+ is tested explicitly, which allows for more flexibility in the testing
+ scenario.
+
+ It now extensively tests one scenario that used to fail.
+
+M src/lib-sieve/util/Makefile.am
+A src/lib-sieve/util/test-edit-mail.c
+
+2018-03-03 17:50:59 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (b1cd8048)
+
+ lib-sieve: util: edit-mail: istream: Fix bug in calculation of stream
+ position.
+
+ This caused an assert panic when the application or child stream did not
+ skip all buffered data immediately. This was reproducible only when the
+ message input stream consisted of a concatenation of smaller streams, which
+ is used in LMTP to prepend a few headers.
+
+ The panic was:
+
+ Panic: file istream.c: line 329 (i_stream_read_memarea): assertion failed:
+ ((size_t)ret+old_size == _stream->pos - _stream->skip)
+
+M src/lib-sieve/util/edit-mail.c
+
+2018-03-03 17:54:14 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (0b4ed1a3)
+
+ lib-sieve: util: edit-mail: istream: Remove useless check.
+
+ This is tested already in the assertion that precedes it.
+
+M src/lib-sieve/util/edit-mail.c
+
+2018-03-03 11:42:29 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (b9cfdb83)
+
+ lib-sieve: util: mail-raw: Implemented mail_raw_open_stream().
+
+ This allows using a seekable stream as mail directly.
+
+M src/lib-sieve/util/mail-raw.c
+M src/lib-sieve/util/mail-raw.h
+
+2018-03-03 10:59:23 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (cd4507f0)
+
+ Move mail-raw from lib-sieve-tool to lib-sieve/util.
+
+ Needed for use in test suite.
+
+M src/lib-sieve-tool/Makefile.am
+M src/lib-sieve/util/Makefile.am
+R100 src/lib-sieve-tool/mail-raw.c src/lib-sieve/util/mail-raw.c
+R100 src/lib-sieve-tool/mail-raw.h src/lib-sieve/util/mail-raw.h
+M src/testsuite/Makefile.am
+
+2018-03-02 20:21:27 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (71d7283d)
+
+ testsuite: Don't initialize mail storage with
+ mail_full_filesystem_access=yes.
+
+ Recent changes in Dovecot make slashes allowed in mailbox names when this
+ flag is set. This flag is not useful for the test suite and it breaks one of
+ the tests because slashes are no longer invalid when this flag is set.
+
+M src/testsuite/testsuite-mailstore.c
+
+2018-03-02 00:14:55 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (dadedf97)
+
+ lib-sieve: store action: Sanitize both specified and virtual mailbox names
+ in log strings.
+
+ Before, the virtual mailbox name was not sanitized, which caused control
+ characters to be displayed in log messages. Also, the mailbox name would be
+ mentioned twice in the log message, once santized and once unsanitized.
+
+M src/lib-sieve/sieve-actions.c
+
+2018-03-02 01:25:43 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (19e012ee)
+
+ lib-sieve: variables extension: Move top comment in sieve-ext-variables.h.
+
+ The header guard defines should be on top.
+
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2018-03-02 01:22:31 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (b7580860)
+
+ Changed .h ifdef/defines to use <NAME>_H format.
+
+
+M src/lib-managesieve/managesieve-arg.h
+M src/lib-managesieve/managesieve-parser.h
+M src/lib-managesieve/managesieve-quote.h
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/copy/sieve-ext-copy.h
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.h
+M src/lib-sieve/plugins/editheader/ext-editheader-common.h
+M src/lib-sieve/plugins/editheader/ext-editheader-limits.h
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify-limits.h
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/environment/ext-environment-common.h
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.h
+M src/lib-sieve/plugins/ihave/ext-ihave-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-limits.h
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/index/ext-index-common.h
+M src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
+M src/lib-sieve/plugins/mailbox/sieve-ext-mailbox.h
+M src/lib-sieve/plugins/metadata/ext-metadata-common.h
+M src/lib-sieve/plugins/mime/ext-mime-common.h
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/notify/ext-notify-limits.h
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug-common.h
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-common.h
+M src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.h
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address-source.h
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-plugins.h
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-storage-private.h
+M src/lib-sieve/sieve-storage.h
+M src/lib-sieve/sieve-stringlist.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.h
+M src/lib-sieve/storage/dict/sieve-dict-storage.h
+M src/lib-sieve/storage/file/sieve-file-storage.h
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.h
+M src/lib-sieve/util/edit-mail.h
+M src/lib-sieve/util/rfc2822.h
+M src/managesieve-login/client-authenticate.h
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-login-settings-plugin.h
+M src/managesieve-login/managesieve-login-settings.h
+M src/managesieve-login/managesieve-proxy.h
+M src/managesieve/managesieve-capabilities.h
+M src/managesieve/managesieve-client.h
+M src/managesieve/managesieve-commands.h
+M src/managesieve/managesieve-common.h
+M src/managesieve/managesieve-quota.h
+M src/managesieve/managesieve-settings.h
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd.h
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.h
+M src/plugins/imapsieve/ext-imapsieve-common.h
+M src/plugins/imapsieve/imap-sieve-storage.h
+M src/plugins/imapsieve/imap-sieve.h
+M src/plugins/imapsieve/sieve-imapsieve-plugin.h
+M src/plugins/lda-sieve/lda-sieve-log.h
+M src/plugins/lda-sieve/lda-sieve-plugin.h
+M src/plugins/sieve-extprograms/sieve-extprograms-common.h
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.h
+M src/testsuite/testsuite-arguments.h
+M src/testsuite/testsuite-binary.h
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.h
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite-result.h
+M src/testsuite/testsuite-script.h
+M src/testsuite/testsuite-settings.h
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite-substitutions.h
+M src/testsuite/testsuite-variables.h
+
+2018-03-02 00:53:31 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (9f6db6f4)
+
+ Remove copyright notices from header files.
+
+ Dovecot core doesn't have copyright notices in header files.
+
+M src/lib-managesieve/managesieve-arg.h
+M src/lib-managesieve/managesieve-parser.h
+M src/lib-managesieve/managesieve-quote.h
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/copy/sieve-ext-copy.h
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.h
+M src/lib-sieve/plugins/editheader/ext-editheader-common.h
+M src/lib-sieve/plugins/editheader/ext-editheader-limits.h
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify-limits.h
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/environment/ext-environment-common.h
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.h
+M src/lib-sieve/plugins/ihave/ext-ihave-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-limits.h
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/index/ext-index-common.h
+M src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
+M src/lib-sieve/plugins/mailbox/sieve-ext-mailbox.h
+M src/lib-sieve/plugins/metadata/ext-metadata-common.h
+M src/lib-sieve/plugins/mime/ext-mime-common.h
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/notify/ext-notify-limits.h
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug-common.h
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-common.h
+M src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.h
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address-source.h
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-plugins.h
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-storage-private.h
+M src/lib-sieve/sieve-storage.h
+M src/lib-sieve/sieve-stringlist.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.h
+M src/lib-sieve/storage/dict/sieve-dict-storage.h
+M src/lib-sieve/storage/file/sieve-file-storage.h
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.h
+M src/lib-sieve/util/edit-mail.h
+M src/lib-sieve/util/rfc2822.h
+M src/managesieve-login/client-authenticate.h
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-login-settings-plugin.h
+M src/managesieve-login/managesieve-login-settings.h
+M src/managesieve-login/managesieve-proxy.h
+M src/managesieve/managesieve-capabilities.h
+M src/managesieve/managesieve-client.h
+M src/managesieve/managesieve-commands.h
+M src/managesieve/managesieve-common.h
+M src/managesieve/managesieve-quota.h
+M src/managesieve/managesieve-settings.h
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd.h
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.h
+M src/plugins/imapsieve/ext-imapsieve-common.h
+M src/plugins/imapsieve/imap-sieve-plugin.h
+M src/plugins/imapsieve/imap-sieve-storage.h
+M src/plugins/imapsieve/imap-sieve.h
+M src/plugins/imapsieve/sieve-imapsieve-plugin.h
+M src/plugins/lda-sieve/lda-sieve-log.h
+M src/plugins/lda-sieve/lda-sieve-plugin.h
+M src/plugins/sieve-extprograms/sieve-extprograms-common.h
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.h
+M src/testsuite/testsuite-arguments.h
+M src/testsuite/testsuite-binary.h
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.h
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite-result.h
+M src/testsuite/testsuite-script.h
+M src/testsuite/testsuite-settings.h
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite-substitutions.h
+M src/testsuite/testsuite-variables.h
+
+2018-02-15 09:47:09 +0200 Aki Tuomi <aki.tuomi@dovecot.fi> (907d3b00)
+
+ imapsieve: Check more imapsieve contexts
+
+ Satisfies static analyzer, these were forgotten from
+ b2de2aee75963a1ac5b229a3578f08bca0d23a0e
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2018-02-08 12:19:52 +0200 Aki Tuomi <aki.tuomi@dovecot.fi> (b2de2aee)
+
+ imapsieve: Check imapsieve contexts
+
+ Satisfies static analyzer
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2018-02-08 12:12:31 +0200 Aki Tuomi <aki.tuomi@dovecot.fi> (973963e5)
+
+ doveadm-sieve-sync: Require sieve context
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+
+2018-02-13 09:51:48 +0200 Martti Rannanjärvi <martti.rannanjarvi@dovecot.fi> (36418e04)
+
+ managesieve: Drop MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT flag
+
+ The flag has been removed, and the setting is now the default.
+
+M src/managesieve/main.c
+
+2018-02-01 21:24:05 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (169dae70)
+
+ plugins: imapsieve: Deal with messages being expunged concurrently by the
+ time Sieve filter is to be applied.
+
+ Before, this was an assertion that got triggered transiently during
+ imaptest.
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2018-01-05 21:40:33 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (3a9ea428)
+
+ tests: extprograms plugin: execute extension: Add test for large output from
+ program.
+
+
+A tests/plugins/extprograms/bin/big
+M tests/plugins/extprograms/execute/execute.svtest
+
+2018-01-05 21:44:29 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (d8d8cb8c)
+
+ sieve-extprograms plugin: execute extension: Fix handling big output from
+ external program.
+
+ The output buffer was on the data stack, which leads to big trouble when the
+ buffer needs to grow in a deeper stack level.
+
+M src/plugins/sieve-extprograms/cmd-execute.c
+
+2018-01-04 00:52:31 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (d4ee6c85)
+
+ tests: imap4flags extension: Added more tests involving variables.
+
+
+M tests/extensions/imap4flags/basic.svtest
+
+2018-01-04 00:39:38 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (8b9f5e2e)
+
+ lib-sieve: imap4flags extension: Fix binary corruption occurring when
+ setflag/addflag/removeflag flag-list is a variable.
+
+ The original implementation checked the first operand for being a variable.
+ Obviously, when the assigned flag string is just a variable, this doesn't
+ work. This causes the flag list to be recognized erroneously as a variable
+ flags string. Fixed the problem by explicitly emitting an omitted operand
+ when there is no second argument for a setflag/addflag/removeflag.
+
+ Because the new byte code format is incompatible, the extension version is
+ bumped to 1.
+
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+
+2018-01-01 20:09:40 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (00d2c5b7)
+
+ Updated copyright notices to include the year 2018.
+
+
+M doc/man/doveadm-sieve.1.in
+M doc/man/pigeonhole.7.in
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-filter.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+M src/lib-managesieve/managesieve-arg.c
+M src/lib-managesieve/managesieve-arg.h
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-managesieve/managesieve-parser.h
+M src/lib-managesieve/managesieve-quote.c
+M src/lib-managesieve/managesieve-quote.h
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/cmp-i-ascii-casemap.c
+M src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/copy/sieve-ext-copy.h
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/date/ext-date.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.h
+M src/lib-sieve/plugins/duplicate/ext-duplicate.c
+M src/lib-sieve/plugins/duplicate/tst-duplicate.c
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.h
+M src/lib-sieve/plugins/editheader/ext-editheader-limits.h
+M src/lib-sieve/plugins/editheader/ext-editheader.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify-limits.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/ext-environment-common.h
+M src/lib-sieve/plugins/environment/ext-environment.c
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/ihave/cmd-error.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.h
+M src/lib-sieve/plugins/ihave/ext-ihave-common.c
+M src/lib-sieve/plugins/ihave/ext-ihave-common.h
+M src/lib-sieve/plugins/ihave/ext-ihave.c
+M src/lib-sieve/plugins/ihave/tst-ihave.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-limits.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/index/ext-index-common.c
+M src/lib-sieve/plugins/index/ext-index-common.h
+M src/lib-sieve/plugins/index/ext-index.c
+M src/lib-sieve/plugins/index/tag-index.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/plugins/mailbox/sieve-ext-mailbox.h
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/metadata/ext-metadata-common.h
+M src/lib-sieve/plugins/metadata/ext-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+M src/lib-sieve/plugins/mime/cmd-break.c
+M src/lib-sieve/plugins/mime/cmd-extracttext.c
+M src/lib-sieve/plugins/mime/cmd-foreverypart.c
+M src/lib-sieve/plugins/mime/ext-extracttext.c
+M src/lib-sieve/plugins/mime/ext-foreverypart.c
+M src/lib-sieve/plugins/mime/ext-mime-common.c
+M src/lib-sieve/plugins/mime/ext-mime-common.h
+M src/lib-sieve/plugins/mime/ext-mime.c
+M src/lib-sieve/plugins/mime/tag-mime.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/notify/ext-notify-limits.h
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation-seconds.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/cmd-debug-log.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug-common.h
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-common.h
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-items.c
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-variables.c
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.c
+M src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address-source.c
+M src/lib-sieve/sieve-address-source.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary-code.c
+M src/lib-sieve/sieve-binary-debug.c
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-plugins.c
+M src/lib-sieve/sieve-plugins.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-storage-private.h
+M src/lib-sieve/sieve-storage-sync.c
+M src/lib-sieve/sieve-storage.c
+M src/lib-sieve/sieve-storage.h
+M src/lib-sieve/sieve-stringlist.c
+M src/lib-sieve/sieve-stringlist.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/storage/dict/sieve-dict-script.c
+M src/lib-sieve/storage/dict/sieve-dict-storage.c
+M src/lib-sieve/storage/dict/sieve-dict-storage.h
+M src/lib-sieve/storage/file/sieve-file-script-sequence.c
+M src/lib-sieve/storage/file/sieve-file-script.c
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+M src/lib-sieve/storage/file/sieve-file-storage-list.c
+M src/lib-sieve/storage/file/sieve-file-storage-quota.c
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+M src/lib-sieve/storage/file/sieve-file-storage.h
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+M src/lib-sieve/storage/ldap/sieve-ldap-script.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage-settings.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/lib-sieve/tst-truefalse.c
+M src/lib-sieve/util/edit-mail.c
+M src/lib-sieve/util/edit-mail.h
+M src/lib-sieve/util/rfc2822.c
+M src/lib-sieve/util/rfc2822.h
+M src/managesieve-login/client-authenticate.c
+M src/managesieve-login/client-authenticate.h
+M src/managesieve-login/client.c
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-login-settings-plugin.c
+M src/managesieve-login/managesieve-login-settings-plugin.h
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve-login/managesieve-login-settings.h
+M src/managesieve-login/managesieve-proxy.c
+M src/managesieve-login/managesieve-proxy.h
+M src/managesieve/cmd-capability.c
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-havespace.c
+M src/managesieve/cmd-listscripts.c
+M src/managesieve/cmd-logout.c
+M src/managesieve/cmd-noop.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/cmd-setactive.c
+M src/managesieve/main.c
+M src/managesieve/managesieve-capabilities.c
+M src/managesieve/managesieve-capabilities.h
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+M src/managesieve/managesieve-commands.c
+M src/managesieve/managesieve-commands.h
+M src/managesieve/managesieve-common.h
+M src/managesieve/managesieve-quota.c
+M src/managesieve/managesieve-quota.h
+M src/managesieve/managesieve-settings.c
+M src/managesieve/managesieve-settings.h
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-activate.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-delete.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-get.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-list.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-put.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-rename.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd.h
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.h
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+M src/plugins/imapsieve/ext-imapsieve-common.h
+M src/plugins/imapsieve/ext-imapsieve-environment.c
+M src/plugins/imapsieve/ext-imapsieve.c
+M src/plugins/imapsieve/imap-sieve-plugin.c
+M src/plugins/imapsieve/imap-sieve-plugin.h
+M src/plugins/imapsieve/imap-sieve-storage.c
+M src/plugins/imapsieve/imap-sieve-storage.h
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/imapsieve/imap-sieve.h
+M src/plugins/imapsieve/sieve-imapsieve-plugin.c
+M src/plugins/imapsieve/sieve-imapsieve-plugin.h
+M src/plugins/lda-sieve/lda-sieve-log.c
+M src/plugins/lda-sieve/lda-sieve-log.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.h
+M src/plugins/settings/pigeonhole-settings.c
+M src/plugins/sieve-extprograms/cmd-execute.c
+M src/plugins/sieve-extprograms/cmd-filter.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+M src/plugins/sieve-extprograms/ext-execute.c
+M src/plugins/sieve-extprograms/ext-filter.c
+M src/plugins/sieve-extprograms/ext-pipe.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.h
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.c
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.h
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-imap-metadata.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-arguments.c
+M src/testsuite/testsuite-arguments.h
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-binary.h
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-log.h
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-script.h
+M src/testsuite/testsuite-settings.c
+M src/testsuite/testsuite-settings.h
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/testsuite-substitutions.h
+M src/testsuite/testsuite-variables.c
+M src/testsuite/testsuite-variables.h
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-action.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2017-12-25 18:20:14 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (321a39be)
+
+ plugins: sieve-extprograms: Fix segfault occurring when used in IMAPSieve
+ context.
+
+ This was caused by recent lib-smtp changes. There is no envelope in
+ IMAPSieve context, so the rcpt parameters are NULL, causing the segfault.
+
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+
+2017-12-23 16:37:27 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (480eb777)
+
+ plugins: lda-sieve: Remove session ID prefix from log messages.
+
+ The session ID is now already added by Dovecot.
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2017-12-18 21:11:31 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (15f05db9)
+
+ lib-sieve: vacation extension: Use the correct address for "From:" outgoing
+ header when original envelope recipient is found.
+
+ Caused by earlier adjustments for Dovecot lib-smtp. Copy-paste problem
+ detected by Coverity.
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2017-12-18 19:55:03 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (c8b4ade0)
+
+ test suite: enotify extension: Remove stray test_message_print call.
+
+ It is a remnant from debugging.
+
+M tests/extensions/enotify/mailto.svtest
+
+2017-12-16 02:04:09 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (6670190d)
+
+ global: Change calls to array_idx_modifiable to array_idx_get_space.
+
+ Only calls that require space allocation are to be changed.
+
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-validator.c
+
+2017-12-16 01:31:38 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (82a16434)
+
+ configure: Switched version number to 0.6.devel.
+
+
+M configure.ac
+
+2017-12-03 13:17:24 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (1b2454cf)
+
+ lib-sieve: Fixed writing address headers to outgoing messages.
+
+ It erroneously applied another layer of MIME header encoding. The problem is
+ that existing Sieve scripts may rely on this behaviour; i.e. scripts may
+ contain addresesses with literal UTF8 in the phrase part. Therefore, this
+ change allows both behaviors.
+
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M tests/extensions/enotify/mailto.svtest
+M tests/extensions/vacation/utf-8.svtest
+
+2017-12-03 12:52:03 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (811f84f8)
+
+ lib-sieve: util: rfc2822: Added rfc2822_header_write_address() which allows
+ adding a header with one or more addresses.
+
+ It applies UTF8 encoding only when the address string somehow contains 8-bit
+ characters. Sieve addresses are supposed to have any UTF8 characters in the
+ phase MIME-encoded, not literal 8-bit characters. However, this has been
+ allowed from the beginning, so disabling the old behavior may break existing
+ installations. This function allows supporting both options.
+
+M src/lib-sieve/util/rfc2822.c
+M src/lib-sieve/util/rfc2822.h
+
+2017-12-11 17:39:04 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (fe3b7c4b)
+
+ managesieve: Include mail user variables in logout format
+
+ Also dropped the single-letter identifier for most fields to prevent
+ conflicts with mail user variables; these were undocumented anyway.
+
+M src/managesieve/managesieve-client.c
+
+2017-12-11 17:35:07 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (95a0c04a)
+
+ doc: example-config: Document remaining supported managesieve_logout_format
+ substitution variables.
+
+ A few were still omitted.
+
+M doc/example-config/conf.d/20-managesieve.conf
+
+2017-12-11 17:14:27 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (dbc3f2f8)
+
+ global: start relying on [io]_stream_unref(NULL) being a no-op
+
+ Cleanup performed with the following semantic patch:
+
+ @@
+ expression E;
+ @@
+
+ - if (E != NULL) {
+ - i_stream_unref(&E);
+ - }
+ + i_stream_unref(&E);
+
+ @@
+ expression E;
+ @@
+
+ - if (E != NULL) {
+ - o_stream_unref(&E);
+ - }
+ + o_stream_unref(&E);
+
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+M src/lib-sieve/util/edit-mail.c
+
+2017-12-11 17:08:21 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (45cfd196)
+
+ global: start relying on timeout_remove(NULL) being a no-op
+
+ Cleanup performed with the following semantic patch:
+
+ @@
+ expression E;
+ @@
+
+ - if (E != NULL) {
+ - timeout_remove(&E);
+ - }
+ + timeout_remove(&E);
+
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+M src/managesieve-login/client.c
+M src/managesieve/managesieve-client.c
+
+2017-12-11 17:04:28 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (ca1773cd)
+
+ global: start relying on io_remove{,_closed}(NULL) being a no-op
+
+ Cleanup performed with the following semantic patch:
+
+ @@
+ expression E;
+ @@
+
+ - if (E != NULL) {
+ - io_remove(&E);
+ - }
+ + io_remove(&E);
+
+ @@
+ expression E;
+ @@
+
+ - if (E != NULL) {
+ - io_remove_closed(&E);
+ - }
+ + io_remove_closed(&E);
+
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+M src/managesieve/managesieve-client.c
+
+2017-12-15 13:21:30 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (b5a9750a)
+
+ lib-sieve: Adjusted to changes in handling of postmaster_address setting in
+ Dovecot.
+
+ Error handling is delayed, so that we need to explicitly handle the error in
+ Sieve. This is now implemented by handling the error before executing the
+ scritpt and placing the parsed address in struct sieve_script_env.
+
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+
+2017-12-15 12:46:54 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (15ddc4a0)
+
+ lib-sieve: Added sieve_script_env_init() to initialize struct
+ sieve_script_env from struct mail_user.
+
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite.c
+
+2017-12-15 12:31:34 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (68395161)
+
+ plugins: lda-sieve: Restructured lda_sieve_execute() to reduce indent.
+
+ Most code was put in an unnecessary else block.
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2017-12-13 19:57:39 +0200 Timo Sirainen <timo.sirainen@dovecot.fi> (32bdac72)
+
+ lib-sieve: file storage: When autodetecting storage path, use home even if
+ it doesn't exist
+
+ If a home directory is given, it's assumed that it will be autocreated even
+ if it doesn't initially exist. Earlier the autocreation may have been done
+ by lib-storage as it created the mail root directory, but this no longer
+ happens.
+
+M src/lib-sieve/storage/file/sieve-file-storage.c
+
+2017-12-12 16:35:55 +0200 Timo Sirainen <timo.sirainen@dovecot.fi> (cedc5e4b)
+
+ global: Adjust to mail_user_alloc() API change
+
+ The parent event doesn't really matter here, so NULL is used.
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/testsuite/testsuite-mailstore.c
+
+2017-12-11 16:45:58 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (624e1769)
+
+ managesieve: Adjusted to lib-storage changes in Dovecot.
+
+ This follows the following commits in Dovecot: lib-storage: Moved connection
+ information in struct mail_user into separate struct
+ mail_user_connection_data. lib-storage: mail-user: Added more information
+ about the client connection.
+
+M src/managesieve/main.c
+
+2017-12-03 13:01:53 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (37853002)
+
+ lib-sieve: vnd.dovecot.report extension: Fixed creation of
+ "Original-Mail-From" and original "Original-Rcpt-To" headers.
+
+ Recent changes relating to lib-smtp caused the paths to have duplicate '<'
+ '>'.
+
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+
+2017-12-03 12:50:26 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (4a9bc3d2)
+
+ lib-sieve: enotify extension: mailto method: Fixed parsing of mailto URI
+ with only a header part.
+
+
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+
+2017-01-20 19:16:06 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (fbedb2db)
+
+ Adjusted to the lib-smtp changes in Dovecot.
+
+ Now using struct smtp_address rather than sieve_address. In some cases,
+ struct message_address may prove to be more suitable, but this is the best
+ fit for now. Adjusted to the renamed fields in struct mail_deliver_context.
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address-source.c
+M src/lib-sieve/sieve-address-source.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/plugins/imapsieve/ext-imapsieve-environment.c
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/Makefile.am
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite.c
+M tests/execute/smtp.svtest
+M tests/extensions/envelope.svtest
+M tests/extensions/reject/smtp.svtest
+
+2017-11-16 00:07:14 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (89f1d4ab)
+
+ lib-sieve: enotify extension: uri-mailto: Removed unused field.
+
+ It doesn't serve a purpose either, since parsing "from" address from URI is
+ not allowed for notify mailto.
+
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
+
+2017-11-25 11:51:02 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (81505779)
+
+ lib-sieve: store action: Avoid NULL pointer dereference during rollback when
+ transaction context is somehow unassigned.
+
+ This change matches the other transaction stages. This will not currently
+ happen though. Reported by Coverity.
+
+M src/lib-sieve/sieve-actions.c
+
+2017-11-25 11:45:52 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (972bafc4)
+
+ lib-managesieve: managesieve-parser: Return error status in quoted string
+ stream immediately.
+
+ Otherwise the error status is overwritten. Problem found by Coverity.
+
+M src/lib-managesieve/managesieve-parser.c
+
+2017-11-25 11:28:57 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (c9cf5650)
+
+ lib-sieve: util: edit-mail: Fixed potential NULL dereference in
+ edit_mail_istream_seek().
+
+ Used the stream's cur_header field, rather than the local variable. Problem
+ found by Coverity.
+
+M src/lib-sieve/util/edit-mail.c
+
+2017-11-25 11:22:56 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (1e20fa6c)
+
+ lib-sieve: util: edit-header: Fixed potential NULL dereference in
+ edit_mail_istream_read().
+
+ The merge_from_parent() function may not actually read anything, potentially
+ leaving the stream buffer unassigned. Problem found by Coverity.
+
+M src/lib-sieve/util/edit-mail.c
+
+2017-03-31 01:48:41 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (6f31aa72)
+
+ lib-sieve: variables extension: Made the maximum scope and variable size
+ configurable.
+
+
+M INSTALL
+A doc/extensions/variables.txt
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/mime/cmd-extracttext.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/plugins/sieve-extprograms/cmd-execute.c
+
+2017-11-03 21:31:36 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (56b46cd0)
+
+ lib-sieve: util: edit-mail: Changed buffer implementation to use normal
+ stream buffer management.
+
+ This makes the implementation easier to understand and amend once Dovecot
+ APIs changes. This implicitly makes the implementation suitable for the new
+ istream snapshot handling.
+
+M src/lib-sieve/util/edit-mail.c
+
+2017-11-04 00:42:47 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (c8a70d56)
+
+ lib-sieve: util: edit-mail: Restructured merge_modified_headers() to remove
+ useless indent.
+
+
+M src/lib-sieve/util/edit-mail.c
+
+2017-11-03 21:26:52 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (ce92b90b)
+
+ lib-sieve: util: edit-mail: Properly remember the detection of EOF in the
+ edit mail stream.
+
+
+M src/lib-sieve/util/edit-mail.c
+
+2017-11-02 11:43:08 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (87402574)
+
+ lib-sieve: util: edit-mail: Fixed runtime integer arithmetic warnings
+ (CLang).
+
+ Added assertions on subtractions. Restructured the code for clarity. Added
+ comments.
+
+M src/lib-sieve/util/edit-mail.c
+
+2017-11-03 21:33:06 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (48a29a0b)
+
+ testsuite: editheader extension: Added a few more tests.
+
+
+M tests/extensions/editheader/addheader.svtest
+
+2017-11-01 22:55:34 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (daeff904)
+
+ lib-managesieve: managesieve-parser: Adjusted quoted string stream to
+ istream changes in Dovecot.
+
+ Ported Dovecot's istream-jsonstr for ManageSieve syntax.
+
+M src/lib-managesieve/managesieve-parser.c
+
+2017-11-01 22:54:05 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (c582d151)
+
+ managesieve: putscript command: Fixed parse error handling for save parser.
+
+
+M src/managesieve/cmd-putscript.c
+
+2017-11-07 00:42:24 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (96fe42e7)
+
+ managesieve-login: Removed ssl-proxy.h include forgotten in the previous
+ commit.
+
+
+M src/managesieve-login/client.c
+
+2017-11-02 15:28:32 +0200 Timo Sirainen <timo.sirainen@dovecot.fi> (001d9f1f)
+
+ managesieve-login: Core API change - rename ssl_initialized to
+ login_ssl_initialized
+
+
+M src/managesieve-login/client.c
+
+2017-11-02 23:45:17 +0200 Timo Sirainen <timo.sirainen@dovecot.fi> (a5b04e7a)
+
+ managesieve: Don't access login_set.*_socket_path after they're freed from
+ data stack
+
+ Call master_login_init() before master_service_init_finish(), which frees
+ all the data stack done in initialization.
+
+ This didn't normally cause any visible problems, because data stack wasn't
+ currently being used in a way that the strings were invalidated. However, it
+ was causing failures if --enable-devel-checks was used.
+
+M src/managesieve/main.c
+
+2017-11-02 09:54:39 +0200 Martti Rannanjärvi <martti.rannanjarvi@dovecot.fi> (4fd3b53a)
+
+ lib-managesieve,lib-sieve: Add istream_create_flag parameter to
+ i_stream_create
+
+
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-sieve/util/edit-mail.c
+
+2017-11-01 11:57:58 +0200 Aki Tuomi <aki.tuomi@dovecot.fi> (6558a20e)
+
+ lib-sieve: Fix undefined define
+
+
+M src/lib-sieve/storage/ldap/sieve-ldap-db.h
+
+2017-10-30 16:14:26 +0200 Timo Sirainen <timo.sirainen@dovecot.fi> (f4659224)
+
+ global: Rename i_stream_is_eof() to i_stream_read_eof()
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+
+2017-10-28 03:16:35 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (40c54675)
+
+ global: Replace o_stream_nfinish() with o_stream_finish
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/sieve.c
+M src/testsuite/testsuite-smtp.c
+
+2017-10-29 21:27:05 +0200 Aki Tuomi <aki.tuomi@dovecot.fi> (0f46b1d8)
+
+ configure: Support EXTRA_CFLAGS/LDFLAGS
+
+
+M configure.ac
+
+2017-10-23 15:11:18 +0300 Aki Tuomi <aki.tuomi@dovecot.fi> (97a87ac7)
+
+ lib-sieve: Use uni_is_valid_ucs4 to check ucs4 validity
+
+
+M src/lib-sieve/ext-encoded-character.c
+
+2017-10-23 01:34:09 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (454bbd47)
+
+ managesieve: Fixed spelling mistake in source code.
+
+ Patch by Andreas Schulze.
+
+M src/managesieve/managesieve-common.h
+
+2017-10-23 01:32:34 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (d0dab022)
+
+ lib-sieve: Fixed spelling mistakes in source code.
+
+ Patch by Andreas Schulze.
+
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-storage.c
+
+2017-10-23 01:31:49 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (f85c4e8c)
+
+ doc/man/sieve-test.1: Fixed spelling mistake.
+
+ Patch by Andreas Schulze.
+
+M doc/man/sieve-test.1.in
+
+2017-10-21 12:45:29 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (1210d338)
+
+ lib-sieve: enotify plugin: mailto method: Make sure from header is set to a
+ usable address and not (null).
+
+
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+
+2017-10-06 18:51:40 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (8b5be61d)
+
+ managesieve: Remove fd-set-nonblock.h includes.
+
+ It's replaced with fd-util.h which is automatically included now.
+
+M src/managesieve-login/managesieve-login-settings-plugin.c
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve/main.c
+
+2017-10-06 13:57:31 +0300 Aki Tuomi <aki.tuomi@dovecot.fi> (620b7808)
+
+ lib-sieve-tool: Remove fd-set-nonblock.h
+
+ It's replaced with fd-util.h which is automatically included now
+
+M src/lib-sieve-tool/mail-raw.c
+
+2017-10-05 23:29:25 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (37e8f71c)
+
+ managesieve: Fix missing-command check
+
+ Mirrors imap fix in Dovecot: 42149f48624b82fdf9631c256497580154c2e412
+
+ It's impossible for the command's pointer to be NULL at this point.
+ Previously, the command_find() would have returned NULL, but this check
+ presumably short-circuits that search in the trivial case, so has some real
+ use.
+
+ Problem now found by GCC 7.
+
+M src/managesieve/managesieve-client.c
+
+2017-10-05 23:19:13 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (15f9fd11)
+
+ imapsieve: Fixed check for the presence of causes in a mailbox rule.
+
+ Problem found by GCC 7.
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2017-10-05 23:15:17 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (370b9739)
+
+ lib-sieve: sieve-result: Added /* fall through */ comment to mark
+ intentional switch case fall through.
+
+ Addresses GCC 7 warning.
+
+M src/lib-sieve/sieve-result.c
+
+2017-09-22 15:59:15 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (a0997e4f)
+
+ Obtain postmaster_address and hostname from mail_storage_settings.
+
+
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-address-source.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite.c
+
+2017-09-14 04:11:42 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (1b42755f)
+
+ plugins: Migrated from lib-lda/smtp-client.h to using lib-smtp/smtp-submit.h
+ for message submission.
+
+
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2017-09-16 14:48:52 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (8b7bf6b6)
+
+ plugins/imapsieve: Initialize struct imap_sieve with full struct client,
+ rather than individual fields.
+
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/imapsieve/imap-sieve.h
+
+2017-10-04 23:32:23 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (4d0db1ce)
+
+ Adjusted to changes in Dovecot mail_duplicate API.
+
+
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2017-09-14 03:31:55 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (3ac2b15c)
+
+ lib-sieve: Dropped lib-lda dependencies.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-result.c
+
+2017-09-30 21:19:11 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (418816cd)
+
+ lib-sieve: redirect action: Always set X-Sieve-Redirected-From header to
+ sieve_user_email if configured.
+
+ Set it to the final recipient only when there is an envelope and
+ sieve_user_email is unconfigured.
+
+M src/lib-sieve/cmd-redirect.c
+M tests/execute/smtp.svtest
+
+2017-09-30 21:23:44 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (b38df93b)
+
+ testsuite: Fixed redirect action tests to use the correct test message.
+
+
+M tests/execute/smtp.svtest
+
+2017-09-22 16:30:26 +0300 Martti Rannanjärvi <martti.rannanjarvi@dovecot.fi> (c978393b)
+
+ global: Add reasons to mailbox_transaction_begins
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-storage-sync.c
+M src/lib-sieve/util/edit-mail.c
+M src/plugins/imapsieve/imap-sieve-storage.c
+M src/sieve-tools/sieve-filter.c
+M src/testsuite/testsuite-mailstore.c
+
+2017-08-24 02:03:21 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (8643cbde)
+
+ lib-sieve: vacation extension: Allow ignoring the envelope sender while
+ composing the "To:" header for the reply.
+
+ This adds a new setting "sieve_vacation_to_header_ignore_envelope". With
+ this setting enabled, the "To:" header is always composed from the first
+ "Sender", "Resent-From" or "From" header found in the message (in that
+ order). Normally, the "To:" header is composed from the address found in the
+ "Sender", "Resent-From" or "From" headers that is equal to the envelope
+ sender. If none is then found, the bare envelope sender is used. The new
+ setting allows ignoring the envelope, which is useful e.g. when SRS is used.
+
+M doc/extensions/vacation.txt
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M tests/extensions/vacation/message.svtest
+
+2017-09-05 21:29:06 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (2b3aca5a)
+
+ LDA Sieve plugin: Fixed sequential exection of LDAP-based scripts.
+
+ The sequence was broken when the LDAP script attribute does not exist; i.e.,
+ when the script is not found. The NOT_FOUND error is returned at a later
+ instance than normal fs-based scripts, explaining why this problem does not
+ normally occur.
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2017-09-05 20:26:21 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (15bd3533)
+
+ LDA Sieve plugin: Restructured execution of scripts by putting execution of
+ individual scripts in separate function.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2017-08-29 22:43:49 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (e5ea21fb)
+
+ lib-sieve: imap4flags extension: Added API for runtime initialization of
+ derived extensions.
+
+ This is needed to register the implicit side effect for the internal flag
+ variable.
+
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h
+
+2017-08-30 21:27:42 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (736f94ea)
+
+ imapsieve plugin: Fixed copyright messages.
+
+
+M src/plugins/imapsieve/imap-sieve-plugin.c
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2017-08-28 13:04:40 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (e37583a9)
+
+ sieve-filter: Removed (now) duplicate utf8 to mutf7 mailbox name conversion.
+
+ The Dovecot API was changed years ago, but apparently sieve-filter was never
+ updated.
+
+M src/sieve-tools/sieve-filter.c
+
+2017-08-22 13:15:34 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (dc20a45f)
+
+ imapsieve plugin: Provide proper error details upon failure to access the
+ mailbox/server script METADATA attribute.
+
+ This addresses an old FIXME.
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2017-08-18 16:20:22 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (e0e179b3)
+
+ lib-sieve: vacation extension: Fixed invalid return value in function added
+ by previous change.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2017-08-17 18:59:33 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (d55d8773)
+
+ lib-sieve: vacation extension: Compose the "To:" header from full sender
+ address found in the first "Sender:", "From:" or "Resent-From:" header.
+
+ Before, it would create a "To:" header without a phrase part. The new
+ behavior is nicer, since the reply will be addressed to the sender by name
+ if possible. This addresses an old FIXME.
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M tests/extensions/vacation/message.svtest
+
+2017-08-17 00:17:13 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (c7882e61)
+
+ lib-sieve: vacation extension: Use mail_get_first_header*() rather than
+ mail_get_headers(*).
+
+ Only the first header is ever of interest.
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2017-08-17 00:15:27 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (3a1ce369)
+
+ testsuite: vacation extension: Test creation of subject header better.
+
+
+M tests/extensions/vacation/message.svtest
+
+2017-07-08 10:51:27 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (d188419f)
+
+ sieve-tools: sieve-filter: Forgot to clean up script binary at end of
+ execution.
+
+ Normally, this would merely be an inconsequential memory leak. However, when
+ the script comes from an LDAP storage, the storage is not closed before
+ master_service_deinit() -> io_loop_destroy(). The LDAP connection's stale io
+ can cause problems while closing the main ioloop.
+
+M src/sieve-tools/sieve-filter.c
+
+2017-07-08 10:27:52 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (7aabfac4)
+
+ sieve-tools: Terminate with a fatal error when script cannot be
+ compiled/opened.
+
+ Rather than continuing with binary == NULL, causing a segfault.
+
+M src/lib-sieve-tool/sieve-tool.c
+
+2017-07-06 12:34:08 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (c80aa7c2)
+
+ managesieve-login: managesieve_client_input_next_cmd(): Fix handling of
+ command continuation.
+
+ Commands that continued after waiting for more input always failed. This
+ mainly applies to the AUTHENTICATE command, which mostly handles its own
+ arguments. This caused problems when a string literal was used as the
+ initial response for the AUTHENTICATE command.
+
+ Caused by recent change:
+
+ Author: Timo Sirainen <timo.sirainen@dovecot.fi> Date: Wed Jun 14 12:39:02
+ 2017 +0300
+
+ managesieve-login: managesieve_client_input_next_cmd() - minor code cleanup
+
+M src/managesieve-login/client.c
+
+2017-07-06 12:28:44 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (f7b63d94)
+
+ managesieve-login: authenticate command: Make sure
+ client->auth_mech_name_parsed is reset properly upon command error.
+
+ This could cause problems for any subsequent AUTHENTICATE commmend.
+
+M src/managesieve-login/client-authenticate.c
+
+2017-06-28 18:41:33 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (dd34509a)
+
+ LDA Sieve plugin: Fixed memory leak caused by not cleaning up the
+ sieve_discard script.
+
+ Moved script cleanup to separate function as well.
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2017-06-22 21:12:21 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (c024dc7c)
+
+ lib-sieve: include extension: Fixed segfault that (sometimes) occurred when
+ the global script location was left unconfigured.
+
+
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2017-06-20 23:36:10 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (f68f5637)
+
+ sieve-tools: Make sure sieve command line tools properly show debug messages
+ if requested.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/sieve-tools/sieve-filter.c
+
+2017-06-13 19:36:57 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (de4248b9)
+
+ lib-sieve: Made the retention period for redirect duplicate identifiers
+ configurable.
+
+ For accounts that perform many redirects, the lda-dupes database could grow
+ to impractical sizes. Changed the default retention period from 24 to 12
+ hours.
+
+M INSTALL
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-settings.c
+
+2017-06-20 20:46:28 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (82563e97)
+
+ lib-sieve: Clear extension context upon unload.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2017-06-16 14:42:39 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (072b0b49)
+
+ managesieve-login: Adjust to new client_vfuncs.free() API change
+
+
+M src/managesieve-login/client.c
+
+2017-06-14 12:39:46 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (303e561c)
+
+ managesieve-login: managesieve_client_input_next_cmd() - Add assert to help
+ static analyzer
+
+
+M src/managesieve-login/client.c
+
+2017-06-14 12:39:02 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (ea7e1789)
+
+ managesieve-login: managesieve_client_input_next_cmd() - minor code cleanup
+
+
+M src/managesieve-login/client.c
+
+2017-06-12 23:00:26 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (9d66c3e5)
+
+ managesieve-login: Adjust to login-common API change
+
+
+M src/managesieve-login/client.c
+
+2017-04-28 00:02:39 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (3e1a17a2)
+
+ lib-sieve: Fixed bug in handling of deferred implicit keep with implicit
+ side-effects.
+
+ Upon continuing the deferred implicit keep, the implicit side-effects (such
+ as imap flags) were not applied.
+
+M src/lib-sieve/sieve-result.c
+
+2017-04-24 18:58:07 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (11d5f197)
+
+ imapsieve: Use client_add_capability() for adding the dynamic capability
+
+
+M src/plugins/imapsieve/imap-sieve-plugin.c
+
+2017-04-21 13:37:40 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (649c7785)
+
+ managesieve-login: Fill the new client_vfuncs.send_raw_data
+
+
+M src/managesieve-login/client.c
+
+2017-04-12 13:17:53 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (6891f70d)
+
+ imapsieve: Fixed flag assignment for the source message.
+
+ Implicit keep was deferred for the source message, which discards all flags.
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2017-04-05 16:02:51 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (b8af3b97)
+
+ managesieve-login: Fill the new banner_sent field.
+
+
+M src/managesieve-login/client.c
+
+2017-03-10 21:48:14 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (e69a6dec)
+
+ imapsieve plugin: Implemented the copy_source_after rule action.
+
+ When this is enabled for a mailbox rule, the specified Sieve script is
+ executed for the message in the source mailbox during a "COPY" event. This
+ happens only after the Sieve script that is executed for the corresponding
+ message in the destination mailbox finishes running successfully.
+
+M doc/plugins/imapsieve.txt
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2017-03-10 21:53:19 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (71e773ca)
+
+ imapsieve plugin: Prevent recording events for the COPY/MOVE source mailbox
+ transaction.
+
+ This already has the imapsieve transaction context associated with it before
+ the sieve scripts are executed. This currently cannot occur, but it will
+ become relevant in subsequent commits.
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2017-03-10 21:44:36 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (b7ade8c3)
+
+ imapsieve plugin: Added non-standard Sieve environment items for source and
+ destination mailbox.
+
+
+M doc/plugins/imapsieve.txt
+M src/plugins/imapsieve/ext-imapsieve-common.h
+M src/plugins/imapsieve/ext-imapsieve-environment.c
+M src/plugins/imapsieve/ext-imapsieve.c
+M src/plugins/imapsieve/imap-sieve-storage.c
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/imapsieve/imap-sieve.h
+M src/plugins/imapsieve/sieve-imapsieve-plugin.c
+
+2017-03-10 21:36:13 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (1748e01b)
+
+ imapsieve plugin: Don't open the user's personal script storage if no
+ personal script is configured.
+
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2017-03-10 21:31:40 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (148ba040)
+
+ imapsieve plugin: Forgot to cleanup imap_sieve_run object when
+ mailbox_sync() fails.
+
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2017-03-16 20:56:46 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (e0283189)
+
+ lib-sieve: multiscript: The execution of the discard script had an implicit
+ "keep", rather than an implicit "discard".
+
+
+M src/lib-sieve/sieve.c
+
+2017-03-09 12:13:04 -0500 Timo Sirainen <timo.sirainen@dovecot.fi> (8053c068)
+
+ managesieve-login: Log proxy state as human-readable string
+
+
+M src/managesieve-login/client.c
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-proxy.c
+M src/managesieve-login/managesieve-proxy.h
+
+2017-03-09 12:10:30 -0500 Timo Sirainen <timo.sirainen@dovecot.fi> (9f9bc901)
+
+ managesieve-login: Use enum managesieve_proxy_state for proxy_state
+
+
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-proxy.c
+
+2017-02-26 19:23:34 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (bf2bd0ff)
+
+ lib-sieve: store action: Made static analyzer happier about tr_context
+ argument for sieve_act_store_add_flags().
+
+ Added an assert ensuring it is not NULL.
+
+M src/lib-sieve/sieve-actions.c
+
+2017-02-26 18:25:53 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (7d06cde9)
+
+ managesieve: Fix creation of critical error message timestamp.
+
+ This used strftime() directly and allocated memory from the heap before
+ i_fatal(). It also used printf() to send the BYE message, which will only
+ work right when the service is running stand-alone.
+
+M src/managesieve/managesieve-client.c
+
+2017-02-22 13:36:26 +0200 Timo Sirainen <timo.sirainen@dovecot.fi> (92f3d323)
+
+ global: Replace mail_storage_service_user_free() with _unref()
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/managesieve/main.c
+M src/managesieve/managesieve-client.c
+
+2017-02-16 17:00:53 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (c4df3317)
+
+ lib-sieve: Made public function for adding a redirect action to the result.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+
+2017-02-07 18:10:48 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (25a5a493)
+
+ lib-sieve: Implemented means to abort SMTP message submission after it is
+ started.
+
+ This adds a new callback to the Sieve script execution environment.
+
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-types.h
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite.c
+
+2017-02-19 00:55:12 +0200 Timo Sirainen <timo.sirainen@dovecot.fi> (051cf477)
+
+ doveadm-sieve: Fix crash when setting Sieve script via attribute's string
+ value.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+
+2017-02-09 18:48:20 +0200 Timo Sirainen <timo.sirainen@dovecot.fi> (a1dbf7a9)
+
+ lib-sieve: Remove unnecessary mailbox_save_set_dest_mail() call
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+
+2017-02-09 17:26:29 +0200 Timo Sirainen <timo.sirainen@dovecot.fi> (85c9de00)
+
+ imapsieve: Remove unnecessary mail_save_context.dest_mail==NULL checks
+
+ It can never be NULL after the "lib-storage: Always create
+ mail_save_context.dest_mail" core change.
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2017-02-12 15:29:14 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (298b3410)
+
+ lib-sieve: file storage: Amended the up-to-date timestamp comparison for
+ on-disk binaries to include nanoseconds.
+
+ This will fix problems occurring when both binary and script are saved
+ within the same second. On older systems that have no support for
+ nanoseconds in the stat() time stamps, this has no effect.
+
+M src/lib-sieve/storage/file/sieve-file-script.c
+
+2017-02-12 15:28:44 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (602326ee)
+
+ lib-sieve: binary: Added means to obtain stat() information from loaded
+ binary.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+
+2017-02-12 14:01:41 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (014df56e)
+
+ imapsieve plugin: Make sure "INBOX" is upper case in static mailbox rules.
+
+ Otherwise, the mailbox name would never match, since matching is performed
+ case-sensitively and Dovecot only returns the upper-cased "INBOX". This
+ change prevents confusing administrators that for some reason choose to use
+ a different capitalization of that mailbox name.
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2017-02-12 11:46:31 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (34d44f7a)
+
+ lib-sieve: file storage: Improve save permission error.
+
+ Use eacces_error_get(), rather than just printing "Permission denied".
+
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+
+2017-02-08 02:08:17 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (51e4ff29)
+
+ lib-sieve: file storage: Improve listing permission error.
+
+ Use eacces_error_get(), rather than just printing "Permission denied".
+
+M src/lib-sieve/storage/file/sieve-file-storage-list.c
+
+2016-11-28 18:55:10 +0200 Martti Rannanjärvi <martti.rannanjarvi@dovecot.fi> (03434fa4)
+
+ global: Replace realpath with path-util from core.
+
+ path-util is a merge of realpath from Pigeonhole and abspath from core.
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve/storage/file/sieve-file-script.c
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+M src/lib-sieve/util/Makefile.am
+D src/lib-sieve/util/realpath.c
+D src/lib-sieve/util/realpath.h
+M src/managesieve/main.c
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite.c
+
+2017-01-14 02:52:42 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (462a5352)
+
+ lib-sieve: Fixed transaction context passed to finish() method of action
+ object in two cases.
+
+ This is not currently used anywhere, so nothing actually broke. This bug was
+ exposed by the previous commit, causing a compiler error/warning on some
+ compilers.
+
+M src/lib-sieve/sieve-result.c
+
+2017-01-13 23:24:10 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (77248553)
+
+ lib-sieve: Fixed handling of an early explicit keep during multiscript
+ execution.
+
+ Applies to LDA/LMTP context in general, not only when
+ sieve_before/sieve_after are used. Action side-effects and the message
+ snapshot would be lost at the final stage where the implicit keep is
+ evaluated. This happened because the keep action itself is not actually
+ executed, but rather its presence is noted to determine whether more scripts
+ need to be executed. So, when finally execution of the actual keep action is
+ due, i.e. when there are no more scripts in the sequence, it overrides the
+ explicit keep from the last script. This didn't take the side-effects and
+ message snapshot into account.
+
+M src/lib-sieve/sieve-result.c
+
+2017-01-11 21:01:45 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (2583936f)
+
+ Updated dovecot.m4.
+
+
+M m4/dovecot.m4
+
+2017-01-10 23:22:28 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (f9b37da1)
+
+ lib-sieve: Fixed handling of mail_get_headers()/mail_get_headers_utf8()
+ result.
+
+ The situation where no headers are found was not always handled correctly.
+
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/sieve-message.c
+
+2017-01-11 01:13:45 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (22cbd7e7)
+
+ lib-sieve: util: edit-mail: Fixed success return value for
+ mail_get_headers() to be 1.
+
+
+M src/lib-sieve/util/edit-mail.c
+
+2017-01-01 13:32:21 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (57c05f4d)
+
+ Updated copyright notices to include the year 2017.
+
+
+M doc/man/doveadm-sieve.1.in
+M doc/man/pigeonhole.7.in
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-filter.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+M src/lib-managesieve/managesieve-arg.c
+M src/lib-managesieve/managesieve-arg.h
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-managesieve/managesieve-parser.h
+M src/lib-managesieve/managesieve-quote.c
+M src/lib-managesieve/managesieve-quote.h
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/cmp-i-ascii-casemap.c
+M src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/copy/sieve-ext-copy.h
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/date/ext-date.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.h
+M src/lib-sieve/plugins/duplicate/ext-duplicate.c
+M src/lib-sieve/plugins/duplicate/tst-duplicate.c
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.h
+M src/lib-sieve/plugins/editheader/ext-editheader-limits.h
+M src/lib-sieve/plugins/editheader/ext-editheader.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify-limits.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/ext-environment-common.h
+M src/lib-sieve/plugins/environment/ext-environment.c
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/ihave/cmd-error.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.h
+M src/lib-sieve/plugins/ihave/ext-ihave-common.c
+M src/lib-sieve/plugins/ihave/ext-ihave-common.h
+M src/lib-sieve/plugins/ihave/ext-ihave.c
+M src/lib-sieve/plugins/ihave/tst-ihave.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-limits.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/index/ext-index-common.c
+M src/lib-sieve/plugins/index/ext-index-common.h
+M src/lib-sieve/plugins/index/ext-index.c
+M src/lib-sieve/plugins/index/tag-index.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/plugins/mailbox/sieve-ext-mailbox.h
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/metadata/ext-metadata-common.h
+M src/lib-sieve/plugins/metadata/ext-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+M src/lib-sieve/plugins/mime/cmd-break.c
+M src/lib-sieve/plugins/mime/cmd-extracttext.c
+M src/lib-sieve/plugins/mime/cmd-foreverypart.c
+M src/lib-sieve/plugins/mime/ext-extracttext.c
+M src/lib-sieve/plugins/mime/ext-foreverypart.c
+M src/lib-sieve/plugins/mime/ext-mime-common.c
+M src/lib-sieve/plugins/mime/ext-mime-common.h
+M src/lib-sieve/plugins/mime/ext-mime.c
+M src/lib-sieve/plugins/mime/tag-mime.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/notify/ext-notify-limits.h
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation-seconds.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/cmd-debug-log.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug-common.h
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-common.h
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-items.c
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-variables.c
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.c
+M src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address-source.c
+M src/lib-sieve/sieve-address-source.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary-code.c
+M src/lib-sieve/sieve-binary-debug.c
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-plugins.c
+M src/lib-sieve/sieve-plugins.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-storage-private.h
+M src/lib-sieve/sieve-storage-sync.c
+M src/lib-sieve/sieve-storage.c
+M src/lib-sieve/sieve-storage.h
+M src/lib-sieve/sieve-stringlist.c
+M src/lib-sieve/sieve-stringlist.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/storage/dict/sieve-dict-script.c
+M src/lib-sieve/storage/dict/sieve-dict-storage.c
+M src/lib-sieve/storage/dict/sieve-dict-storage.h
+M src/lib-sieve/storage/file/sieve-file-script-sequence.c
+M src/lib-sieve/storage/file/sieve-file-script.c
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+M src/lib-sieve/storage/file/sieve-file-storage-list.c
+M src/lib-sieve/storage/file/sieve-file-storage-quota.c
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+M src/lib-sieve/storage/file/sieve-file-storage.h
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+M src/lib-sieve/storage/ldap/sieve-ldap-script.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage-settings.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/lib-sieve/tst-truefalse.c
+M src/lib-sieve/util/edit-mail.c
+M src/lib-sieve/util/edit-mail.h
+M src/lib-sieve/util/rfc2822.c
+M src/lib-sieve/util/rfc2822.h
+M src/managesieve-login/client-authenticate.c
+M src/managesieve-login/client-authenticate.h
+M src/managesieve-login/client.c
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-login-settings-plugin.c
+M src/managesieve-login/managesieve-login-settings-plugin.h
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve-login/managesieve-login-settings.h
+M src/managesieve-login/managesieve-proxy.c
+M src/managesieve-login/managesieve-proxy.h
+M src/managesieve/cmd-capability.c
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-havespace.c
+M src/managesieve/cmd-listscripts.c
+M src/managesieve/cmd-logout.c
+M src/managesieve/cmd-noop.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/cmd-setactive.c
+M src/managesieve/main.c
+M src/managesieve/managesieve-capabilities.c
+M src/managesieve/managesieve-capabilities.h
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+M src/managesieve/managesieve-commands.c
+M src/managesieve/managesieve-commands.h
+M src/managesieve/managesieve-common.h
+M src/managesieve/managesieve-quota.c
+M src/managesieve/managesieve-quota.h
+M src/managesieve/managesieve-settings.c
+M src/managesieve/managesieve-settings.h
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-activate.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-delete.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-get.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-list.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-put.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-rename.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd.h
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.h
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+M src/plugins/imapsieve/ext-imapsieve-common.h
+M src/plugins/imapsieve/ext-imapsieve-environment.c
+M src/plugins/imapsieve/ext-imapsieve.c
+M src/plugins/imapsieve/imap-sieve-plugin.h
+M src/plugins/imapsieve/imap-sieve-storage.h
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/imapsieve/imap-sieve.h
+M src/plugins/imapsieve/sieve-imapsieve-plugin.c
+M src/plugins/imapsieve/sieve-imapsieve-plugin.h
+M src/plugins/lda-sieve/lda-sieve-log.c
+M src/plugins/lda-sieve/lda-sieve-log.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.h
+M src/plugins/settings/pigeonhole-settings.c
+M src/plugins/sieve-extprograms/cmd-execute.c
+M src/plugins/sieve-extprograms/cmd-filter.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+M src/plugins/sieve-extprograms/ext-execute.c
+M src/plugins/sieve-extprograms/ext-filter.c
+M src/plugins/sieve-extprograms/ext-pipe.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.h
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.c
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.h
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-imap-metadata.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-arguments.c
+M src/testsuite/testsuite-arguments.h
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-binary.h
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-log.h
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-script.h
+M src/testsuite/testsuite-settings.c
+M src/testsuite/testsuite-settings.h
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/testsuite-substitutions.h
+M src/testsuite/testsuite-variables.c
+M src/testsuite/testsuite-variables.h
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-action.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2016-12-24 02:56:01 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (131ea974)
+
+ global: Replaced all instances of memset(p, 0, sizeof(*p)) with the new
+ i_zero() macro.
+
+ Used the following script:
+
+ C_FILES=`git ls-files *.c` H_FILES=`git ls-files *.h` for F in "$C_FILES
+ $H_FILES"; do
+ echo "$F"
+ perl -p -i -e
+ 's/safe_memset\(&\(?([^,]*)\)?,\s*0,\s*sizeof\(\g1\)\)/i_zero_safe(&$1)/g'
+ $F
+ perl -p -i -e
+ 's/safe_memset\(([^,]*),\s*0,\s*sizeof\(\*\g1\)\)/i_zero_safe($1)/g' $F
+ perl -p -i -e
+ 's/memset\(&\(?([^,]*)\)?,\s*0,\s*sizeof\(\g1\)\)/i_zero(&$1)/g' $F
+ perl -p -i -e 's/memset\(([^,]*),\s*0,\s*sizeof\(\*\g1\)\)/i_zero($1)/g' $F
+ done
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-address-source.c
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-plugins.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/storage/dict/sieve-dict-storage.c
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/managesieve-login/managesieve-proxy.c
+M src/managesieve/main.c
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-commands.c
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+M src/plugins/imapsieve/imap-sieve-storage.c
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite.c
+
+2016-11-19 01:14:18 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (13fbc935)
+
+ lib-sieve: sieve-message: Fixed trimming of empty header.
+
+
+M src/lib-sieve/sieve-message.c
+
+2016-11-19 00:27:59 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (6709993b)
+
+ lib-sieve: matches match type: Improved string pointer manipulation.
+
+
+M src/lib-sieve/mcht-matches.c
+
+2016-12-26 19:56:47 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (5fe323d1)
+
+ managesieve-login: proxy: Adjusted to changes in Dovecot lib-sasl API.
+
+
+M src/managesieve-login/managesieve-proxy.c
+
+2016-11-13 15:13:48 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (c90b7fdc)
+
+ managesieve: Fixed indent in client_output().
+
+ Apparently, this causes GCC warnings.
+
+M src/managesieve/managesieve-client.c
+
+2016-11-13 15:11:59 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (d5afd719)
+
+ lib-sieve: file storage: Fixed indent in
+ sieve_storage_get_relative_link_path().
+
+ Apparently, this causes GCC warnings.
+
+M src/lib-sieve/storage/file/sieve-file-storage.c
+
+2016-11-08 01:45:16 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (c8b91de8)
+
+ imapsieve plugin: Removed spurious debug message.
+
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2016-11-08 01:03:00 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (00651e60)
+
+ imapsieve plugin: Fixed assert failure occurring when used with virtual
+ mailboxes.
+
+ In that case a transaction (delayed sync) is perfromed outside of the
+ context of an IMAP command.
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2016-11-07 09:55:28 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (be11698e)
+
+ doc: Forgot to add several files to the distribution.
+
+
+M doc/example-config/Makefile.am
+M doc/extensions/Makefile.am
+M doc/plugins/Makefile.am
+M doc/rfc/Makefile.am
+
+2016-11-03 20:52:07 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (3deda06e)
+
+ managesieve: Try to initialize var_expand_tab[] directly.
+
+ This avoids accidents with the array numbering being wrong.
+
+M src/managesieve/managesieve-client.c
+
+2016-11-03 20:26:49 +0100 Stephan Bosch <stephan.bosch@dovecot.fi> (849790c5)
+
+ lib-sieve: ldap storage: Adjust to var_expand*() API changes.
+
+
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+
+2016-11-01 01:09:42 +0200 Timo Sirainen <timo.sirainen@dovecot.fi> (1e5d2c6a)
+
+ Adjust to var_expand*() API changes.
+
+
+M src/lib-sieve/sieve-error.c
+M src/managesieve/main.c
+M src/managesieve/managesieve-client.c
+M src/plugins/lda-sieve/lda-sieve-log.c
+
+2016-10-29 14:28:07 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (10e70749)
+
+ lib-sieve: edit-mail: Adjusted to changes in Dovecot lib-storage/index.
+
+
+M src/lib-sieve/util/edit-mail.c
+
+2016-10-21 18:02:57 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (c5ed66bc)
+
+ testsuite: Cleanup spurious test output.
+
+
+M src/testsuite/Makefile.am
+
+2016-10-21 15:35:51 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (74ab3713)
+
+ managesieve: Added rawlog_dir setting to store ManageSieve traffic logs.
+
+ This at least partially replaces the "rawlog" post-login binary. For now the
+ "rawlog" binary supports some parameters, which aren't configurable for
+ rawlog_dir.
+
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-settings.c
+M src/managesieve/managesieve-settings.h
+
+2016-10-21 17:29:17 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (036d5191)
+
+ lib-sieve: vacation extension: Use Microsoft X-Auto-Response-Suppress header
+ to prevent unwanted responses.
+
+ We've seen a few situations where Pigeonhole and Microsoft products start a
+ useless machine conversation. At least older versions of Outlook ignore the
+ standards on multiple points to make this happen. We prevent this now by
+ recognizing and generating the X-Auto-Response-Suppress header.
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M tests/extensions/vacation/reply.svtest
+
+2016-10-21 17:36:44 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (32e7781d)
+
+ lib-sieve: util: Removed Pigeonhole's own version of t_str_trim(), since it
+ is now available in Dovecot.
+
+
+M src/lib-sieve/sieve-address-source.c
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/util/Makefile.am
+D src/lib-sieve/util/strtrim.c
+D src/lib-sieve/util/strtrim.h
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2016-10-21 01:01:16 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (663f8cc5)
+
+ lib-sieve: code dumper: Fixed T_BEGIN { ... } T_END block violation.
+
+
+M src/lib-sieve/sieve-code-dumper.c
+
+2016-10-20 02:38:07 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (ca0cd69e)
+
+ lib-sieve: vnd.dovecot.report extension: Added Dovecot-Reporting-User field,
+ which contains the e-mail address of the user sending the report.
+
+
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M tests/extensions/vnd.dovecot/report/execute.svtest
+
+2016-10-19 18:38:00 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (4d5a9448)
+
+ Updated dovecot.m4.
+
+
+M m4/dovecot.m4
+
+2016-10-19 16:04:49 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (905db120)
+
+ Sieve extprograms plugin: Adjusted to more changes in Dovecot program-client
+ API.
+
+
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+
+2016-10-17 23:59:58 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (85680b40)
+
+ lib-sieve: result object: Fixed bug in detection of the execution of
+ delivery action.
+
+ Sequential exections would override a previously flagged delivery, which is
+ wrong. This caused the sieve_discard feature to trigger for messages that
+ were actually delivered somewhere by an earlier script in the sequence.
+
+M src/lib-sieve/sieve-result.c
+
+2016-10-15 12:24:33 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (bcad6334)
+
+ LDA Sieve plugin: Fixed assert failure caused by earlier sieve_discard
+ changes.
+
+ The simplest case in which all normal scripts maintain the (implicit) keep
+ action triggered an assert failure. Fixed by restructuring the script
+ execution loop to make it easy to understand. Now handles each case
+ explicitly.
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2016-10-13 15:30:25 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (d18e9b53)
+
+ Sieve exprograms plugin: Adjusted to changes in Dovecot program-client API.
+
+
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+
+2016-10-11 16:40:47 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (a195bd82)
+
+ lib-sieve: vnd.dovecot.report extension: Added support for configuring the
+ "From:" address used in the report.
+
+
+A doc/extensions/vnd.dovecot.report.txt
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.c
+M src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.h
+M src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report.c
+M tests/extensions/vnd.dovecot/report/execute.svtest
+
+2016-10-10 19:20:57 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (2a6ff60b)
+
+ Sieve extprograms plugin: Adjusted to program-client API change in Dovecot.
+
+ program_client_remote_create() is now called program_client_unix_create().
+
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+
+2016-10-07 12:42:09 +0300 Martti Rannanjärvi <martti.rannanjarvi@dovecot.fi> (a8fb5314)
+
+ lib-sieve: restore realpath.h in Makefile.am
+
+
+M src/lib-sieve/util/Makefile.am
+
+2016-10-06 12:11:57 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (055537a3)
+
+ doveadm sieve plugin: sync: Fixed saving synchronized Sieve script.
+
+ Assert failure could occur if the input buffer was full. Also, a small
+ chance existed that not all data would be saved.
+
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+
+2016-10-05 22:28:03 +0300 Aki Tuomi <aki.tuomi@dovecot.fi> (22f05f11)
+
+ lib-sieve: program-client was moved to dovecot core
+
+
+M src/lib-sieve/util/Makefile.am
+D src/lib-sieve/util/program-client-local.c
+D src/lib-sieve/util/program-client-private.h
+D src/lib-sieve/util/program-client-remote.c
+D src/lib-sieve/util/program-client.c
+D src/lib-sieve/util/program-client.h
+
+2016-09-30 23:57:05 +0200 Stephan Bosch <stephan@dovecot.fi> (2ae18e51)
+
+ LDA Sieve plugin: Implemented support for a "discard script" that is run
+ when the message is going to be discarded.
+
+ This adds a new "sieve_discard" setting that points to the location of the
+ "discard script". Once the normal scripts finish executing and the result is
+ that the message will be discarded without being delivered anywhere, the
+ "discard script" is executed. The discard script can prevent dropping the
+ message, by executing alternative actions. If the discard script does
+ nothing, the message is still discarded.
+
+M INSTALL
+M doc/example-config/conf.d/90-sieve.conf
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2016-09-30 23:55:25 +0200 Stephan Bosch <stephan@dovecot.fi> (bc99d792)
+
+ lib-sieve: Implemented support for running a "discard script" in the
+ multiscript execution API.
+
+ The "discard script" is run when the normal script sequence ends and the
+ message is going to be discarded.
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+
+2016-09-30 21:44:33 +0200 Stephan Bosch <stephan@dovecot.fi> (df19597c)
+
+ lib-sieve: Added means to evaluate whether the result object executed a
+ delivery action.
+
+
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2016-09-30 19:37:25 +0200 Stephan Bosch <stephan@dovecot.fi> (8f959e8f)
+
+ LDA Sieve plugin: Always use multiscript API for script execution.
+
+ Removed special code path for single script. This is a remnant from times
+ when the multiscript feature was still experimental.
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2016-09-29 21:23:51 +0200 Stephan Bosch <stephan@dovecot.fi> (67c93ffd)
+
+ lib-sieve: vnd.dovecot.environment extension: Added vnd.dovecot.config.*
+ environment items.
+
+ A "vnd.dovecot.config.<identifier>" environment item maps to the content of
+ the matching sieve_env_<identifier> plugin setting.
+
+M INSTALL
+A doc/extensions/vnd.dovecot.environment.txt
+M doc/rfc/spec-bosch-sieve-dovecot-environment.txt
+M doc/rfc/xml/spec-bosch-sieve-dovecot-environment.xml
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-items.c
+M tests/extensions/vnd.dovecot/environment/basic.svtest
+
+2016-10-04 19:59:03 +0200 Stephan Bosch <stephan.bosch@dovecot.fi> (c9324ac9)
+
+ lib-sieve: environment extension: Improved runtime trace for a nonexistent
+ environment item.
+
+
+M src/lib-sieve/plugins/environment/tst-environment.c
+
+2016-09-29 21:21:50 +0200 Stephan Bosch <stephan@dovecot.fi> (2865e415)
+
+ lib-sieve: environment extension: Added support for wildcard environment
+ items that are identified by a name prefix.
+
+
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-items.c
+M src/plugins/imapsieve/ext-imapsieve-environment.c
+
+2016-09-29 23:39:42 +0200 Stephan Bosch <stephan@dovecot.fi> (1bca1af3)
+
+ lib-sieve: variables extension: Substitution of an invalid namespace
+ canceled the substitution, rather than substituting the empty string.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+
+2016-09-29 23:37:50 +0200 Stephan Bosch <stephan@dovecot.fi> (da1ed8d9)
+
+ lib-sieve: variables extension: Increased the maximum number of namespace
+ elements in a variable name.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+
+2016-09-21 21:41:25 +0200 Stephan Bosch <stephan@dovecot.fi> (47635d88)
+
+ lib-sieve: file storage: Fixed handling of non-blocking input in
+ save_continue().
+
+ Bug was exposed by previous change. Normally, this would not surface.
+
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+
+2016-09-21 21:33:58 +0200 Stephan Bosch <stephan@dovecot.fi> (2ce32c4c)
+
+ managesieve: The PUTSCRIPT command now allows uploading empty Sieve scripts.
+
+ There is no reason to forbid an empty Sieve script.
+
+M src/managesieve/cmd-putscript.c
+
+2016-09-20 09:35:38 -0400 Josef 'Jeff' Sipek <jeff.sipek@dovecot.fi> (a4348748)
+
+ doveadm-sieve: Update attribute API usage
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+
+2016-08-28 23:40:30 +0200 Stephan Bosch <stephan@dovecot.fi> (4a5c2ce4)
+
+ Adjusted client_read_string_args() prototype to handle CLang warning.
+
+ Clang -Wvargargs complained about passing a bool argument to va_start().
+
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/cmd-setactive.c
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+
+2016-08-26 01:44:23 +0200 Stephan Bosch <stephan@dovecot.fi> (8a2ef99d)
+
+ lib-sieve: ldap storage: Fixed bool vs. int mixup in function call.
+
+ Found with clang -Wstrict-bool.
+
+M src/lib-sieve/storage/ldap/sieve-ldap-storage-settings.c
+
+2016-08-21 12:07:34 +0200 Stephan Bosch <stephan@rename-it.nl> (930ec524)
+
+ lib-sieve: Fixed various bool vs. int/pointer mixups.
+
+ Found with clang -Wstrict-bool.
+
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-storage.c
+M src/lib-sieve/sieve-stringlist.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/tst-exists.c
+
+2016-08-21 12:05:55 +0200 Stephan Bosch <stephan@rename-it.nl> (cab5eff7)
+
+ doveadm sieve plugin: Removed unused 'subscriptions' field from command
+ context.
+
+ Addresses a FIXME. Caused a warning with clang -Wstrict-bool.
+
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd.h
+
+2016-08-21 12:05:05 +0200 Stephan Bosch <stephan@rename-it.nl> (0929a400)
+
+ extprograms plugin: Fixed various bool vs. int mixups.
+
+ Found with clang -Wstrict-bool.
+
+M src/plugins/sieve-extprograms/cmd-execute.c
+M src/plugins/sieve-extprograms/cmd-filter.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+
+2016-08-21 12:02:20 +0200 Stephan Bosch <stephan@rename-it.nl> (ec02e3b5)
+
+ managesieve: Fixed various bool vs. int mixups.
+
+ Found with clang -Wstrict-bool.
+
+M src/managesieve/managesieve-client.c
+
+2016-08-21 12:01:29 +0200 Stephan Bosch <stephan@rename-it.nl> (ee3a6554)
+
+ lib-sieve: util: program-client: Fixed a bool vs. int/pointer mixup.
+
+ Found with clang -Wstrict-bool.
+
+M src/lib-sieve/util/program-client.c
+
+2016-08-21 11:58:41 +0200 Stephan Bosch <stephan@rename-it.nl> (8e0367b0)
+
+ lib-sieve: file storage: The try_hardlink parameter of file_copy() is of
+ type bool, rather than int.
+
+ Found with clang -Wstrict-bool.
+
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+
+2016-08-21 11:57:16 +0200 Stephan Bosch <stephan@rename-it.nl> (a010c390)
+
+ lib-sieve: The return type of duplicate_check() is supposed to be bool
+ rather than int.
+
+ Found with clang -Wstrict-bool.
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-types.h
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+
+2016-08-21 11:52:55 +0200 Stephan Bosch <stephan@rename-it.nl> (b0b9e0a5)
+
+ lib-sieve: script: The return type of binary_dump_metadata() is supposed to
+ be bool rather than int.
+
+ Found with clang -Wstrict-bool.
+
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/storage/dict/sieve-dict-script.c
+M src/lib-sieve/storage/ldap/sieve-ldap-script.c
+
+2016-08-21 11:46:15 +0200 Stephan Bosch <stephan@rename-it.nl> (6a6f7309)
+
+ sieve-filter: Fixed a bool vs. int mixup.
+
+ Found with clang -Wstrict-bool.
+
+M src/sieve-tools/sieve-filter.c
+
+2016-08-21 11:44:50 +0200 Stephan Bosch <stephan@rename-it.nl> (86eb7c95)
+
+ testsuite: Fixed various bool vs. int mixups.
+
+ Found with clang -Wstrict-bool.
+
+M src/testsuite/cmd-test-message.c
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-script.c
+
+2016-08-21 11:37:12 +0200 Stephan Bosch <stephan@rename-it.nl> (ae255494)
+
+ lib-sieve: reject extension: Fixed varius bool vs. int mixups.
+
+ Found with clang -Wstrict-bool.
+
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+
+2016-08-21 11:28:32 +0200 Stephan Bosch <stephan@rename-it.nl> (d8331c81)
+
+ lib-sieve: vacation extension: Fixed invalid evaluation of the
+ mail_get_headers() return value.
+
+ Found with clang -Wstrict-bool.
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2016-08-21 11:27:37 +0200 Stephan Bosch <stephan@rename-it.nl> (d2fa7208)
+
+ lib-sieve: regex extension: Fixed invalid use of sieve_ast_stringlist_map().
+
+ Mixed up bool and int return types. Found with clang -Wstrict-bool.
+
+M src/lib-sieve/plugins/regex/mcht-regex.c
+
+2016-08-21 11:25:57 +0200 Stephan Bosch <stephan@rename-it.nl> (dabacd9a)
+
+ lib-sieve: deprecated notify extension: Fixed various bool vs. int/pointer
+ mixups.
+
+ Found with clang -Wstrict-bool.
+
+M src/lib-sieve/plugins/notify/cmd-notify.c
+
+2016-08-21 11:24:35 +0200 Stephan Bosch <stephan@rename-it.nl> (f95c6c0c)
+
+ lib-sieve: metadata extension: Fixed invalid use of
+ sieve_ast_stringlist_map().
+
+ Mixed up bool and int return types. Found with clang -Wstrict-bool.
+
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+
+2016-08-21 11:23:03 +0200 Stephan Bosch <stephan@rename-it.nl> (01f7d9f3)
+
+ lib-sieve: mailbox extension: Fixed invalid use of
+ sieve_ast_stringlist_map().
+
+ Mixed up bool and int return types. Found with clang -Wstrict-bool.
+
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+
+2016-08-21 11:21:39 +0200 Stephan Bosch <stephan@rename-it.nl> (e180373f)
+
+ lib-sieve: index extension: Fixed a bool vs. int mixup.
+
+ Found with clang -Wstrict-bool.
+
+M src/lib-sieve/plugins/index/tag-index.c
+
+2016-08-21 11:20:54 +0200 Stephan Bosch <stephan@rename-it.nl> (13485c33)
+
+ lib-sieve: include extension: Fixed various bool vs. int mixups.
+
+ Found with clang -Wstrict-bool.
+
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2016-08-21 11:19:30 +0200 Stephan Bosch <stephan@rename-it.nl> (dc60b279)
+
+ lib-sieve: enotify extension: Fixed various bool vs. int/pointer mixups.
+
+ Found with clang -Wstrict-bool.
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+
+2016-08-21 11:16:27 +0200 Stephan Bosch <stephan@rename-it.nl> (5ef69ddc)
+
+ lib-sieve: match types: Fixed match function return values to be int rather
+ than bool.
+
+ Found with clang -Wstrict-bool.
+
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+
+2016-08-21 11:13:43 +0200 Stephan Bosch <stephan@rename-it.nl> (02d0b7ff)
+
+ lib-sieve: encoded-character extension: Fixed function return types to be
+ bool rather than int.
+
+ Found with clang -Wstrict-bool.
+
+M src/lib-sieve/ext-encoded-character.c
+
+2016-08-21 11:11:45 +0200 Stephan Bosch <stephan@rename-it.nl> (b800fc1c)
+
+ lib-managesieve: managesieve-parser: Fixed function return types to be bool
+ rather than int.
+
+ Found with clang -Wstrict-bool.
+
+M src/lib-managesieve/managesieve-parser.c
+
+2016-08-24 02:47:37 +0200 Stephan Bosch <stephan@dovecot.fi> (af91dd3f)
+
+ doveadm sieve plugin: sync: Fixed handling of unknown attribute timestamps.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+
+2016-08-24 01:22:12 +0200 Stephan Bosch <stephan@dovecot.fi> (ef268fec)
+
+ lib-sieve: util: program-client-remote: Fixed assert failure caused by
+ previous change.
+
+ Erroneously assumed the number of reserved bytes (for the return code) could
+ not decrease.
+
+M src/lib-sieve/util/program-client-remote.c
+
+2016-08-23 17:07:34 +0300 Aki Tuomi <aki.tuomi@dovecot.fi> (0dcee109)
+
+ tests/deprecated: Fix typo
+
+
+M tests/deprecated/imapflags/errors.svtest
+M tests/deprecated/notify/errors.svtest
+
+2016-08-16 14:29:53 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (d582f0db)
+
+ Adjust to unlink_directory() API changes.
+
+
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-smtp.c
+
+2016-08-20 03:32:58 +0200 Stephan Bosch <stephan@rename-it.nl> (6b02395c)
+
+ global: unsigned int:1 -> bool:1
+
+ perl -i -pe 's/unsigned int ([^,:;]+):1;/bool $1:1;/' **/*.[ch]
+
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/index/tag-index.c
+M src/lib-sieve/plugins/mime/tag-mime.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-storage-private.h
+M src/lib-sieve/sieve-stringlist.c
+M src/lib-sieve/sieve-stringlist.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/storage/dict/sieve-dict-script.c
+M src/lib-sieve/storage/file/sieve-file-script-sequence.c
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/lib-sieve/storage/ldap/sieve-ldap-script.c
+M src/lib-sieve/util/edit-mail.c
+M src/lib-sieve/util/program-client-private.h
+M src/lib-sieve/util/program-client-remote.c
+M src/lib-sieve/util/program-client.h
+M src/managesieve-login/client.h
+M src/managesieve/cmd-getscript.c
+M src/managesieve/managesieve-client.h
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-delete.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-put.c
+M src/plugins/imapsieve/imap-sieve-storage.c
+M src/plugins/imapsieve/imap-sieve.c
+M src/sieve-tools/sieve-filter.c
+
+2016-08-19 23:05:27 +0200 Stephan Bosch <stephan@dovecot.fi> (0adb7400)
+
+ lib-sieve: util: program-client-remote: Made the program_client_istream
+ implementation cleaner and more logical.
+
+ It was too hard to understand.
+
+M src/lib-sieve/util/program-client-remote.c
+
+2016-08-19 23:02:32 +0200 Stephan Bosch <stephan@dovecot.fi> (351bb053)
+
+ lib-sieve: util: program-client: Fixed position of the seekable stream for
+ the output of remote programs.
+
+ It would now make the output of the script service seekable, rather than the
+ output of the program. This adds a '+' at the end of the data. This showed
+ up for the extprograms filter command.
+
+M src/lib-sieve/util/program-client.c
+
+2016-08-19 01:24:21 +0200 Stephan Bosch <stephan@dovecot.fi> (36614104)
+
+ sieve-test: Forgot to disable error handling for dummy SMTP output stream.
+
+
+M src/sieve-tools/sieve-test.c
+
+2016-08-14 19:13:13 +0300 Martti Rannanjärvi <martti.rannanjarvi@dovecot.fi> (a920da2a)
+
+ lib-sieve: remove set_cache_corrupted_reason from mail_vfuncs
+
+ set_cache_corrupted_reason was removed in core.
+
+M src/lib-sieve/util/edit-mail.c
+
+2016-08-13 18:43:04 +0200 Stephan Bosch <stephan@dovecot.fi> (97dcfb2f)
+
+ lib-sieve: relational extension: Replaced return statement with
+ i_unreached() in mcht_value_match_key().
+
+ Coverity still complained.
+
+M src/lib-sieve/plugins/relational/mcht-value.c
+
+2016-08-13 18:10:08 +0200 Stephan Bosch <stephan@dovecot.fi> (0edfe0c1)
+
+ lib-sieve: ldap storage: Removed useless NULL checks.
+
+ Caused minor complaints by Coverity.
+
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+
+2016-08-13 17:42:03 +0200 Stephan Bosch <stephan@dovecot.fi> (a6aa9d44)
+
+ lib-sieve: relational extension: Removed dead default in switch statement.
+
+ Minor complaint by Coverity.
+
+M src/lib-sieve/plugins/relational/mcht-value.c
+
+2016-08-13 17:26:56 +0200 Stephan Bosch <stephan@dovecot.fi> (53eee4d9)
+
+ imapsieve plugin: Fixed potential segfault bug caused by shadowing a
+ parameter with a local variable.
+
+ Renamed the local variable. Found by Coverity.
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2016-08-13 14:42:31 +0300 Martti Rannanjärvi <martti.rannanjarvi@dovecot.fi> (54eb6fb7)
+
+ lib-sieve: MAIL_FETCH_UIDL_FILE_NAME to MAIL_FETCH_STORAGE_ID:
+
+ MAIL_FETCH_UIDL_FILE_NAME was removed from core.
+
+M src/lib-sieve/util/edit-mail.c
+
+2016-08-11 03:17:36 +0200 Stephan Bosch <stephan@dovecot.fi> (886199dd)
+
+ Fixed copyright notices.
+
+
+M src/lib-sieve/plugins/mime/cmd-extracttext.c
+M src/lib-sieve/plugins/mime/ext-extracttext.c
+
+2016-08-10 20:38:05 +0300 Aki Tuomi <aki.tuomi@dovecot.fi> (e246fe9d)
+
+ imapsieve: Update mailbox_attribute API usage
+
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2016-08-10 20:20:57 +0300 Aki Tuomi <aki.tuomi@dovecot.fi> (0b8386aa)
+
+ doveadm-sieve: Update attribute API
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+
+2016-08-10 11:32:04 +0200 Stephan Bosch <stephan@dovecot.fi> (2987a3c2)
+
+ imapsieve plugin: Fixed crash occurring when a mailbox is opened for a user
+ before the imap client object is created.
+
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2016-08-10 11:27:40 +0200 Stephan Bosch <stephan@dovecot.fi> (0e8abe2c)
+
+ imapsieve plugin: Removed spurious pool field from imap_sieve_user struct.
+
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2016-08-02 23:41:11 +0200 Stephan Bosch <stephan@dovecot.fi> (670e029a)
+
+ lib-sieve: program client: Changed I/O to use o_stream_send_istream() where
+ possible.
+
+ This simplifies the code significantly. This also removes calls to
+ i_stream_get_data(), which caused problems after its semantics were changed
+ in Dovecot.
+
+M src/lib-sieve/util/program-client.c
+
+2016-08-02 19:39:15 +0200 Stephan Bosch <stephan@dovecot.fi> (18338b4b)
+
+ lib-sieve: lexer: Adjusted to Dovecot change: i_stream_get_data() no longer
+ returns NULL when returned size = 0.
+
+
+M src/lib-sieve/sieve-lexer.c
+
+2016-05-20 15:38:31 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (d6cacfef)
+
+ Use i_unlink() to improve unexpected unlink() error messages.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/lib-sieve/util/program-client.c
+M src/sieve-tools/sieve-test.c
+
+2016-07-15 01:32:01 +0200 Stephan Bosch <stephan@rename-it.nl> (1521447e)
+
+ Removed the test suite's valgrind handling in favor of the generic
+ implementation Dovecot provides.
+
+
+M .gitignore
+M Makefile.am
+M configure.ac
+M dovecot-pigeonhole.m4
+
+2016-07-14 21:50:34 +0200 Stephan Bosch <stephan@rename-it.nl> (814ef928)
+
+ Add flags in DOVECOT_BINARY_CFLAGS and DOVECOT_BINARY_LDFLAGS to all
+ binaries.
+
+ In effect, this adds PIE and RELRO to binaries.
+
+M configure.ac
+M src/managesieve-login/Makefile.am
+M src/managesieve/Makefile.am
+M src/sieve-tools/Makefile.am
+
+2016-07-14 23:09:34 +0200 Stephan Bosch <stephan@rename-it.nl> (1f157d0f)
+
+ lib-managesieve: Use libtool.
+
+
+M src/lib-managesieve/Makefile.am
+M src/managesieve-login/Makefile.am
+M src/managesieve/Makefile.am
+
+2016-07-14 21:50:20 +0200 Stephan Bosch <stephan@rename-it.nl> (91368343)
+
+ Updated dovecot.m4.
+
+
+M m4/dovecot.m4
+
+2016-07-07 21:52:05 +0200 Stephan Bosch <stephan@rename-it.nl> (66b7c14c)
+
+ extprograms plugin: Clarified the language specification regarding handling
+ of filter and execute errors.
+
+
+M doc/rfc/spec-bosch-sieve-extprograms.txt
+M doc/rfc/xml/spec-bosch-sieve-extprograms.xml
+
+2016-07-07 18:25:29 +0200 Stephan Bosch <stephan@dovecot.fi> (3fa08e71)
+
+ extprograms plugin: Added tests for invocation of unknown programs.
+
+
+M tests/plugins/extprograms/execute/errors.svtest
+A tests/plugins/extprograms/execute/errors/unknown-program.sieve
+M tests/plugins/extprograms/filter/errors.svtest
+A tests/plugins/extprograms/filter/errors/unknown-program.sieve
+M tests/plugins/extprograms/pipe/errors.svtest
+A tests/plugins/extprograms/pipe/errors/unknown-program.sieve
+
+2016-07-07 18:24:16 +0200 Stephan Bosch <stephan@dovecot.fi> (60f4960a)
+
+ extprograms plugin: For directly forked programs, the "program not found"
+ was reported twice.
+
+
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+
+2016-07-07 18:18:35 +0200 Stephan Bosch <stephan@dovecot.fi> (efef641a)
+
+ extprograms plugin: Execution errors in filter and execute commands did not
+ lead to script termination.
+
+
+M src/plugins/sieve-extprograms/cmd-execute.c
+M src/plugins/sieve-extprograms/cmd-filter.c
+
+2016-07-07 10:15:15 +0200 Stephan Bosch <stephan@dovecot.fi> (70c27283)
+
+ lib-sieve: program client: Fixed bug in handling of result code from remote
+ program (script service).
+
+ It was sometimes passed through as data, meaning that the result code was
+ missed. This transiently resulted in programs seemingly returning invalid
+ result codes, causing an error.
+
+M src/lib-sieve/util/program-client-remote.c
+
+2016-07-07 01:23:27 +0200 Stephan Bosch <stephan@dovecot.fi> (aabde88b)
+
+ lib-sieve: program client: Connection to remote program service was not
+ retried.
+
+
+M src/lib-sieve/util/program-client-remote.c
+
+2016-07-06 21:15:19 +0200 Stephan Bosch <stephan@dovecot.fi> (807c61c2)
+
+ lib-sieve: vacation extension: The sieve_user_email setting is now used in
+ check for implicit delivery.
+
+ This means that vacation responses are now also sent for messages that
+ include the sieve_user_email address in one of the relevant headers.
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M tests/extensions/vacation/reply.svtest
+
+2016-07-06 20:31:35 +0200 Stephan Bosch <stephan@dovecot.fi> (cefa449a)
+
+ testsuite: Removed spurious test_message_print statements.
+
+
+M tests/execute/address-normalize.svtest
+
+2016-07-06 20:26:50 +0200 Stephan Bosch <stephan@dovecot.fi> (467080db)
+
+ lib-sieve: Fixed handling of quoted string localparts in email addresses.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve.c
+M src/testsuite/testsuite-message.c
+M tests/extensions/envelope.svtest
+
+2016-06-28 23:44:12 +0200 Stephan Bosch <stephan@rename-it.nl> (f9eda178)
+
+ lib-sieve: if command: Made static analyzer happier.
+
+ Added assertion to validation function.
+
+M src/lib-sieve/cmd-if.c
+
+2016-06-28 23:17:50 +0200 Stephan Bosch <stephan@rename-it.nl> (5673ee51)
+
+ lib-sieve: Make static analyzer happier about argument validation.
+
+ Added assertions.
+
+M src/lib-sieve/plugins/mime/tag-mime.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/sieve-validator.c
+
+2016-06-28 22:35:34 +0200 Stephan Bosch <stephan@rename-it.nl> (82592618)
+
+ lib-sieve: Make static analyzer happier about use of
+ sieve_ast_stringlist_map().
+
+ Added assertions.
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/tst-address.c
+
+2016-06-27 21:39:18 +0200 Stephan Bosch <stephan@rename-it.nl> (e2aa3166)
+
+ dovecot-pigeonhole.m4: Make testsuite available when linked against
+ Pigeonhole source tree, even when it is not yet compiled.
+
+
+M dovecot-pigeonhole.m4
+
+2016-06-23 13:30:49 +0200 Stephan Bosch <stephan@dovecot.fi> (9e6e5ee0)
+
+ imapsieve plugin: During transaction run the synchronized version of the
+ target mailbox was opened too early.
+
+ This meant opening a mailbox a second time even if it did not match any
+ mailbox rules.
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2016-06-21 02:54:36 +0200 Stephan Bosch <stephan@rename-it.nl> (f3944c69)
+
+ lib-sieve: edit-mail: Passed FALSE for normalizer argument of
+ message_header_decode_utf8() rather than NULL.
+
+
+M src/lib-sieve/util/edit-mail.c
+
+2016-06-21 02:54:00 +0200 Stephan Bosch <stephan@rename-it.nl> (7860911b)
+
+ lib-sieve: variables extesnion: Fixed instances where FALSE was returned
+ rather than NULL.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+
+2016-06-21 02:50:29 +0200 Stephan Bosch <stephan@rename-it.nl> (f6b6815a)
+
+ lib-sieve: enotify extension: Fixed instances where FALSE was returned
+ rather than NULL.
+
+
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+
+2016-06-20 23:39:09 +0200 Stephan Bosch <stephan@rename-it.nl> (69296a11)
+
+ imapsieve plugin: Restructured imap_sieve_run_scripts() function such that
+ the compile error code is never used uninitialized.
+
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2016-06-20 23:08:09 +0200 Stephan Bosch <stephan@rename-it.nl> (561d0adc)
+
+ lib-sieve: address test: Mixed up bool and int for
+ sieve_ast_stringlist_map() return type.
+
+
+M src/lib-sieve/tst-address.c
+
+2016-06-20 22:48:06 +0200 Stephan Bosch <stephan@rename-it.nl> (358e40db)
+
+ imapsieve plugin: Prevent possible NULL pointer dereference at transaction
+ commit.
+
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2016-06-20 22:40:50 +0200 Stephan Bosch <stephan@rename-it.nl> (44316d49)
+
+ lib-sieve: envelope extension: Mixed up bool and int for
+ sieve_ast_stringlist_map() return type.
+
+
+M src/lib-sieve/ext-envelope.c
+
+2016-06-20 22:32:32 +0200 Stephan Bosch <stephan@rename-it.nl> (f3e53764)
+
+ imapsieve plugin: Removed dead assignment reported by scan-build.
+
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2016-06-20 22:20:32 +0200 Stephan Bosch <stephan@rename-it.nl> (a16a9b8b)
+
+ lib-sieve: variables extension: Changed declaration of new variables to
+ avoid useless memory allocation.
+
+ Also prevents assert failures with new hash_table_insert() assertion against
+ existing entries. This changes the API for the variables extension.
+
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2016-06-20 21:52:17 +0200 Stephan Bosch <stephan@rename-it.nl> (45d4fa9d)
+
+ lib-sieve: Require blocking message stream for sieve_message_substitute().
+
+ This prevents trouble with o_stream_nsend_istream() later.
+
+M src/lib-sieve/sieve-message.c
+M src/plugins/sieve-extprograms/cmd-filter.c
+
+2016-06-20 21:14:11 +0200 Stephan Bosch <stephan@rename-it.nl> (8091baf4)
+
+ lib-sieve: Changed sieve_extension_override() to use hash_table_update()
+ rather than hash_table_insert().
+
+ Due to a Dovecot change this would now cause an assertion failure.
+
+M src/lib-sieve/sieve-extensions.c
+
+2016-06-20 20:53:47 +0200 Stephan Bosch <stephan@rename-it.nl> (5931b69e)
+
+ managesieve-login: proxy: Did not handle zero return value from
+ managesieve_parser_read_args() correctly.
+
+
+M src/managesieve-login/managesieve-proxy.c
+
+2016-06-13 22:06:55 +0200 Stephan Bosch <stephan@dovecot.fi> (167ca91b)
+
+ lib-sieve: Handle duplicate registrations of capabilities better.
+
+ This would uselessly allocate a new entry with the same content.
+
+M src/lib-sieve/sieve-extensions.c
+
+2016-06-13 21:59:45 +0200 Stephan Bosch <stephan@dovecot.fi> (9cdc454e)
+
+ lib-sieve: variables extensions: Fixed handling of importing a variable into
+ a scope that is already imported earlier.
+
+ This allocated a new variable entry every time.
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+
+2016-06-13 21:41:49 +0200 Stephan Bosch <stephan@dovecot.fi> (74f60b97)
+
+ sieve-tools: Disable automatic data stack frame initialization.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+
+2016-05-20 15:32:51 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (1ddbb32e)
+
+ Adjusted to changes in o_stream_send_istream() API
+
+
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/managesieve/cmd-getscript.c
+
+2016-06-09 19:21:53 +0300 Aki Tuomi <aki.tuomi@dovecot.fi> (5e492476)
+
+ pigeonhole: Remove autoclose parameter
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/lib-sieve/util/program-client.c
+M src/managesieve/managesieve-client.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-result.c
+
+2016-05-31 02:56:26 +0200 Stephan Bosch <stephan@rename-it.nl> (67dfb5a2)
+
+ Previous change omitted one occurrence of t_malloc().
+
+
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+
+2016-05-11 10:19:00 +0300 Martti Rannanjärvi <martti.rannanjarvi@dovecot.fi> (3d1226b5)
+
+ Replace t_malloc with t_malloc0 or t_malloc_no0
+
+ Plain t_malloc was deprecated in dovecot.
+
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/util/program-client-local.c
+M src/managesieve/managesieve-client.c
+
+2016-05-16 21:02:09 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (e2d6a03d)
+
+ Use o_stream_nsend*() to make sure write errors are caught.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve.c
+M src/managesieve-login/managesieve-proxy.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-smtp.c
+
+2016-05-16 16:08:41 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (69cce444)
+
+ managesieve: Adjust to new o_stream_send_istream() API
+
+
+M src/managesieve/cmd-getscript.c
+
+2016-05-18 15:23:18 +0200 Stephan Bosch <stephan@dovecot.fi> (b3f5d771)
+
+ Adjusted to changes in Dovecot buffer API.
+
+
+M src/lib-sieve/sieve-binary.c
+
+2016-05-18 00:31:27 +0200 Stephan Bosch <stephan@rename-it.nl> (634b16b3)
+
+ lib-sieve: ldap storage: Fixed compiler warning occurring under specific
+ configuration conditions.
+
+
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+
+2016-05-18 00:25:24 +0200 Stephan Bosch <stephan@rename-it.nl> (5f4db18f)
+
+ doveadm-sieve: Fixed copy-paste stupidity in previous change.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-delete.c
+
+2016-05-18 00:09:28 +0300 Aki Tuomi <aki.tuomi@dovecot.fi> (b47c3a06)
+
+ doveadm-sieve: Update to ver2 structures
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-activate.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-delete.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-get.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-list.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-put.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-rename.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd.h
+
+2016-05-16 22:04:13 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (2c0aa0f0)
+
+ Replaced i_stream_read_data() calls with _read_bytes and _read_more()
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/util/program-client-remote.c
+M src/lib-sieve/util/program-client.c
+M src/managesieve-login/client-authenticate.c
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+M src/testsuite/cmd-test-message.c
+
+2016-05-15 14:42:49 +0200 Stephan Bosch <stephan@dovecot.fi> (8ab4f24c)
+
+ managesieve: Avoid crashing at deinit if mail_user_unref() triggers
+ mail_storage_callbacks
+
+ This could have happened with Maildir/mbox and autoexpunging. Mimics
+ Dovecot/IMAP change ddffbb277e212adb9d594b3d7d1e1d39fa78f7c6.
+
+M src/managesieve/managesieve-client.c
+
+2016-05-15 14:38:05 +0200 Stephan Bosch <stephan@dovecot.fi> (cafb21eb)
+
+ managesieve: Free mail_user only after client is disconnected.
+
+ Mimics Dovecot/IMAP change 1001bda65e9f592d852a26ddd6a993f7973050bf.
+
+M src/managesieve/managesieve-client.c
+
+2016-03-22 10:13:19 -0400 Aaron Lindsay <aaron@aclindsay.com> (dd0f8d1a)
+
+ subaddress: Support multiple recipient_delimiters
+
+ The recipient_delimiter is treated as multiple one-character delimiters
+ rather than one multi-character delimiter if more than one character is
+ supplied.
+
+ Based on a patch by: Lennart Weller <lhw@ring0.de>
+
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M tests/extensions/subaddress/config.svtest
+
+2016-05-09 23:12:43 +0200 Stephan Bosch <stephan@rename-it.nl> (daf1c25c)
+
+ lib-sieve: program client: Significantly improved error handling.
+
+ Stream errors were never logged properly. Streams now have a name that makes
+ sense. Timeout errors were handled in a rather stupid fashion.
+
+M src/lib-sieve/util/program-client-local.c
+M src/lib-sieve/util/program-client-private.h
+M src/lib-sieve/util/program-client-remote.c
+M src/lib-sieve/util/program-client.c
+
+2016-05-09 22:27:45 +0200 Stephan Bosch <stephan@rename-it.nl> (64ac8433)
+
+ lib-sieve: Fixed error handling for mail streams.
+
+ The previous change prompted some futher code review and similar
+ improvements/fixes were applied at various places in the code.
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+M src/lib-sieve/sieve-message.c
+
+2016-05-09 16:05:37 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (a66812ae)
+
+ lib-sieve: edit mail wasn't didn't handle truncated header correctly.
+
+ If header was truncated, it was treated as an istream error. Also the
+ istream read errors weren't logged.
+
+M src/lib-sieve/util/edit-mail.c
+
+2016-05-06 17:40:25 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (495393c5)
+
+ Adjusted to changes in Dovecot lib-dict API.
+
+
+M src/lib-sieve/storage/dict/sieve-dict-script.c
+M src/lib-sieve/storage/dict/sieve-dict-storage.c
+
+2016-05-04 02:20:17 +0200 Stephan Bosch <stephan@rename-it.nl> (f7f206d5)
+
+ configure: Changed version number to v0.5.devel.
+
+
+M configure.ac
+
+2016-05-02 17:09:12 +0300 Timo Sirainen <timo.sirainen@dovecot.fi> (641fa414)
+
+ testsuite: Adjusted to changes in Dovecot lib-storage API.
+
+
+M src/testsuite/testsuite-mailstore.c
+
+2016-05-02 18:08:59 +0200 Stephan Bosch <stephan@rename-it.nl> (6b436b4f)
+
+ Changed Makefile.am to make sure test suite is executed at `make check'.
+
+
+M Makefile.am
+
+2016-05-02 17:49:05 +0200 Stephan Bosch <stephan@rename-it.nl> (2dc13c59)
+
+ Merged concurrent changes.
+
+
+2016-04-28 23:02:38 +0200 Stephan Bosch <stephan@dovecot.fi> (b9e567b5)
+
+ lib-sieve: Handle extension overriding itself properly.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2016-04-26 22:36:43 +0200 Stephan Bosch <stephan@rename-it.nl> (850d80b2)
+
+ Updated README with availability of vnd.dovecot.report extension.
+
+
+M README
+
+2016-04-26 21:51:46 +0200 Stephan Bosch <stephan@rename-it.nl> (7c79cdc8)
+
+ Added v0.4.13 to NEWS.
+
+
+M NEWS
+
+2016-04-26 21:34:15 +0200 Stephan Bosch <stephan@rename-it.nl> (c984322f)
+
+ lib-sieve: edit-mail: Removed useless NULL check in
+ edit_mail_istream_seek().
+
+ This caused a Coverity defect report.
+
+M src/lib-sieve/util/edit-mail.c
+
+2016-04-26 21:27:08 +0200 Stephan Bosch <stephan@rename-it.nl> (0b04d67d)
+
+ lib-sieve: vnd.dovecot.report extension: Removed logically dead code.
+
+ This caused Coverity defect reports.
+
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+
+2016-04-26 21:19:06 +0200 Stephan Bosch <stephan@rename-it.nl> (dfe0d52c)
+
+ lib-sieve: validator: Fixed potential NULL dereference in
+ sieve_validator_extensions_check_conficts().
+
+ Would only happen with dummy/internal `extensions' that have no valid ID.
+ This caused a Coverity defect report.
+
+M src/lib-sieve/sieve-validator.c
+
+2016-04-26 21:13:04 +0200 Stephan Bosch <stephan@rename-it.nl> (e25f31a3)
+
+ lib-sieve: validator: Fixed potential NULL dereference in
+ sieve_validator_extension_load().
+
+ Would only happen with dummy/internal `extensions' that have no valid ID.
+ This caused a Coverity defect report.
+
+M src/lib-sieve/sieve-validator.c
+
+2016-04-26 21:09:12 +0200 Stephan Bosch <stephan@rename-it.nl> (504a08ae)
+
+ lib-sieve: redirect command: Removed useless NULL check in loop detection.
+
+ This caused a coverity defect report.
+
+M src/lib-sieve/cmd-redirect.c
+
+2016-04-19 00:27:09 +0200 Stephan Bosch <stephan@rename-it.nl> (ef25ce69)
+
+ imapsieve plugin: Do not initialize mailbox rules until they are needed.
+
+ Otherwise, these would be re-parsed every time a new mail_user is created
+ (e.g. when opening a mail as raw).
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2016-04-18 22:46:03 +0200 Stephan Bosch <stephan@rename-it.nl> (6af702e3)
+
+ lib-sieve: redirect action: Sender address was not always correctly
+ assigned.
+
+ This should have provoked a compiler warning.
+
+M src/lib-sieve/cmd-redirect.c
+
+2016-04-18 22:40:47 +0200 Stephan Bosch <stephan@rename-it.nl> (c8d1f17a)
+
+ lib-sieve: Messed up indentation in earlier change.
+
+
+M src/lib-sieve/sieve.c
+
+2016-04-18 21:27:31 +0200 Stephan Bosch <stephan@rename-it.nl> (931adc13)
+
+ lib-sieve: The redirect action still partly depended on having an envelope
+ available.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2016-04-18 19:54:55 +0200 Stephan Bosch <stephan@rename-it.nl> (7949cc28)
+
+ lib-sieve: Implemented utility function that determines the primary email
+ address of the user.
+
+
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve.c
+M src/plugins/imapsieve/ext-imapsieve-environment.c
+
+2016-04-14 20:52:04 +0200 Stephan Bosch <stephan@dovecot.fi> (1b6fb01a)
+
+ lib-sieve: Don't add overridden built-in extensions to the capability list.
+
+ These are not available under that name anymore and when the replacing
+ extension has the same bare name, this would have led to duplicate
+ capabilities.
+
+M src/lib-sieve/sieve-extensions.c
+
+2016-04-14 20:51:04 +0200 Stephan Bosch <stephan@dovecot.fi> (cfb5ee27)
+
+ lib-sieve: When overriding a built-in extension, the wrong extension was
+ marked as overridden.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2016-04-10 03:41:48 +0200 Stephan Bosch <stephan@dovecot.fi> (215349a4)
+
+ lib-sieve: deprecated notify: Removed dependencies on availability of
+ message envelope.
+
+
+M src/lib-sieve/plugins/notify/cmd-notify.c
+
+2016-04-09 23:16:06 +0200 Stephan Bosch <stephan@dovecot.fi> (04d86b2f)
+
+ lib-sieve: vnd.dovecot.report extension: Made the report action behave
+ correctly when there is no envelope.
+
+
+M src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+
+2016-04-09 22:32:00 +0200 Stephan Bosch <stephan@dovecot.fi> (6015613a)
+
+ lib-sieve: enotify: mailto: Sending a notification still partly depended on
+ having an envelope available.
+
+
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+
+2016-04-09 22:11:35 +0200 Stephan Bosch <stephan@dovecot.fi> (0bcd59d7)
+
+ lib-sieve: Added a "sieve_user_email" setting that configures the user's
+ primary email address.
+
+ This is used mainly when no other means of obtaining the user's email is
+ available, such as when there is no envelope (in IMAP). Before, the
+ postmaster address or the null "<>" address was used as a fallback for
+ sending messages. The redirect and enotify commands can be explicitly
+ configured to use what is configured with sieve_user_email.
+
+M INSTALL
+M doc/example-config/conf.d/90-sieve.conf
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/sieve-address-source.c
+M src/lib-sieve/sieve-address-source.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-settings.c
+M tests/execute/smtp.svtest
+M tests/extensions/enotify/mailto.svtest
+
+2016-04-09 21:35:05 +0200 Stephan Bosch <stephan@dovecot.fi> (2e67f041)
+
+ lib-sieve: sieve-address-source: Fixed result initialization.
+
+ Used wrong type in sizeof().
+
+M src/lib-sieve/sieve-address-source.c
+
+2016-04-09 20:45:33 +0200 Stephan Bosch <stephan@dovecot.fi> (39713774)
+
+ lib-sieve: Made redirect and enotify/mailto handle the absence of an
+ envelope properly.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/sieve-address-source.c
+M src/lib-sieve/sieve-address-source.h
+
+2016-04-09 18:48:47 +0200 Stephan Bosch <stephan@dovecot.fi> (a3e2ad32)
+
+ lib-sieve: Moved resolution of sender address source to common location.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/sieve-address-source.c
+M src/lib-sieve/sieve-address-source.h
+M src/lib-sieve/sieve-common.h
+
+2016-04-09 18:09:32 +0200 Stephan Bosch <stephan@dovecot.fi> (674376cd)
+
+ lib-sieve: Created sieve_address_source for common handling of address
+ configuration.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/sieve-actions.c
+A src/lib-sieve/sieve-address-source.c
+A src/lib-sieve/sieve-address-source.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+
+2016-04-09 16:19:09 +0200 Stephan Bosch <stephan@dovecot.fi> (35f31bfc)
+
+ Updated README file regarding implementation status of IMAPSIEVE.
+
+
+M README
+
+2016-04-09 16:03:35 +0200 Stephan Bosch <stephan@dovecot.fi> (2e3f99c4)
+
+ lib-sieve: Made sure local part of a mail address is encoded properly using
+ quoted string when it is not a dot-atom.
+
+
+M Makefile.am
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+A tests/execute/address-normalize.svtest
+
+2016-04-09 13:53:10 +0200 Stephan Bosch <stephan@dovecot.fi> (dba245c0)
+
+ lib-sieve: Made parsing of explicit address for mail sender setting check
+ the address syntax.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-settings.c
+
+2016-04-07 21:31:55 +0200 Stephan Bosch <stephan@rename-it.nl> (7627b9f2)
+
+ Merge pull request #1 from sebix/x-original-to
+
+ lib-sieve: Allow X-Original-To header for the address test.
+2016-04-07 16:54:13 +0200 Stephan Bosch <stephan@rename-it.nl> (4e27a127)
+
+ Fix segfault bug caused by earlier trace log changes.
+
+ Trace_log variable was not initialized.
+
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2016-04-07 04:31:30 +0200 Stephan Bosch <stephan@rename-it.nl> (cd05a404)
+
+ Documented new trace debugging features.
+
+
+M INSTALL
+M doc/example-config/conf.d/90-sieve.conf
+
+2016-04-07 04:02:26 +0200 Stephan Bosch <stephan@rename-it.nl> (bb4b299e)
+
+ imapsieve plugin: Added trace logging support.
+
+
+M src/plugins/imapsieve/imap-sieve.c
+
+2016-04-07 04:01:07 +0200 Stephan Bosch <stephan@rename-it.nl> (c934cc42)
+
+ lda-sieve plugin: Added trace logging support.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2016-04-07 03:57:14 +0200 Stephan Bosch <stephan@rename-it.nl> (8b51e7c1)
+
+ lib-sieve: trace logging: Added optional file name label.
+
+ This way, imapsieve can show to which user.mailbox.uid the trace applies.
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+
+2016-04-07 03:55:07 +0200 Stephan Bosch <stephan@rename-it.nl> (6a8f7bdf)
+
+ lib-sieve: Implemented utility functions for configuring runtime trace
+ logging.
+
+
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+
+2016-04-06 23:23:42 +0200 Stephan Bosch <stephan@dovecot.fi> (905f66a3)
+
+ lib-sieve: Fixed crashes in extension conflict checking.
+
+ Registering conflicting commands before conflicts are checked is a bad idea.
+ Make sure conflicting extensions are not part of remaining validation
+ process.
+
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/sieve-validator.c
+M tests/deprecated/notify/errors.svtest
+M tests/deprecated/notify/errors/conflict-ihave.sieve
+
+2016-04-06 23:18:23 +0200 Stephan Bosch <stephan@dovecot.fi> (228855fc)
+
+ lib-sieve: Made command and argument error macros accept NULL for commands
+ and arguments.
+
+
+M src/lib-sieve/sieve-commands.h
+
+2016-04-06 00:56:07 +0200 Stephan Bosch <stephan@rename-it.nl> (ee860f97)
+
+ lib-sieve: Moved the algorithm for determining the user log file path to
+ lib-sieve.
+
+ This was duplicated between the lda-sieve and imapsieve plugins.
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/imapsieve/imap-sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2016-04-06 00:28:29 +0200 Stephan Bosch <stephan@rename-it.nl> (f95bab5c)
+
+ lib-sieve: Implemented support for writing runtime trace output to a
+ directory if it exists, much like Dovecot rawlog.
+
+
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite.c
+
+2016-04-05 21:35:22 +0200 Stephan Bosch <stephan@rename-it.nl> (684aa242)
+
+ doc/example-config: Added description for a few generic settings that were
+ only mentioned in the INSTALL file.
+
+
+M doc/example-config/conf.d/90-sieve.conf
+
+2016-04-05 21:21:12 +0200 Stephan Bosch <stephan@rename-it.nl> (2591cd15)
+
+ doc/man: The -u and -o options were undocumented for the sieve* tools.
+
+
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-filter.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+
+2016-04-05 11:43:36 +0200 Stephan Bosch <stephan@rename-it.nl> (0a191d4b)
+
+ lib-sieve: Make sure that an absent envelope does not cause segfaults.
+
+ Futher changes are needed to prevent accessing the envelope in the first
+ place.
+
+M src/lib-sieve/sieve-message.c
+
+2016-04-05 11:17:31 +0200 Stephan Bosch <stephan@rename-it.nl> (ebc95b51)
+
+ imapsieve plugin: storage: Forgot to free mailbox when there are no Sieve
+ scripts.
+
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2016-03-28 19:31:39 +0200 Stephan Bosch <stephan@rename-it.nl> (136c5b18)
+
+ test suite: Added some more ihave-related extension conflict tests.
+
+
+M tests/deprecated/imapflags/errors.svtest
+A tests/deprecated/imapflags/errors/conflict-ihave.sieve
+R100 tests/deprecated/imapflags/errors/imapflags.sieve tests/deprecated/imapflags/errors/conflict.sieve
+M tests/deprecated/notify/errors.svtest
+A tests/deprecated/notify/errors/conflict-ihave.sieve
+A tests/deprecated/notify/errors/conflict.sieve
+
+2016-03-27 23:48:44 +0200 Stephan Bosch <stephan@rename-it.nl> (cb2f60e3)
+
+ lib-sieve: Implemented the dovecot-specific "vnd.dovecot.report".
+
+ It allows sending feedback report (RFC 5965) messages.
+
+M Makefile.am
+M configure.ac
+A doc/rfc/spec-bosch-sieve-report.txt
+A doc/rfc/xml/reference.IMAPSIEVE.xml
+A doc/rfc/xml/reference.MARF.xml
+A doc/rfc/xml/reference.RFC.2045.xml
+A doc/rfc/xml/reference.RFC.3834.xml
+A doc/rfc/xml/spec-bosch-sieve-report.xml
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/vnd.dovecot/Makefile.am
+A src/lib-sieve/plugins/vnd.dovecot/report/Makefile.am
+A src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+A src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.c
+A src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.h
+A src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report.c
+M src/lib-sieve/sieve-extensions.c
+A tests/extensions/vnd.dovecot/report/errors.svtest
+A tests/extensions/vnd.dovecot/report/errors/syntax.sieve
+A tests/extensions/vnd.dovecot/report/execute.svtest
+
+2016-03-27 23:47:44 +0200 Stephan Bosch <stephan@rename-it.nl> (b1e2bbd7)
+
+ imapsieve plugins: Fixed compiler warning.
+
+
+M src/plugins/imapsieve/imap-sieve-storage.c
+
+2016-03-27 23:41:10 +0200 Stephan Bosch <stephan@rename-it.nl> (08c6a402)
+
+ Documented the new IMAPSIEVE plugins.
+
+
+M INSTALL
+A doc/plugins/imapsieve.txt
+A doc/rfc/imapsieve.rfc6785.txt
+M src/plugins/imapsieve/ext-imapsieve.c
+
+2016-03-27 16:44:20 +0200 Stephan Bosch <stephan@rename-it.nl> (dbe03ae2)
+
+ Implemented the imapsieve extension for Sieve and IMAP as a plugin.
+
+
+M TODO
+M configure.ac
+M src/plugins/Makefile.am
+A src/plugins/imapsieve/Makefile.am
+A src/plugins/imapsieve/ext-imapsieve-common.h
+A src/plugins/imapsieve/ext-imapsieve-environment.c
+A src/plugins/imapsieve/ext-imapsieve.c
+A src/plugins/imapsieve/imap-sieve-plugin.c
+A src/plugins/imapsieve/imap-sieve-plugin.h
+A src/plugins/imapsieve/imap-sieve-storage.c
+A src/plugins/imapsieve/imap-sieve-storage.h
+A src/plugins/imapsieve/imap-sieve.c
+A src/plugins/imapsieve/imap-sieve.h
+A src/plugins/imapsieve/sieve-imapsieve-plugin.c
+A src/plugins/imapsieve/sieve-imapsieve-plugin.h
+
+2016-03-27 16:41:20 +0200 Stephan Bosch <stephan@rename-it.nl> (b190d77b)
+
+ lib-sieve: Added support for running the Sieve interpreter without an
+ envelope.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-types.h
+
+2016-03-27 16:40:20 +0200 Stephan Bosch <stephan@rename-it.nl> (4dce44be)
+
+ lib-sieve: Added support for evaluating extension availability (ihave test)
+ at runtime.
+
+
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/ihave/cmd-error.c
+M src/lib-sieve/plugins/ihave/ext-ihave-common.h
+M src/lib-sieve/plugins/ihave/ext-ihave.c
+M src/lib-sieve/plugins/ihave/tst-ihave.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-validator.c
+M src/testsuite/testsuite-common.c
+
+2016-03-25 02:48:06 +0100 Stephan Bosch <stephan@rename-it.nl> (222c5af0)
+
+ lib-sieve: Notify extensions about whether they are loaded in the validator
+ optionally (ihave extension).
+
+
+M src/lib-sieve/plugins/duplicate/ext-duplicate.c
+M src/lib-sieve/plugins/ihave/tst-ihave.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/mime/ext-extracttext.c
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/plugins/sieve-extprograms/ext-pipe.c
+
+2016-03-25 01:47:49 +0100 Stephan Bosch <stephan@rename-it.nl> (ac77b22b)
+
+ lib-sieve: Improved handling of extension conflicts.
+
+ Conflicts are now always tested from both sides. This is mainly important
+ for the "ihave" test.
+
+M src/lib-sieve/plugins/duplicate/ext-duplicate.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/mime/ext-extracttext.c
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/plugins/sieve-extprograms/ext-pipe.c
+
+2016-03-23 02:41:46 +0100 Stephan Bosch <stephan@rename-it.nl> (a95b0579)
+
+ lib-sieve: program client: local: Destroy the output stream before the fd is
+ closed.
+
+ An earlier change exposed this bug. Before, it was always a socket, and
+ closing the output early meant using shutdown() rather than close(). This
+ bug caused an assert failure.
+
+M src/lib-sieve/util/program-client.c
+
+2016-03-21 20:57:29 +0100 Sebastian <sebix@sebix.at> (dee854ed)
+
+ Allow X-Original-To for address test
+
+
+M src/lib-sieve/tst-address.c
+
+2016-03-19 17:05:28 +0100 Stephan Bosch <stephan@rename-it.nl> (75e241fa)
+
+ lib-sieve: Added support for bluntly replacing extensions.
+
+
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+
+2016-03-19 17:04:28 +0100 Stephan Bosch <stephan@rename-it.nl> (aa5a9a93)
+
+ lib-sieve: Added execution flag that defers handling of keep to the caller.
+
+
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-types.h
+
+2016-03-19 17:03:28 +0100 Stephan Bosch <stephan@rename-it.nl> (fb69bc52)
+
+ lib-sieve: Renamed sieve_runtime_flags to sieve_execute_flags and made these
+ available to result execution.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-script.c
+
+2016-03-18 02:58:25 +0100 Stephan Bosch <stephan@rename-it.nl> (8d1b0810)
+
+ lib-sieve: util: Fixed message header composition functions to turn newlines
+ into proper header line continuations.
+
+
+M src/lib-sieve/util/rfc2822.c
+
+2016-03-09 22:11:21 +0100 Stephan Bosch <stephan@rename-it.nl> (1d36af65)
+
+ Documented the new sieve_implicit_extensions setting.
+
+
+M INSTALL
+
+2016-03-09 21:35:37 +0100 Stephan Bosch <stephan@rename-it.nl> (355dfd82)
+
+ Added v0.4.12 to NEWS.
+
+
+M NEWS
+
+2016-03-09 19:23:26 +0100 Stephan Bosch <stephan@rename-it.nl> (c2bca55b)
+
+ lib-sieve: redirect action: Made mail loop detection more robust by forcibly
+ adding a Message-ID header if it is missing.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2016-03-08 17:48:43 +0100 Stephan Bosch <stephan@rename-it.nl> (b188844f)
+
+ Merge branch 'master' of git.dovecot.net:pigeonhole/core
+
+
+2016-03-02 13:01:13 +0100 Stephan Bosch <stephan@rename-it.nl> (0cfa05d0)
+
+ Adjusted to changes in Dovecot lib-storage API/ABI.
+
+ Struct mail_vfuncs has an additional method now.
+
+M src/lib-sieve/util/edit-mail.c
+
+2016-02-29 18:05:37 +0100 Stephan Bosch <stephan@rename-it.nl> (75498e45)
+
+ doc/man: doveadm sieve: Clarified that the script name has no ".sieve"
+ extension.
+
+
+M doc/man/doveadm-sieve.1.in
+
+2016-02-29 13:26:29 +0100 Stephan Bosch <stephan@dovecot.fi> (5181c14c)
+
+ lib-sieve: validator: Prevent duplicate registration of persistent command
+ tags.
+
+
+M src/lib-sieve/sieve-validator.c
+
+2016-02-29 13:08:59 +0100 Stephan Bosch <stephan@dovecot.fi> (61780582)
+
+ lib-sieve: imap4flags: Created API for registering the implicit flags
+ side-effect with commands.
+
+ This is needed for other extensions that manipulate flags while the
+ imap4flags extension is not used directly.
+
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h
+
+2016-02-29 01:51:04 +0100 Stephan Bosch <stephan@rename-it.nl> (da266d81)
+
+ lib-sieve: redirect action: Added list-id header to the duplicate ID for
+ mail loop prevention.
+
+ This prevents a conflict between the message coming through a mailing list
+ and a copy of that message recieved directly. If both of these have the same
+ message ID, one of these messages would be discarded (or worse: delivered
+ locally) when redirected.
+
+M src/lib-sieve/cmd-redirect.c
+
+2016-02-27 13:28:37 +0100 Stephan Bosch <stephan@rename-it.nl> (93e501fe)
+
+ lib-sieve: Omit logging message for "script not found" during normal script
+ compile.
+
+ The caller will normally handle this and it will handle it better with more
+ context information. This also produced a spurious "script not found" error
+ message when an entry but no attribute existed for an LDAP-based Sieve
+ script.
+
+M src/lib-sieve/sieve.c
+
+2016-02-27 13:28:22 +0100 Stephan Bosch <stephan@rename-it.nl> (2be3992e)
+
+ lib-sieve: ldap storage: Clarified "script not found" errors a bit so that
+ it is clear at which stage it occurrs.
+
+
+M src/lib-sieve/storage/ldap/sieve-ldap-script.c
+
+2016-02-22 20:53:46 +0100 Stephan Bosch <stephan@rename-it.nl> (d28957f5)
+
+ lib-sieve: util: program-client-local: Changed link between parent and child
+ process from a socketpair to a double pipe.
+
+ Turns out /dev/stdin, /dev/stdout, and /dev/fd/XX don't work on Linux if the
+ underlying FD is a socket. Since some programs may rely on those symbolic
+ links to work, the local client is amended to use two pipes instead. This
+ will not help for programs invoked in the remote script service, since a
+ socket is required for the connection.
+
+M src/lib-sieve/util/program-client-local.c
+A tests/plugins/extprograms/bin/cat-stdin
+M tests/plugins/extprograms/execute/execute.svtest
+
+2016-02-22 20:48:58 +0100 Stephan Bosch <stephan@rename-it.nl> (b83db1dc)
+
+ lib-sieve: util: program-client: Made shutting down output towards program
+ more efficient.
+
+ Shutdown is now called only once. If there is no used input side to the FD,
+ it is now closed entirely.
+
+M src/lib-sieve/util/program-client-local.c
+M src/lib-sieve/util/program-client-remote.c
+
+2016-02-22 20:30:36 +0100 Stephan Bosch <stephan@rename-it.nl> (63080455)
+
+ lib-sieve: util: program-client-local: Made FD handling in child process a
+ little more robust.
+
+ Prevent mishaps with dup2(); e.g., when source and destination are
+ identicial, which could happen.
+
+M src/lib-sieve/util/program-client-local.c
+
+2016-02-14 23:27:12 +0100 Stephan Bosch <stephan@rename-it.nl> (7ba41a7c)
+
+ Removed some remaining real addresses/domains from the test suite.
+
+
+M src/testsuite/testsuite-message.c
+M tests/compile/trivial.sieve
+M tests/plugins/extprograms/bin/stderr
+
+2016-02-13 00:40:48 +0100 Stephan Bosch <stephan@rename-it.nl> (0de2a195)
+
+ lib-sieve: Implemented sieve_implicit_extensions setting.
+
+ The extensions listed in this setting do not need to be enabled explicitly
+ using the Sieve require command. This behavior voilates the standard, but is
+ necessary for compatibility with some existing implementations of Sieve. Do
+ not use this setting unless you really need to!
+
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+
+2016-02-12 22:19:46 +0100 Stephan Bosch <stephan@rename-it.nl> (f37f0165)
+
+ lib-sieve: Changed Sieve number type to uint64.
+
+ Fixed a few printf format problems in the process. Updated test suite to
+ account for the new number width.
+
+M src/lib-sieve/plugins/duplicate/tst-duplicate.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/tst-size.c
+M src/testsuite/cmd-test-message.c
+M tests/compile/errors.svtest
+M tests/compile/errors/lexer.sieve
+
+2016-02-12 21:38:09 +0100 Stephan Bosch <stephan@rename-it.nl> (b899aa34)
+
+ lib-sieve: code: Made jump offset code generation a bit more robust against
+ integer overflow mishaps.
+
+
+M src/lib-sieve/sieve-binary-code.c
+
+2016-02-12 21:19:52 +0100 Stephan Bosch <stephan@rename-it.nl> (60ad07ad)
+
+ lib-sieve: lexer: Updated number parsing to use Dovecot strnum.h.
+
+
+M src/lib-sieve/sieve-lexer.c
+
+2016-01-27 01:25:42 +0100 Stephan Bosch <stephan@rename-it.nl> (77e7e81f)
+
+ configure: Changed version number to v0.4.devel.
+
+ The actual version numbers live only on the release-branches from now on.
+
+M configure.ac
+
+2016-01-27 01:21:07 +0100 Stephan Bosch <stephan@rename-it.nl> (4fd43c3c)
+
+ configure: Matched first few lines with Dovecot's configure.ac.
+
+
+M configure.ac
+
+2016-01-26 23:21:50 +0100 Stephan Bosch <stephan@rename-it.nl> (3d48d756)
+
+ Makefile: Added run-test.sh to be cleaned by distclean.
+
+
+M Makefile.am
+
+2016-01-26 21:48:05 +0100 Stephan Bosch <stephan@rename-it.nl> (311a2090)
+
+ Increased ABI version.
+
+
+M configure.ac
+
+2016-01-26 21:29:54 +0100 Stephan Bosch <stephan@rename-it.nl> (fd9f5795)
+
+ ChangeLog: Generate Mercurial-style changelogs
+
+ Mimics similar change in Dovecot.
+
+M Makefile.am
+M autogen.sh
+
+2016-01-19 22:33:02 +0100 Stephan Bosch <stephan@rename-it.nl> (71e908a1)
+
+ managesieve-login: Fixed proxy to allow SASL mechanisms other than PLAIN.
+ Also made sure that any capability-derived state information is reset
+ properly before a new capability reply is to be parsed.
+
+
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-proxy.c
+
+2016-01-19 22:03:17 +0100 Stephan Bosch <stephan@rename-it.nl> (2bb0c624)
+
+ Fixed recurring language mistake.
+
+
+M NEWS
+M doc/extensions/spamtest-virustest.txt
+M doc/man/sieve-test.1.in
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/managesieve-login/managesieve-proxy.c
+M tests/compile/errors/if.sieve
+
+2016-01-17 20:08:32 +0100 Stephan Bosch <stephan@rename-it.nl> (9e93a502)
+
+ Fixed the document name of the vnd.dovecot.environment specification.
+
+
+M doc/rfc/spec-bosch-sieve-dovecot-environment.txt
+M doc/rfc/xml/spec-bosch-sieve-dovecot-environment.xml
+
+2016-01-16 00:09:25 +0100 Stephan Bosch <stephan@rename-it.nl> (3a29a267)
+
+ Merge branch 'master' of git.dovecot.net:pigeonhole/core
+
+
+2016-01-16 00:07:05 +0100 Stephan Bosch <stephan@rename-it.nl> (16362ac8)
+
+ lib-sieve: multiscript: Fixed bug in handling of (implicit) keep; final keep
+ action was executed as though there was a failure. Among other things, this
+ caused the keep action to revert back to the initial message, causing
+ editheader actions to be ignored.
+
+
+M Makefile.am
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve.c
+A tests/extensions/editheader/execute.svtest
+A tests/extensions/editheader/execute/multiscript-after.sieve
+A tests/extensions/editheader/execute/multiscript-before.sieve
+A tests/extensions/editheader/execute/multiscript-personal.sieve
+
+2016-01-14 02:28:46 +0100 Stephan Bosch <stephan@rename-it.nl> (cf873f14)
+
+ LDA Sieve plugin: Removed useless assignment. Addresses LLVM scan-build
+ report.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2016-01-14 02:16:53 +0100 Stephan Bosch <stephan@rename-it.nl> (62279853)
+
+ lib-sieve: ldap storage: Prevent segfault occurring when assigning global
+ configuration options.
+
+
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+
+2016-01-14 01:30:20 +0100 Stephan Bosch <stephan@rename-it.nl> (a66a4af8)
+
+ lib-sieve: storage: Local variable in
+ sieve_storage_active_script_is_default() wasn't always properly initialized.
+ This was a LLVM scan-build report.
+
+
+M src/lib-sieve/sieve-storage.c
+
+2016-01-10 02:11:04 +0100 Stephan Bosch <stephan@rename-it.nl> (3f32cd00)
+
+ Updated description of user log in the README file.
+
+
+M README
+
+2016-01-09 22:54:06 +0100 Stephan Bosch <stephan@rename-it.nl> (3446fef1)
+
+ Forgot to remove is-tagged.py from Makefile.am.
+
+
+M Makefile.am
+
+2016-01-09 20:58:56 +0100 Stephan Bosch <stephan@rename-it.nl> (45bc3d90)
+
+ lib-sieve: imap4flags extension: Similar problem as previous commit, but
+ relating to retrieval rather than manipulation.
+
+
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+
+2016-01-09 20:26:06 +0100 Stephan Bosch <stephan@rename-it.nl> (61127ef9)
+
+ lib-sieve: imap4flags extension: Fixed problem in public flag manipulation
+ API. Flags weren't always assigned properly, because the internal variable
+ was not retrieved correctly.
+
+
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h
+
+2016-01-09 16:00:04 +0100 Stephan Bosch <stephan@rename-it.nl> (0a593901)
+
+ Updated TODO.
+
+
+M TODO
+
+2016-01-09 15:59:03 +0100 Stephan Bosch <stephan@rename-it.nl> (1596c777)
+
+ Updated Sieve extension support information in README.
+
+
+M README
+
+2016-01-09 15:10:49 +0100 Stephan Bosch <stephan@rename-it.nl> (060c7bd4)
+
+ Updated dovecot.m4 to the latest version.
+
+
+M m4/dovecot.m4
+
+2016-01-09 12:54:47 +0100 Stephan Bosch <stephan@rename-it.nl> (2d92fd87)
+
+ Switched from hg to git.
+
+
+A .gitignore
+D .hgignore
+D .hgsigs
+M Makefile.am
+D is-tagged.py
+M update-version.sh
+
+2016-01-08 22:27:34 +0100 Stephan Bosch <stephan@rename-it.nl> (f3817d68)
+
+ lib-sieve: imap4flags extension: Forgot to check for empty flag/keyword in
+ new flag checking function.
+
+
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+
+2016-01-08 22:05:03 +0100 Stephan Bosch <stephan@rename-it.nl> (a68816ee)
+
+ lib-sieve: imap4flags extension: Made flag syntax checking available to
+ other extensions.
+
+
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h
+
+2016-01-08 20:49:39 +0100 Stephan Bosch <stephan@rename-it.nl> (9d7a19d9)
+
+ Implemented Sieve extracttext extension.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/mime/Makefile.am
+A src/lib-sieve/plugins/mime/cmd-extracttext.c
+A src/lib-sieve/plugins/mime/ext-extracttext.c
+M src/lib-sieve/plugins/mime/ext-mime-common.h
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/sieve-extensions.c
+M tests/extensions/mime/errors.svtest
+A tests/extensions/mime/errors/extracttext-nofep.sieve
+A tests/extensions/mime/errors/extracttext-novar.sieve
+A tests/extensions/mime/errors/extracttext.sieve
+A tests/extensions/mime/extracttext.svtest
+
+2016-01-08 20:49:39 +0100 Stephan Bosch <stephan@rename-it.nl> (b8b6f750)
+
+ lib-sieve: message body: Amended messaage part API with some more access
+ functions. Added support for getting message part information and content.
+
+
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+
+2016-01-08 20:49:39 +0100 Stephan Bosch <stephan@rename-it.nl> (b2444c8d)
+
+ lib-sieve: foreverypart extension: Improved byte code generated around break
+ command. Prevents useless jumps after break operation.
+
+
+M src/lib-sieve/plugins/mime/cmd-break.c
+
+2016-01-08 20:49:39 +0100 Stephan Bosch <stephan@rename-it.nl> (0caef4ef)
+
+ lib-sieve: Added support for having multiple instances of a single tag
+ (type) within a single command.
+
+
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-validator.c
+
+2016-01-08 20:49:39 +0100 Stephan Bosch <stephan@rename-it.nl> (823d2903)
+
+ lib-sieve: Cleaned up object definitions using newer C99 syntax.
+
+
+M src/lib-sieve/cmp-i-ascii-casemap.c
+M src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-variables.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-objects.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-substitutions.c
+
+2016-01-08 20:49:39 +0100 Stephan Bosch <stephan@rename-it.nl> (877f8247)
+
+ lib-sieve: Cleaned up byte code operand and operation definitions using
+ newer C99 syntax.
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/duplicate/tst-duplicate.c
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/ihave/cmd-error.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/index/tag-index.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/metadata/tst-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+M src/lib-sieve/plugins/mime/cmd-break.c
+M src/lib-sieve/plugins/mime/cmd-foreverypart.c
+M src/lib-sieve/plugins/mime/tag-mime.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/cmd-debug-log.c
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-variables.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+M src/plugins/sieve-extprograms/cmd-execute.c
+M src/plugins/sieve-extprograms/cmd-filter.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-imap-metadata.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/testsuite-variables.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-action.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2016-01-08 20:49:39 +0100 Stephan Bosch <stephan@rename-it.nl> (3d33283d)
+
+ lib-sieve: Cleaned up command definitions using newer C99 syntax.
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/duplicate/tst-duplicate.c
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/ihave/cmd-error.c
+M src/lib-sieve/plugins/ihave/tst-ihave.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/metadata/tst-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+M src/lib-sieve/plugins/mime/cmd-break.c
+M src/lib-sieve/plugins/mime/cmd-foreverypart.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/cmd-debug-log.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/lib-sieve/tst-truefalse.c
+M src/plugins/sieve-extprograms/cmd-execute.c
+M src/plugins/sieve-extprograms/cmd-filter.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-imap-metadata.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-action.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2016-01-08 20:49:39 +0100 Stephan Bosch <stephan@rename-it.nl> (2677f978)
+
+ lib-sieve: Cleaned up command argument definitions using newer C99 syntax.
+
+
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/duplicate/tst-duplicate.c
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/index/tag-index.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mime/cmd-break.c
+M src/lib-sieve/plugins/mime/cmd-foreverypart.c
+M src/lib-sieve/plugins/mime/tag-mime.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/tst-size.c
+M src/plugins/sieve-extprograms/cmd-execute.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-imap-metadata.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/testsuite-arguments.c
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-result-action.c
+M src/testsuite/tst-test-script-run.c
+
+2016-01-08 20:07:51 +0100 Stephan Bosch <stephan@rename-it.nl> (45f46f03)
+
+ Added signature for changeset 80146e7670e9
+
+
+M .hgsigs
+
+2016-01-08 19:15:44 +0100 Stephan Bosch <stephan@rename-it.nl> (7da5ae6e)
+
+ Added tag 0.4.11 for changeset 80146e7670e9
+
+
+2016-01-08 19:15:33 +0100 Stephan Bosch <stephan@rename-it.nl> (9d7b1725)
+
+ Released v0.4.11 for Dovecot v2.2.21.
+
+
+M NEWS
+M configure.ac
+
+2016-01-07 22:20:21 +0100 Stephan Bosch <stephan@rename-it.nl> (dd66c5f3)
+
+ lib-sieve: util: realpath: Make Coverity happier.
+
+
+M src/lib-sieve/util/realpath.c
+
+2016-01-07 22:09:50 +0100 Stephan Bosch <stephan@rename-it.nl> (d576f532)
+
+ lib-sieve: util: Fixed source code indentation in realpath.c.
+
+
+M src/lib-sieve/util/realpath.c
+
+2016-01-04 01:19:02 +0100 Stephan Bosch <stephan@rename-it.nl> (c405da95)
+
+ Added signature for changeset ce96bdac1f74
+
+
+M .hgsigs
+
+2016-01-04 01:14:24 +0100 Stephan Bosch <stephan@rename-it.nl> (3ef7f9d7)
+
+ Added tag 0.4.11.rc1 for changeset ce96bdac1f74
+
+
+2016-01-04 01:14:15 +0100 Stephan Bosch <stephan@rename-it.nl> (439ad92d)
+
+ Released v0.4.11.rc1 for Dovecot v2.2.21.
+
+
+M NEWS
+M configure.ac
+
+2016-01-04 00:19:02 +0100 Stephan Bosch <stephan@rename-it.nl> (51b2276f)
+
+ Updated copyright notices to include the year 2016.
+
+
+M doc/man/doveadm-sieve.1.in
+M doc/man/pigeonhole.7.in
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-filter.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+M src/lib-managesieve/managesieve-arg.c
+M src/lib-managesieve/managesieve-arg.h
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-managesieve/managesieve-parser.h
+M src/lib-managesieve/managesieve-quote.c
+M src/lib-managesieve/managesieve-quote.h
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/cmp-i-ascii-casemap.c
+M src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/copy/sieve-ext-copy.h
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/date/ext-date.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.h
+M src/lib-sieve/plugins/duplicate/ext-duplicate.c
+M src/lib-sieve/plugins/duplicate/tst-duplicate.c
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.h
+M src/lib-sieve/plugins/editheader/ext-editheader-limits.h
+M src/lib-sieve/plugins/editheader/ext-editheader.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify-limits.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/ext-environment-common.h
+M src/lib-sieve/plugins/environment/ext-environment.c
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/ihave/cmd-error.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.h
+M src/lib-sieve/plugins/ihave/ext-ihave-common.c
+M src/lib-sieve/plugins/ihave/ext-ihave-common.h
+M src/lib-sieve/plugins/ihave/ext-ihave.c
+M src/lib-sieve/plugins/ihave/tst-ihave.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-limits.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/index/ext-index-common.c
+M src/lib-sieve/plugins/index/ext-index-common.h
+M src/lib-sieve/plugins/index/ext-index.c
+M src/lib-sieve/plugins/index/tag-index.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/plugins/mailbox/sieve-ext-mailbox.h
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/metadata/ext-metadata-common.h
+M src/lib-sieve/plugins/metadata/ext-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+M src/lib-sieve/plugins/mime/cmd-break.c
+M src/lib-sieve/plugins/mime/cmd-foreverypart.c
+M src/lib-sieve/plugins/mime/ext-foreverypart.c
+M src/lib-sieve/plugins/mime/ext-mime-common.c
+M src/lib-sieve/plugins/mime/ext-mime-common.h
+M src/lib-sieve/plugins/mime/ext-mime.c
+M src/lib-sieve/plugins/mime/tag-mime.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/notify/ext-notify-limits.h
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation-seconds.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/cmd-debug-log.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug-common.h
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-common.h
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-items.c
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-variables.c
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary-code.c
+M src/lib-sieve/sieve-binary-debug.c
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-plugins.c
+M src/lib-sieve/sieve-plugins.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-storage-private.h
+M src/lib-sieve/sieve-storage-sync.c
+M src/lib-sieve/sieve-storage.c
+M src/lib-sieve/sieve-storage.h
+M src/lib-sieve/sieve-stringlist.c
+M src/lib-sieve/sieve-stringlist.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/storage/dict/sieve-dict-script.c
+M src/lib-sieve/storage/dict/sieve-dict-storage.c
+M src/lib-sieve/storage/dict/sieve-dict-storage.h
+M src/lib-sieve/storage/file/sieve-file-script-sequence.c
+M src/lib-sieve/storage/file/sieve-file-script.c
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+M src/lib-sieve/storage/file/sieve-file-storage-list.c
+M src/lib-sieve/storage/file/sieve-file-storage-quota.c
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+M src/lib-sieve/storage/file/sieve-file-storage.h
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+M src/lib-sieve/storage/ldap/sieve-ldap-script.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage-settings.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/lib-sieve/tst-truefalse.c
+M src/lib-sieve/util/edit-mail.c
+M src/lib-sieve/util/edit-mail.h
+M src/lib-sieve/util/program-client-local.c
+M src/lib-sieve/util/program-client-private.h
+M src/lib-sieve/util/program-client-remote.c
+M src/lib-sieve/util/program-client.c
+M src/lib-sieve/util/program-client.h
+M src/lib-sieve/util/realpath.c
+M src/lib-sieve/util/rfc2822.c
+M src/lib-sieve/util/rfc2822.h
+M src/lib-sieve/util/strtrim.c
+M src/managesieve-login/client-authenticate.c
+M src/managesieve-login/client-authenticate.h
+M src/managesieve-login/client.c
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-login-settings-plugin.c
+M src/managesieve-login/managesieve-login-settings-plugin.h
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve-login/managesieve-login-settings.h
+M src/managesieve-login/managesieve-proxy.c
+M src/managesieve-login/managesieve-proxy.h
+M src/managesieve/cmd-capability.c
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-havespace.c
+M src/managesieve/cmd-listscripts.c
+M src/managesieve/cmd-logout.c
+M src/managesieve/cmd-noop.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/cmd-setactive.c
+M src/managesieve/main.c
+M src/managesieve/managesieve-capabilities.c
+M src/managesieve/managesieve-capabilities.h
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+M src/managesieve/managesieve-commands.c
+M src/managesieve/managesieve-commands.h
+M src/managesieve/managesieve-common.h
+M src/managesieve/managesieve-quota.c
+M src/managesieve/managesieve-quota.h
+M src/managesieve/managesieve-settings.c
+M src/managesieve/managesieve-settings.h
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-activate.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-delete.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-get.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-list.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-put.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-rename.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd.h
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.h
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+M src/plugins/lda-sieve/lda-sieve-log.c
+M src/plugins/lda-sieve/lda-sieve-log.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.h
+M src/plugins/settings/pigeonhole-settings.c
+M src/plugins/sieve-extprograms/cmd-execute.c
+M src/plugins/sieve-extprograms/cmd-filter.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+M src/plugins/sieve-extprograms/ext-execute.c
+M src/plugins/sieve-extprograms/ext-filter.c
+M src/plugins/sieve-extprograms/ext-pipe.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.h
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.c
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.h
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-imap-metadata.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-arguments.c
+M src/testsuite/testsuite-arguments.h
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-binary.h
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-log.h
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-script.h
+M src/testsuite/testsuite-settings.c
+M src/testsuite/testsuite-settings.h
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/testsuite-substitutions.h
+M src/testsuite/testsuite-variables.c
+M src/testsuite/testsuite-variables.h
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-action.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2016-01-03 22:06:50 +0100 Stephan Bosch <stephan@rename-it.nl> (645bd122)
+
+ test suite: mime extension: Added more test for exists and address tests
+ with :mime tag.
+
+
+M Makefile.am
+A tests/extensions/mime/address.svtest
+A tests/extensions/mime/exists.svtest
+
+2016-01-03 19:39:32 +0100 Stephan Bosch <stephan@rename-it.nl> (c9a2056a)
+
+ lib-sieve: mime extensions: Updated status from development to experimental.
+
+
+M src/lib-sieve/plugins/mime/ext-foreverypart.c
+M src/lib-sieve/plugins/mime/ext-mime.c
+
+2016-01-03 18:37:39 +0100 Stephan Bosch <stephan@rename-it.nl> (edb268d9)
+
+ lib-sieve: message body: Fixed parsing of content-disposition header.
+
+
+M src/lib-sieve/sieve-message.c
+
+2016-01-03 18:20:51 +0100 Stephan Bosch <stephan@rename-it.nl> (e46b5a2d)
+
+ lib-sieve: Fixed segfault occurring when default match type of a test is not
+ :is. Would not occur in Pigeonhole itself.
+
+
+M src/lib-sieve/sieve-match-types.c
+
+2016-01-03 16:33:39 +0100 Stephan Bosch <stephan@rename-it.nl> (017989a3)
+
+ lib-sieve: mime extension: Fixed the header :mime :anychild test to work
+ properly outside a foreverypart loop.
+
+
+M src/lib-sieve/plugins/mime/tag-mime.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M tests/extensions/mime/foreverypart.svtest
+M tests/extensions/mime/header.svtest
+
+2016-01-03 16:32:27 +0100 Stephan Bosch <stephan@rename-it.nl> (6a117056)
+
+ lib-sieve: message body: Fixed erroneous changes to the message part tree
+ structure performed when re-parsing the message.
+
+
+M src/lib-sieve/sieve-message.c
+
+2016-01-03 16:29:30 +0100 Stephan Bosch <stephan@rename-it.nl> (414251d6)
+
+ lib-sieve: Fixed duplication of discard actions in result. No duplicate
+ check function was implemented, so that the discard action would be
+ duplicated each time it is invoked. This only affects the action limits
+ (each discard invocation is counted as another new action). The result of
+ the script execution would be identical.
+
+
+M src/lib-sieve/cmd-discard.c
+
+2016-01-02 19:36:01 +0100 Stephan Bosch <stephan@rename-it.nl> (eed8e51d)
+
+ test suite: mime extension: Improved header test cases to catch header
+ trimming and folding problems.
+
+
+M tests/extensions/mime/header.svtest
+
+2016-01-02 19:35:24 +0100 Stephan Bosch <stephan@rename-it.nl> (aecb32fe)
+
+ lib-sieve: message body: Forgot to trim header values.
+
+
+M src/lib-sieve/sieve-message.c
+
+2016-01-02 19:34:58 +0100 Stephan Bosch <stephan@rename-it.nl> (75f9c5a0)
+
+ lib-sieve: Fixed an off-by-one error in the previously committed string
+ trimming functions.
+
+
+M src/lib-sieve/util/strtrim.c
+
+2016-01-02 18:27:14 +0100 Stephan Bosch <stephan@rename-it.nl> (c0679f08)
+
+ lib-sieve: Added our own string trimming functions for until equivalents get
+ added in Dovecot.
+
+
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/util/Makefile.am
+A src/lib-sieve/util/strtrim.c
+A src/lib-sieve/util/strtrim.h
+
+2016-01-02 17:13:00 +0100 Stephan Bosch <stephan@rename-it.nl> (fb29773f)
+
+ lib-sieve: Forgot to enable header unfolding for (mime) headers parsed from
+ the whole message.
+
+
+M src/lib-sieve/sieve-message.c
+
+2016-01-02 16:14:27 +0100 Stephan Bosch <stephan@rename-it.nl> (93024df1)
+
+ test suite: Repeated normal header tests for the mime extension.
+
+
+M Makefile.am
+A tests/extensions/mime/header.svtest
+
+2015-12-30 21:38:16 +0100 Stephan Bosch <stephan@rename-it.nl> (57a7d70e)
+
+ lib-sieve: message body: Fixed assert failure occurring when text extraction
+ is attempted on a empty or broken text part.
+
+
+M src/lib-sieve/sieve-message.c
+M tests/extensions/body/text.svtest
+
+2015-12-30 21:36:29 +0100 Stephan Bosch <stephan@rename-it.nl> (62c8bcaf)
+
+ lib-sieve: message body: Erroneously omitted break statement in switch
+ block.
+
+
+M src/lib-sieve/sieve-message.c
+
+2015-12-30 21:34:33 +0100 Stephan Bosch <stephan@rename-it.nl> (766ae2a2)
+
+ lib-sieve: message body: Explicitly prevent attempting text extraction from
+ header and multipart body parts.
+
+
+M src/lib-sieve/sieve-message.c
+
+2015-12-30 17:21:35 +0100 Stephan Bosch <stephan@rename-it.nl> (3debc34c)
+
+ lib-sieve: util: program-client: Ignored ENOTCONN error in shutdown(fd,
+ SHUT_WR) call. This error can apparently occur if the program terminates
+ earlier than the program client issues shutdown().
+
+
+M src/lib-sieve/util/program-client-local.c
+M src/lib-sieve/util/program-client-remote.c
+
+2015-12-29 20:20:29 +0100 Stephan Bosch <stephan@rename-it.nl> (65c4ec04)
+
+ lib-sieve: message body: Fixed assert failure in handling of body parts that
+ are converted to text. No final '\0' character was added to those body
+ parts. This occurs for the body test with the (default) `:text' body
+ transform.
+
+
+M src/lib-sieve/sieve-message.c
+
+2015-12-28 20:46:14 +0100 Stephan Bosch <stephan@rename-it.nl> (75c53950)
+
+ lib-sieve: message body: Prevent cached raw body from growing by one '\0'
+ each time it is accessed.
+
+
+M src/lib-sieve/sieve-message.c
+
+2015-12-28 20:33:01 +0100 Stephan Bosch <stephan@rename-it.nl> (71be8cc6)
+
+ lib-sieve: code: Added assert to prevent emitting invalid byte code when
+ extension definitions are wrong.
+
+
+M src/lib-sieve/sieve-code.c
+
+2015-12-25 20:50:50 +0100 Stephan Bosch <stephan@rename-it.nl> (1a8c0016)
+
+ Added ./compile to .hgignore.
+
+
+M .hgignore
+
+2015-12-22 21:30:12 +0100 Stephan Bosch <stephan@rename-it.nl> (587d90d8)
+
+ lib-sieve: Made sure that quota errors never get logged as errors in syslog.
+ Also improved handling of permission errors caused by ACL plugin.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2015-12-22 21:29:14 +0100 Stephan Bosch <stephan@rename-it.nl> (be199519)
+
+ lib-sieve: Fixed handling of global errors. If master and user error handler
+ were identical, in some cases the log message could be lost.
+
+
+M src/lib-sieve/sieve-error.c
+
+2015-12-22 21:28:17 +0100 Stephan Bosch <stephan@rename-it.nl> (5357208d)
+
+ lib-sieve: result: Fixed handling of implicit keep for a partially executed
+ transaction that yield a temporary failure. It would probably result in
+ message duplication.
+
+
+M src/lib-sieve/sieve-result.c
+
+2015-12-21 23:51:55 +0100 Stephan Bosch <stephan@rename-it.nl> (8411f0fa)
+
+ LDA Sieve plugin: Made sure there is always a proper error handler for the
+ implicit keep action during multiscript execution. Should fix reported bug
+ on missing message-ID in log.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2015-12-21 23:32:49 +0100 Stephan Bosch <stephan@rename-it.nl> (3e2e5545)
+
+ LDA Sieve plugin: Removed stray error handler dereference. This would
+ probably cause a segfault at multiscript errors.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2015-12-14 18:56:25 +0100 Stephan Bosch <stephan@rename-it.nl> (6c9580e8)
+
+ lib-sieve: Fixed AIX compile issue in message body parser. Should not
+ dereference array_idx() result on the spot.
+
+
+M src/lib-sieve/sieve-message.c
+
+2015-12-14 18:54:33 +0100 Stephan Bosch <stephan@rename-it.nl> (d9d8fdb6)
+
+ LDA Sieve plugin: Fixed bug in error handling of Sieve storage constructor.
+ Error code was not passed back to caller, so that it operates on an
+ uninitialized value. Bug found by CLang warning.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2015-12-14 01:10:44 +0100 Stephan Bosch <stephan@rename-it.nl> (3c4c2bb8)
+
+ Added signature for changeset 7e19bcfc0c16
+
+
+M .hgsigs
+
+2015-12-14 01:01:56 +0100 Stephan Bosch <stephan@rename-it.nl> (1adf0132)
+
+ Added tag 0.4.10 for changeset 7e19bcfc0c16
+
+
+2015-12-14 01:01:38 +0100 Stephan Bosch <stephan@rename-it.nl> (fa008c0f)
+
+ Released v0.4.10 for Dovecot v2.2.21.
+
+
+M NEWS
+M configure.ac
+
+2015-12-08 20:33:19 +0100 Stephan Bosch <stephan@rename-it.nl> (4177ae29)
+
+ Renamed pigeonhole.m4 to dovecot-pigeonhole.m4.
+
+
+M Makefile.am
+R100 pigeonhole.m4 dovecot-pigeonhole.m4
+
+2015-12-08 00:37:34 +0100 Stephan Bosch <stephan@rename-it.nl> (c1fe7b28)
+
+ Added signature for changeset 9b7f6f14a350
+
+
+M .hgsigs
+
+2015-12-08 00:32:20 +0100 Stephan Bosch <stephan@rename-it.nl> (1daceb9b)
+
+ Added tag 0.4.10.rc2 for changeset 9b7f6f14a350
+
+
+2015-12-08 00:32:10 +0100 Stephan Bosch <stephan@rename-it.nl> (543848bd)
+
+ Released v0.4.10.rc2 for Dovecot v2.2.20.
+
+
+M configure.ac
+
+2015-12-08 00:31:05 +0100 Stephan Bosch <stephan@rename-it.nl> (d6e95607)
+
+ Fixed indentation in README file.
+
+
+M README
+
+2015-12-05 01:15:11 +0100 Stephan Bosch <stephan@rename-it.nl> (2f56a91f)
+
+ lib-sieve: Added back t_str_trim() for the time being, since it was removed
+ from Dovecot. It is now named pg_t_str_trim() to prevent a new conflict at
+ the next attempt.
+
+
+M src/lib-sieve/sieve-settings.c
+
+2015-12-05 00:49:33 +0100 Stephan Bosch <stephan@rename-it.nl> (a8bec513)
+
+ Added signature for changeset a795304eb433
+
+
+M .hgsigs
+
+2015-12-05 00:44:09 +0100 Stephan Bosch <stephan@rename-it.nl> (c6766eb4)
+
+ Added tag 0.4.10.rc1 for changeset a795304eb433
+
+
+2015-12-05 00:43:45 +0100 Stephan Bosch <stephan@rename-it.nl> (c3af27f4)
+
+ Released v0.4.10.rc1 for Dovecot v2.2.20.rc1.
+
+
+M NEWS
+M configure.ac
+
+2015-12-04 23:21:58 +0100 Stephan Bosch <stephan@rename-it.nl> (ae3ef56d)
+
+ Updated TODO.
+
+
+M TODO
+
+2015-12-04 23:20:05 +0100 Stephan Bosch <stephan@rename-it.nl> (42582832)
+
+ lib-sieve: mime/foreverypart: Properly implemented interaction with include
+ extension. Included scripts now execute in the context of the inner parent
+ foreverypart loop.
+
+
+M src/lib-sieve/plugins/mime/ext-mime-common.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M tests/extensions/mime/errors.svtest
+M tests/extensions/mime/foreverypart.svtest
+A tests/extensions/mime/included/include-foreverypart.sieve
+
+2015-12-04 22:58:35 +0100 Stephan Bosch <stephan@rename-it.nl> (c8643b66)
+
+ lib-sieve: mime: Improved foreverypart runtime trace.
+
+
+M src/lib-sieve/plugins/mime/cmd-foreverypart.c
+
+2015-12-01 14:24:33 +0100 Stephan Bosch <stephan@rename-it.nl> (714988c4)
+
+ Forced distribution of pigeonhole.m4 file. For some inapparent reason it was
+ not included in the output tarball.
+
+
+M Makefile.am
+
+2015-11-29 21:47:14 +0100 Stephan Bosch <stephan@rename-it.nl> (fec57037)
+
+ lib-sieve: variables extension: Fixed handling of empty string by the
+ `:length' set modifier. An empty string yielded an empty string rather than
+ "0".
+
+
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M tests/extensions/variables/modifiers.svtest
+
+2015-11-29 21:33:33 +0100 Stephan Bosch <stephan@rename-it.nl> (c751d077)
+
+ lib-sieve: Fixed memory leak in code dumper. The free handler of code dumper
+ extensions was never executed.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+
+2015-11-29 20:01:09 +0100 Stephan Bosch <stephan@rename-it.nl> (55154015)
+
+ testsuite: mime extension: Added iCalendar example test case.
+
+
+M Makefile.am
+A tests/extensions/mime/calendar-example.svtest
+
+2015-11-29 20:00:37 +0100 Stephan Bosch <stephan@rename-it.nl> (9bdc93c9)
+
+ lib-sieve: mime extension: Improved trace output.
+
+
+M src/lib-sieve/plugins/mime/cmd-foreverypart.c
+M src/lib-sieve/plugins/mime/tag-mime.c
+M src/lib-sieve/sieve-message.c
+
+2015-11-29 18:33:40 +0100 Stephan Bosch <stephan@rename-it.nl> (58fee67d)
+
+ testsuite: mime: Created tests for some basic foreverypart loops.
+
+
+M Makefile.am
+A tests/extensions/mime/foreverypart.svtest
+
+2015-11-29 16:17:41 +0100 Stephan Bosch <stephan@rename-it.nl> (62af47b8)
+
+ testsuite: Fixed the test_fail command to also work from within a
+ foreverypart loop.
+
+
+M src/testsuite/cmd-test-fail.c
+
+2015-11-29 16:17:15 +0100 Stephan Bosch <stephan@rename-it.nl> (0a130f99)
+
+ lib-sieve: interpreter; Added support for program jumps that explicitly
+ cross loop boundaries. Needed for test suite.
+
+
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+
+2015-11-29 15:33:25 +0100 Stephan Bosch <stephan@rename-it.nl> (856c89c6)
+
+ lib-sieve: Fixed memory leak occurring in interpreter loop handling.
+
+
+M src/lib-sieve/sieve-interpreter.c
+
+2015-11-29 15:28:18 +0100 Stephan Bosch <stephan@rename-it.nl> (07ad6819)
+
+ testsuite: Accidentally committed disabled tests.
+
+
+M tests/extensions/mime/errors.svtest
+
+2015-11-29 14:58:20 +0100 Stephan Bosch <stephan@rename-it.nl> (4d2c27cc)
+
+ lib-sieve: interpreter: Improved robustness of code loop handling against
+ binary corruption. When the program crosses the boundary of the current jump
+ somehow, the program is terminated and a corruption error is returned.
+
+
+M src/lib-sieve/plugins/mime/cmd-foreverypart.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+
+2015-11-29 13:46:03 +0100 Stephan Bosch <stephan@rename-it.nl> (028d6fef)
+
+ lib-sieve: mime/foreverypart: Enforced loop nesting limit across includes.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite.c
+M tests/extensions/mime/errors.svtest
+A tests/extensions/mime/errors/limits-include.sieve
+A tests/extensions/mime/included/include-loop-2.sieve
+A tests/extensions/mime/included/include-loop-3.sieve
+A tests/extensions/mime/included/include-loop-4.sieve
+A tests/extensions/mime/included/include-loop-5.sieve
+
+2015-11-29 13:00:38 +0100 Stephan Bosch <stephan@rename-it.nl> (2f4cdcdd)
+
+ lib-sieve: mime/foreverypart: Implemented loop nesting limit.
+
+
+M src/lib-sieve/plugins/mime/cmd-foreverypart.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-limits.h
+M tests/extensions/mime/errors.svtest
+A tests/extensions/mime/errors/limits.sieve
+
+2015-11-29 12:17:32 +0100 Stephan Bosch <stephan@rename-it.nl> (4ee04548)
+
+ lib-sieve: mime/foreverypart: Fixed code dumping of `:param' argument. It
+ erroneously reported a code corruption.
+
+
+M src/lib-sieve/plugins/mime/tag-mime.c
+
+2015-11-29 12:16:25 +0100 Stephan Bosch <stephan@rename-it.nl> (53bab871)
+
+ lib-sieve: mime/foreverypart: Implemented basic execution tests.
+
+
+M Makefile.am
+M tests/extensions/mime/execute.svtest
+M tests/extensions/mime/execute/foreverypart.sieve
+A tests/extensions/mime/execute/mime.sieve
+
+2015-11-29 11:53:24 +0100 Stephan Bosch <stephan@rename-it.nl> (07318673)
+
+ Merged concurrent changes.
+
+
+2015-11-29 11:50:59 +0100 Stephan Bosch <stephan@rename-it.nl> (725a6c66)
+
+ lib-sieve: Implemented the foreverypart and mime extensions (RFC 5703).
+
+
+M Makefile.am
+M README
+M TODO
+M configure.ac
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/mime/Makefile.am
+A src/lib-sieve/plugins/mime/cmd-break.c
+A src/lib-sieve/plugins/mime/cmd-foreverypart.c
+A src/lib-sieve/plugins/mime/ext-foreverypart.c
+A src/lib-sieve/plugins/mime/ext-mime-common.c
+A src/lib-sieve/plugins/mime/ext-mime-common.h
+A src/lib-sieve/plugins/mime/ext-mime.c
+A src/lib-sieve/plugins/mime/tag-mime.c
+M src/lib-sieve/sieve-extensions.c
+A tests/extensions/mime/content-header.svtest
+A tests/extensions/mime/errors.svtest
+A tests/extensions/mime/errors/address-mime-tag.sieve
+A tests/extensions/mime/errors/break.sieve
+A tests/extensions/mime/errors/exists-mime-tag.sieve
+A tests/extensions/mime/errors/foreverypart.sieve
+A tests/extensions/mime/errors/header-mime-tag.sieve
+A tests/extensions/mime/execute.svtest
+A tests/extensions/mime/execute/foreverypart.sieve
+
+2015-11-29 11:50:44 +0100 Stephan Bosch <stephan@rename-it.nl> (7050cd8d)
+
+ lib-sieve: Implemented running code loops in the interpreter.
+
+
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+
+2015-11-29 11:49:47 +0100 Stephan Bosch <stephan@rename-it.nl> (e5dc35fc)
+
+ lib-sieve: Created message body part iterator and mime header list.
+
+
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+
+2015-11-29 11:48:29 +0100 Stephan Bosch <stephan@rename-it.nl> (1679708b)
+
+ lib-sieve: Created special stringlist class for message headers, so that
+ header names can also be returned by the iterator.
+
+
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+
+2015-11-29 11:48:21 +0100 Stephan Bosch <stephan@rename-it.nl> (b9339d5b)
+
+ lib-sieve: Reworked message body parsing to store the message parts in a
+ tree structure.
+
+
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M tests/extensions/body/content.svtest
+
+2015-11-29 11:47:47 +0100 Stephan Bosch <stephan@rename-it.nl> (d8eb07db)
+
+ lib-sieve: The t_str_trim() function has moved to Dovecot.
+
+
+M src/lib-sieve/sieve-settings.c
+
+2015-11-28 23:53:27 +0100 Stephan Bosch <stephan@rename-it.nl> (b947e601)
+
+ Added new TODO item.
+
+
+M TODO
+
+2015-11-18 22:11:31 +0100 Stephan Bosch <stephan@rename-it.nl> (fb2fed99)
+
+ lib-sieve: Moved handling of implicit keep during multiscript execution
+ outside the script sequence itself. Before, implicit keep was executed as
+ part of the final script execution. This caused the implicit keep to be
+ executed as part of that script, including global context. This caused
+ insignificant errors during delivery to be logged as errors in the
+ administrator log when the last script is global.
+
+
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-script.c
+
+2015-11-15 22:46:01 +0100 Stephan Bosch <stephan@rename-it.nl> (c8f4930b)
+
+ lib-sieve: Made message part content type and disposition available to
+ extensions.
+
+
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+
+2015-11-14 00:36:19 +0100 Stephan Bosch <stephan@rename-it.nl> (b378f922)
+
+ lib-sieve: Make message the time the message processing started available to
+ any extension.
+
+
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+
+2015-11-14 00:30:30 +0100 Stephan Bosch <stephan@rename-it.nl> (67366e88)
+
+ lib-sieve: Moved message body parsing code from body extension to Sieve
+ core. This makes this available for other extensions.
+
+
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+
+2015-11-02 18:56:39 +0100 Stephan Bosch <stephan@rename-it.nl> (07defb0a)
+
+ lib-sieve: imap4flags extension: Made flag manipulation API available to
+ other extensions.
+
+
+M src/lib-sieve/plugins/imap4flags/Makefile.am
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+A src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+
+2015-11-02 18:56:39 +0100 Stephan Bosch <stephan@rename-it.nl> (5aebc1c8)
+
+ testsuite: Allow setting configuration options from command line. These will
+ influence some of the performed tests.
+
+
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-settings.c
+
+2015-11-02 18:56:39 +0100 Stephan Bosch <stephan@rename-it.nl> (6ff4199c)
+
+ lib-sieve: Implemented means to override existing (standard) extensions.
+
+
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+
+2015-11-02 18:56:39 +0100 Stephan Bosch <stephan@rename-it.nl> (ab12e844)
+
+ Added pigeonhole.m4 to installation.
+
+
+M Makefile.am
+A pigeonhole.m4
+
+2015-11-02 18:55:14 +0100 Stephan Bosch <stephan@rename-it.nl> (98226d2f)
+
+ doveadm sieve plugin: Added proper handling of Sieve storage initialization
+ failure occurring when sieve_enabled=no
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd.c
+
+2015-10-29 22:14:32 +0100 Stephan Bosch <stephan@rename-it.nl> (d2a75724)
+
+ lib-sieve: Added sieve_enabled setting that defaults to "yes". This allows
+ completely disabling Sieve processing for a particular user.
+
+
+M src/lib-sieve/sieve-storage.c
+M src/managesieve/managesieve-client.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2015-10-29 22:14:24 +0100 Stephan Bosch <stephan@rename-it.nl> (28b1d41f)
+
+ doveadm sieve plugin: Fixed stray debug code committed in earlier patch.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-get.c
+
+2015-10-27 23:42:52 +0100 Stephan Bosch <stephan@rename-it.nl> (a88ff161)
+
+ lib-sieve: body extension: Properly implemented the :text body transform. It
+ now extracts bare text from HTML/XHMTL parts. Other text/* parts are still
+ returned as is. Any other unrecognized content types are skipped.
+
+
+M Makefile.am
+M README
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body.c
+A tests/extensions/body/text.svtest
+
+2015-10-21 23:31:06 +0200 Stephan Bosch <stephan@rename-it.nl> (9bc63675)
+
+ lib-sieve: enotify extension: mailto method: Implemented
+ sieve_notify_mailto_envelope_from setting. This allows setting the MAIL FROM
+ of the SMTP envelope for the notification e-mails. The syntax is identical
+ to the sieve_redirect_envelope_from setting.
+
+
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M tests/extensions/enotify/mailto.svtest
+
+2015-10-21 23:27:36 +0200 Stephan Bosch <stephan@rename-it.nl> (e66eddcd)
+
+ lib-sieve: Created generic implementation for parsing an envelope_from
+ setting, such as sieve_redirect_envelope_from. Also adds a new source for
+ the envelope_from address called "postmaster". This means that the value is
+ obtained from the postmaster_address LDA setting.
+
+
+M INSTALL
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+
+2015-10-20 21:54:49 +0200 Stephan Bosch <stephan@rename-it.nl> (c0d68bce)
+
+ lib-sieve: script storage: Sieve mailbox attributes use an external storage,
+ so they don't need to be synced explicitly with any mail storage backend.
+ Patch by Timo Sirainen.
+
+
+M src/lib-sieve/sieve-storage-sync.c
+
+2015-10-20 13:57:48 +0200 Stephan Bosch <stephan@rename-it.nl> (37e7b654)
+
+ doveadm sieve plugin: Fixed crashes caused by incorrect context allocation
+ in the command implementations. The base context struct was allocated,
+ rather than the (larger) command-specific context. Patch by Timo Sirainen.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-activate.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-get.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-put.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-rename.c
+
+2015-10-04 23:18:29 +0200 Stephan Bosch <stephan@rename-it.nl> (d3c8a4c1)
+
+ Added signature for changeset 8cdb8b90e7a3
+
+
+M .hgsigs
+
+2015-10-04 23:14:08 +0200 Stephan Bosch <stephan@rename-it.nl> (d5710094)
+
+ Added tag 0.4.9 for changeset 8cdb8b90e7a3
+
+
+2015-10-04 23:13:50 +0200 Stephan Bosch <stephan@rename-it.nl> (cef21760)
+
+ Released v0.4.9 for Dovecot v2.2.19.
+
+
+M NEWS
+M configure.ac
+
+2015-10-02 21:37:28 +0200 Stephan Bosch <stephan@rename-it.nl> (0a7c0238)
+
+ lib-sieve: file storage: Added assert to make Coverity happier.
+
+
+M src/lib-sieve/storage/file/sieve-file-storage.c
+
+2015-10-02 17:43:37 +0200 Stephan Bosch <stephan@rename-it.nl> (52ed9371)
+
+ lib-sieve: Use mailbox_save_using_mail() instead of mailbox_copy() for
+ delivering messages. This makes sure that the resulting mail storage events
+ are of the correct type for logging/notification.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2015-10-01 00:11:04 +0200 Stephan Bosch <stephan@rename-it.nl> (a4078e88)
+
+ sieve-test: Fixed couple of Coverity warnings.
+
+
+M src/sieve-tools/sieve-test.c
+
+2015-10-01 00:10:31 +0200 Stephan Bosch <stephan@rename-it.nl> (ab7ae1bc)
+
+ Sieve extprograms plugin: Fixed Coverity warning.
+
+
+M src/plugins/sieve-extprograms/cmd-pipe.c
+
+2015-10-01 00:09:51 +0200 Stephan Bosch <stephan@rename-it.nl> (193d2f88)
+
+ doveadm sieve plugin: Addressed spurious Coverity warning.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd.c
+
+2015-10-01 00:04:37 +0200 Stephan Bosch <stephan@rename-it.nl> (31b96ae3)
+
+ Sieve file storage: Fixed couple of Coverity warnings.
+
+
+M src/lib-sieve/storage/file/sieve-file-script.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+
+2015-10-01 00:02:44 +0200 Stephan Bosch <stephan@rename-it.nl> (e331c727)
+
+ Sieve metadata extension: Fixed couple of Coverity warnings.
+
+
+M src/lib-sieve/plugins/metadata/tst-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+
+2015-09-30 00:54:40 +0200 Stephan Bosch <stephan@rename-it.nl> (b746e31d)
+
+ Sieve vnd.dovecot.environment extension: Forgot 'extern' in extension
+ declaration. This causes link failures for certain platforms.
+
+
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-common.h
+
+2015-09-25 00:01:42 +0200 Stephan Bosch <stephan@rename-it.nl> (3b739e61)
+
+ Added signature for changeset b2d5b1a5fa25
+
+
+M .hgsigs
+
+2015-09-24 23:35:00 +0200 Stephan Bosch <stephan@rename-it.nl> (5d5d4979)
+
+ Added tag 0.4.9.rc1 for changeset b2d5b1a5fa25
+
+
+2015-09-24 23:33:17 +0200 Stephan Bosch <stephan@rename-it.nl> (df7e58f9)
+
+ Released v0.4.9.rc1 for Dovecot v2.2.19.rc1.
+
+
+M NEWS
+M configure.ac
+
+2015-09-23 22:54:11 +0200 Stephan Bosch <stephan@rename-it.nl> (593dde9f)
+
+ Remove now-unnecessary direct stdlib.h #includes.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/storage/file/sieve-file-script-sequence.c
+M src/lib-sieve/storage/file/sieve-file-script.c
+M src/lib-sieve/storage/file/sieve-file-storage-list.c
+M src/lib-sieve/storage/file/sieve-file-storage-quota.c
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+M src/lib-sieve/util/realpath.c
+M src/managesieve-login/client-authenticate.c
+M src/managesieve-login/client.c
+M src/managesieve-login/managesieve-login-settings-plugin.c
+M src/managesieve/cmd-noop.c
+M src/managesieve/main.c
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-commands.c
+M src/managesieve/managesieve-settings.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite.c
+
+2015-09-23 21:57:31 +0200 Stephan Bosch <stephan@rename-it.nl> (ab51bf47)
+
+ Sieve vnd.dovecot.environment extension: Referenced specification from
+ extension source.
+
+
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment.c
+
+2015-09-23 21:54:39 +0200 Stephan Bosch <stephan@rename-it.nl> (8027c3ad)
+
+ doc: Removed obsolete vnd.dovecot.duplicate specification sources.
+
+
+D doc/rfc/xml/reference.IMAP4FLAGS.xml
+D doc/rfc/xml/reference.MAILBOX.xml
+D doc/rfc/xml/reference.VACATION.xml
+D doc/rfc/xml/spec-bosch-sieve-duplicate.xml
+
+2015-09-23 21:50:10 +0200 Stephan Bosch <stephan@rename-it.nl> (a0f7efd0)
+
+ Created specification for the vnd.dovecot.environment extension.
+
+
+A doc/rfc/spec-bosch-sieve-dovecot-environment.txt
+A doc/rfc/xml/reference.ENVIRONMENT.xml
+A doc/rfc/xml/spec-bosch-sieve-dovecot-environment.xml
+
+2015-09-23 21:49:25 +0200 Stephan Bosch <stephan@rename-it.nl> (a8b8d1cb)
+
+ Sieve vnd.dovecot.environment extension: Made activation of the environment
+ extension implicit.
+
+
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment.c
+M tests/extensions/vnd.dovecot/environment/basic.svtest
+M tests/extensions/vnd.dovecot/environment/variables.svtest
+
+2015-09-23 20:06:15 +0200 Stephan Bosch <stephan@rename-it.nl> (1ce4c883)
+
+ Sieve extprograms plugin: Made line endings configurable for the input
+ passed to the external program.
+
+
+M doc/plugins/sieve_extprograms.txt
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.h
+A tests/plugins/extprograms/bin/crlf
+M tests/plugins/extprograms/execute/execute.svtest
+
+2015-09-21 23:34:41 +0200 Stephan Bosch <stephan@rename-it.nl> (66a4bf01)
+
+ vnd.dovecot.environment extension: Forgot a \ in Makefile.am.
+
+
+M src/lib-sieve/plugins/vnd.dovecot/environment/Makefile.am
+
+2015-09-08 01:08:34 +0200 Stephan Bosch <stephan@rename-it.nl> (b185215e)
+
+ managesieve: Fixed assert failure occuring when client disconnects during
+ GETSCRIPT command. Passed NULL as reason to client_disconnect(), which is
+ not allowed.
+
+
+M src/managesieve/cmd-getscript.c
+
+2015-09-08 01:07:43 +0200 Stephan Bosch <stephan@rename-it.nl> (d6079cf4)
+
+ managesieve: Started using io_stream_get_disconnect_reason() for default
+ client_destroy() reason.
+
+
+M src/managesieve/managesieve-client.c
+
+2015-08-29 13:12:58 +0200 Stephan Bosch <stephan@rename-it.nl> (e0c53ce7)
+
+ Removed all invocations of strtoll() and friends.
+
+
+M src/lib-sieve/sieve-settings.c
+
+2015-08-29 13:12:58 +0200 Stephan Bosch <stephan@rename-it.nl> (786522e4)
+
+ Removed all invocations of atoi().
+
+
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+
+2015-08-29 13:12:58 +0200 Stephan Bosch <stephan@rename-it.nl> (3e2d24fc)
+
+ Changed type of internet port values to in_port_t everywhere.
+
+
+M src/managesieve-login/client.c
+
+2015-08-29 12:53:29 +0200 Stephan Bosch <stephan@rename-it.nl> (b25371ee)
+
+ Merged concurrent changes.
+
+
+2015-08-17 23:56:21 +0200 Stephan Bosch <stephan@rename-it.nl> (0615ed9c)
+
+ lib-sieve: Improved efficiency of reading a string-list operand that is
+ actually a single string.
+
+
+M src/lib-sieve/sieve-code.c
+
+2015-08-17 23:51:35 +0200 Stephan Bosch <stephan@rename-it.nl> (5f6735d9)
+
+ lib-sieve: variables extension: Added asserts to extension API to make sure
+ variables extension instance gets passed as argument.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+
+2015-08-17 23:41:05 +0200 Stephan Bosch <stephan@rename-it.nl> (f985536f)
+
+ lib-sieve: vnd.dovecot.environment extension: Forgot to add several files in
+ previous commit.
+
+
+A src/lib-sieve/plugins/vnd.dovecot/environment/Makefile.am
+A src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-common.h
+A src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-items.c
+A src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-variables.c
+A src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment.c
+A tests/extensions/vnd.dovecot/environment/basic.svtest
+A tests/extensions/vnd.dovecot/environment/variables.svtest
+
+2015-08-17 23:34:21 +0200 Stephan Bosch <stephan@rename-it.nl> (2c1540a5)
+
+ lib-sieve: Implemented the vnd.dovecot.environment extension. This adds the
+ vnd.dovecot.default-mailbox and vnd.dovecot.username environment items. It
+ creates the 'env' variables namespace through which all environment items
+ can be accessed directly. This extension is yet to be documented properly.
+ More environment items are under consideration.
+
+
+M Makefile.am
+M configure.ac
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/ext-environment-common.h
+M src/lib-sieve/plugins/environment/ext-environment.c
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/vnd.dovecot/Makefile.am
+M src/lib-sieve/sieve-extensions.c
+
+2015-08-16 19:00:29 +0200 Stephan Bosch <stephan@rename-it.nl> (30509319)
+
+ sieve-filter: Fixed handling of failure-related implicit keep when there is
+ an explicit default destination folder. The message was left in the source
+ mailbox, even though it was stored in the destination folder.
+
+
+M src/sieve-tools/sieve-filter.c
+
+2015-08-06 22:23:29 +0200 Stephan Bosch <stephan@rename-it.nl> (d35a452c)
+
+ doveadm sieve plugin: Fixed incorrect initialization of mail user.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+
+2015-08-06 22:23:03 +0200 Stephan Bosch <stephan@rename-it.nl> (74e03520)
+
+ lib-sieve: Properly implemented checking of ABI version for plugins.
+
+
+M configure.ac
+M pigeonhole-config.h.in
+M src/lib-sieve/sieve-plugins.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.c
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.c
+
+2015-07-25 00:53:51 +0200 Stephan Bosch <stephan@rename-it.nl> (ccf6ae59)
+
+ lib-sieve: Substituted inappropriate use of str_append_n() with normal
+ str_append().
+
+
+M src/lib-sieve/util/rfc2822.c
+
+2015-07-24 23:54:25 +0200 Stephan Bosch <stephan@rename-it.nl> (1cbc493c)
+
+ testsuite: Fixed default envelope extraction fron test message.
+
+
+M src/testsuite/testsuite-message.c
+
+2015-07-24 23:24:33 +0200 Stephan Bosch <stephan@rename-it.nl> (d1b6d77c)
+
+ lib-sieve: util: Fixed RFC5322 header folding.
+
+
+M src/lib-sieve/util/rfc2822.c
+M tests/extensions/vacation/message.svtest
+
+2015-07-06 23:47:05 +0200 Stephan Bosch <stephan@rename-it.nl> (cf089193)
+
+ doveadm-sieve: Fixed one memory leak.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+
+2015-05-22 23:38:58 +0200 Stephan Bosch <stephan@rename-it.nl> (710b5ca5)
+
+ sieve-test: Fixed Clang variable initialization warning.
+
+
+M src/sieve-tools/sieve-test.c
+
+2015-05-22 23:36:03 +0200 Stephan Bosch <stephan@rename-it.nl> (18b089f6)
+
+ Fixed duplicate const specifier warning from Clang.
+
+
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+
+2015-05-22 21:14:21 +0200 Stephan Bosch <stephan@rename-it.nl> (7c96426f)
+
+ managesieve-login: proxy: Fixed use of SASL mechanisms with multiple
+ challenge-response cycles. Previous change had several problems.
+
+
+M src/managesieve-login/managesieve-proxy.c
+
+2015-05-22 02:11:03 +0200 Stephan Bosch <stephan@rename-it.nl> (5da0edb0)
+
+ managesieve-login: Changed proxy to better match imap equivalent. It now
+ uses dsasl-client, so it should now be possible to use SASL mechanisms other
+ than PLAIN. Cleaned up the code a bit.
+
+
+M src/managesieve-login/managesieve-proxy.c
+
+2015-05-22 02:02:38 +0200 Stephan Bosch <stephan@rename-it.nl> (6dfca60c)
+
+ managesieve-login: Copied too much in previous change.
+
+
+M src/managesieve-login/managesieve-proxy.c
+
+2015-05-21 21:45:40 +0200 Stephan Bosch <stephan@rename-it.nl> (79e19b50)
+
+ managesieve-login: Implemented proxy XCLIENT support.
+
+
+M src/managesieve-login/client.c
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-proxy.c
+
+2015-05-19 21:23:52 +0200 Stephan Bosch <stephan@rename-it.nl> (186911f0)
+
+ managesieve-login: settings: Changed default listener initialization to
+ include field names.
+
+
+M src/managesieve-login/managesieve-login-settings.c
+
+2015-05-15 20:54:00 +0200 Stephan Bosch <stephan@rename-it.nl> (898dd129)
+
+ Added signature for changeset baa15dd77f9e
+
+
+M .hgsigs
+
+2015-05-15 20:22:32 +0200 Stephan Bosch <stephan@rename-it.nl> (641126d2)
+
+ Added tag 0.4.8 for changeset baa15dd77f9e
+
+
+2015-05-15 20:22:20 +0200 Stephan Bosch <stephan@rename-it.nl> (f95a87c8)
+
+ Released v0.4.8 for Dovecot v2.2.18.
+
+
+M NEWS
+M configure.ac
+
+2015-05-14 13:13:39 +0200 Stephan Bosch <stephan@rename-it.nl> (2ee12500)
+
+ configure: Use consistent quotation for AC_DEFINEs as per autoconf
+ recommendations.
+
+
+M configure.ac
+
+2015-05-13 23:13:42 +0200 Stephan Bosch <stephan@rename-it.nl> (e4405c33)
+
+ Small adjustment to NEWS file.
+
+
+M NEWS
+
+2015-05-13 22:54:18 +0200 Stephan Bosch <stephan@rename-it.nl> (406b2b87)
+
+ Added signature for changeset 7b154d69394f
+
+
+M .hgsigs
+
+2015-05-13 22:50:58 +0200 Stephan Bosch <stephan@rename-it.nl> (5443d289)
+
+ Added tag 0.4.8.rc3 for changeset 7b154d69394f
+
+
+2015-05-13 22:50:46 +0200 Stephan Bosch <stephan@rename-it.nl> (6f5be001)
+
+ Released v0.4.8.rc3 for Dovecot v2.2.17.
+
+
+M NEWS
+M configure.ac
+
+2015-05-13 19:52:51 +0200 Stephan Bosch <stephan@rename-it.nl> (25d59c10)
+
+ managesieve: Implemented support for reporting command statistics at
+ disconnect.
+
+
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+
+2015-05-13 19:52:51 +0200 Stephan Bosch <stephan@rename-it.nl> (eaf64db1)
+
+ managesieve: Managesieve used "managesieve" rather than "sieve" as login
+ service name, which means that all managesieve-specific settings where
+ ignored.
+
+
+M src/managesieve/main.c
+
+2015-05-13 19:52:51 +0200 Stephan Bosch <stephan@rename-it.nl> (d1cf3325)
+
+ managesieve: Storage quota was not always enforced properly for scripts
+ uploaded as quoted string. Nobody does that, but we support it.
+
+
+M src/managesieve/cmd-putscript.c
+
+2015-05-13 19:52:43 +0200 Stephan Bosch <stephan@rename-it.nl> (b3b0e003)
+
+ lib-sieve: script: Forgot to assign storage error when determining script
+ size from stream.
+
+
+M src/lib-sieve/sieve-script.c
+
+2015-05-12 22:51:12 +0200 Stephan Bosch <stephan@rename-it.nl> (4c587465)
+
+ lib-smtp: storage: Fixed small problem in handling of default script. When
+ the default was first overriden, then deactivated and finally overriden
+ again, it would erroneously implicitly re-activate.
+
+
+M src/lib-sieve/sieve-storage.c
+
+2015-05-12 20:53:46 +0200 Stephan Bosch <stephan@rename-it.nl> (daa9088f)
+
+ lib-sieve: storage: Added parameter to sieve_script_delete() to allow
+ ignoring the active status of the script. Normally, the active script cannot
+ be deleted. This change is necessary to handle doveadm sieve delete -a
+ correctly when the provided script is the default.
+
+
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-storage.c
+M src/managesieve/cmd-deletescript.c
+M src/plugins/doveadm-sieve/doveadm-sieve-cmd-delete.c
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+
+2015-05-11 23:05:24 +0200 Stephan Bosch <stephan@rename-it.nl> (b171cb09)
+
+ lib-sieve: storage: Fixed handling of defaul script in
+ sieve_storage_active_script_open(). It only worked when sieve_default_name
+ was set.
+
+
+M src/lib-sieve/sieve-storage.c
+
+2015-05-11 21:04:39 +0200 Stephan Bosch <stephan@rename-it.nl> (f24b2920)
+
+ Added signature for changeset 44d41235776d
+
+
+M .hgsigs
+
+2015-05-11 21:02:10 +0200 Stephan Bosch <stephan@rename-it.nl> (3236a53c)
+
+ Added tag 0.4.8.rc2 for changeset 44d41235776d
+
+
+2015-05-11 21:02:00 +0200 Stephan Bosch <stephan@rename-it.nl> (42fe82af)
+
+ Released v0.4.8.rc2 for Dovecot v2.2.17.rc1.
+
+
+M configure.ac
+
+2015-05-11 10:03:02 +0200 Stephan Bosch <stephan@rename-it.nl> (f4f8d873)
+
+ lib-sieve: storage: Fixed segfault problem in main storage initialization.
+ Caused by earlier sieve_default_name-related changes.
+
+
+M src/lib-sieve/sieve-storage.c
+
+2015-05-11 00:23:22 +0200 Stephan Bosch <stephan@rename-it.nl> (00ef451c)
+
+ Added signature for changeset fcc97e953584
+
+
+M .hgsigs
+
+2015-05-11 00:19:16 +0200 Stephan Bosch <stephan@rename-it.nl> (84528ce8)
+
+ Added tag 0.4.8.rc1 for changeset fcc97e953584
+
+
+2015-05-11 00:19:00 +0200 Stephan Bosch <stephan@rename-it.nl> (c6c93204)
+
+ Released v0.4.8.rc1 for Dovecot v2.2.17.rc1.
+
+
+M NEWS
+M configure.ac
+
+2015-05-10 22:52:09 +0200 Stephan Bosch <stephan@rename-it.nl> (a7867b24)
+
+ Updated example configuration.
+
+
+M doc/example-config/conf.d/90-sieve.conf
+
+2015-05-07 22:05:23 +0200 Stephan Bosch <stephan@rename-it.nl> (4ca65a78)
+
+ lib-sieve: storage: Forgot to check whether sieve_default_name setting
+ exists. This caused a segfault in the test suite.
+
+
+M src/lib-sieve/sieve-storage.c
+
+2015-05-07 21:46:57 +0200 Stephan Bosch <stephan@rename-it.nl> (91baa5c1)
+
+ LDA Sieve plugin: Fixed spurious error caused by earlier changes.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2015-05-07 21:41:24 +0200 Stephan Bosch <stephan@rename-it.nl> (49a1885f)
+
+ lib-sieve: storage: Check Sieve script name validity in configuration.
+
+
+M src/lib-sieve/sieve-storage.c
+
+2015-05-07 21:17:40 +0200 Stephan Bosch <stephan@rename-it.nl> (74684fcb)
+
+ lib-sieve: file storage: The sieve_script_is_active() function returns int
+ rather than bool.
+
+
+M src/lib-sieve/storage/file/sieve-file-script.c
+
+2015-05-07 21:10:37 +0200 Stephan Bosch <stephan@rename-it.nl> (ccd08367)
+
+ lib-sieve: storage: Changed configuration of default script visibility
+ feature. Using a location option for the default name makes no sense if its
+ only used for the main personal script.
+
+
+M INSTALL
+M src/lib-sieve/sieve-storage.c
+
+2015-05-06 23:58:57 +0200 Stephan Bosch <stephan@rename-it.nl> (f5775b67)
+
+ lib-sieve: storage: Implemented magic to make sieve_default script visible
+ in main storage (e.g. from ManageSieve).
+
+
+M INSTALL
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-storage-private.h
+M src/lib-sieve/sieve-storage.c
+M src/lib-sieve/sieve-storage.h
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+M src/lib-sieve/storage/file/sieve-file-storage.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2015-05-05 13:42:38 +0200 Stephan Bosch <stephan@rename-it.nl> (d1c868ae)
+
+ lib-sieve: Erroneously decoded mime-encoded words in address headers.
+
+
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/index/tag-index.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M tests/test-address.svtest
+
+2015-05-05 10:41:45 +0200 Stephan Bosch <stephan@rename-it.nl> (1e563215)
+
+ lib-sieve: util: program client: Fixed handing of situation when no input is
+ provided to external program used as a command. Previous fixes still omitted
+ a few important aspects: Connect return result wasn't actually passed up to
+ program_client_run(). Default exit code was wrong.
+
+
+M src/lib-sieve/util/program-client-remote.c
+M src/lib-sieve/util/program-client.c
+M tests/plugins/extprograms/execute/execute.svtest
+
+2015-05-04 00:26:58 +0200 Stephan Bosch <stephan@rename-it.nl> (db218f64)
+
+ lib-sieve: util: program client: Fixed omission in previous change.
+
+
+M src/lib-sieve/util/program-client.c
+
+2015-05-04 00:22:09 +0200 Stephan Bosch <stephan@rename-it.nl> (8ba2d883)
+
+ lib-sieve: util: program client: Fixed handling of connecting
+ asynchronously.
+
+
+M src/lib-sieve/util/program-client-remote.c
+M src/lib-sieve/util/program-client.c
+
+2015-04-23 02:04:38 +0200 Stephan Bosch <stephan@rename-it.nl> (45a84bda)
+
+ lib-sieve: util: Fixed bug in t_realpath() normalization occuring with
+ relative symlinks below root. Also contains a few small code cleanups.
+
+
+M src/lib-sieve/util/realpath.c
+
+2015-04-22 21:43:33 +0200 Stephan Bosch <stephan@rename-it.nl> (c7a2dc1a)
+
+ Merged concurrent changes.
+
+
+2015-04-22 21:36:29 +0200 Stephan Bosch <stephan@rename-it.nl> (6fcc0ca9)
+
+ LDA Sieve plugin: Changed error handling so that each action log message can
+ have up-to-date time stamps. This change matches a change in LDA that is
+ aimed at logging timing statistics.
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/Makefile.am
+A src/plugins/lda-sieve/lda-sieve-log.c
+A src/plugins/lda-sieve/lda-sieve-log.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-script.c
+
+2015-04-08 23:48:30 +0200 Stephan Bosch <stephan@rename-it.nl> (3a83dab5)
+
+ lib-sieve: editheader extension: The ADDHEADER operation mnemonic was in
+ lower case.
+
+
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+
+2015-04-06 17:04:13 +0200 Stephan Bosch <stephan@rename-it.nl> (b1bc4da8)
+
+ Fixed some inconsistencies in the INSTALL documentation. Forgot to adjust a
+ few things when the location types were introduced and documented.
+
+
+M INSTALL
+M doc/example-config/conf.d/90-sieve.conf
+
+2015-03-28 10:49:23 +0100 Stephan Bosch <stephan@rename-it.nl> (57aec8ab)
+
+ Updated TODO.
+
+
+M TODO
+
+2015-03-27 23:20:44 +0100 Stephan Bosch <stephan@rename-it.nl> (6aea1b8e)
+
+ More small fixes in file script location documentation.
+
+
+M doc/locations/file.txt
+
+2015-03-27 23:00:11 +0100 Stephan Bosch <stephan@rename-it.nl> (7b3a70cd)
+
+ Small fixes in file script location documentation.
+
+
+M doc/locations/file.txt
+
+2015-03-27 22:36:09 +0100 Stephan Bosch <stephan@rename-it.nl> (029e7a28)
+
+ Revised documentation for the duplicate Sieve extension.
+
+
+M doc/extensions/duplicate.txt
+
+2015-03-27 22:20:09 +0100 Stephan Bosch <stephan@rename-it.nl> (6de83f18)
+
+ Revised documentation for the editheader Sieve extension.
+
+
+M doc/extensions/editheader.txt
+
+2015-03-27 21:58:08 +0100 Stephan Bosch <stephan@rename-it.nl> (0ec8e14a)
+
+ Updated RFCs in documentation.
+
+
+M doc/rfc/Makefile.am
+A doc/rfc/date-index.rfc5260.txt
+D doc/rfc/draft-ietf-appsawg-sieve-duplicate-03.txt
+A doc/rfc/duplicate.rfc7352.txt
+A doc/rfc/mailbox-metadata.rfc5490.txt
+D doc/rfc/spec-bosch-sieve-duplicate.txt
+
+2015-03-27 21:40:00 +0100 Stephan Bosch <stephan@rename-it.nl> (b55d8611)
+
+ Fixed installation of documentation. This was quite fundamentally broken,
+ not only due to previous change.
+
+
+M configure.ac
+M doc/Makefile.am
+A doc/extensions/Makefile.am
+A doc/locations/Makefile.am
+A doc/plugins/Makefile.am
+M doc/rfc/Makefile.am
+
+2015-03-26 23:32:21 +0100 Stephan Bosch <stephan@rename-it.nl> (cfae5b21)
+
+ Updated configuration-related documentation.
+
+
+M INSTALL
+M doc/extensions/duplicate.txt
+R098 doc/script-location-dict.txt doc/locations/dict.txt
+A doc/locations/file.txt
+R100 doc/script-location-ldap.txt doc/locations/ldap.txt
+
+2015-03-19 23:27:48 +0100 Stephan Bosch <stephan@rename-it.nl> (eedd48c9)
+
+ Added signature for changeset f2323a90c202
+
+
+M .hgsigs
+
+2015-03-19 23:18:35 +0100 Stephan Bosch <stephan@rename-it.nl> (993984f5)
+
+ Added tag 0.4.7 for changeset f2323a90c202
+
+
+2015-03-19 23:18:17 +0100 Stephan Bosch <stephan@rename-it.nl> (1052e9e9)
+
+ Released v0.4.7 for Dovecot v2.2.16.
+
+
+M NEWS
+M configure.ac
+
+2015-03-17 02:31:57 +0100 Stephan Bosch <stephan@rename-it.nl> (8ab23992)
+
+ Added signature for changeset 87b2d3e43a44
+
+
+M .hgsigs
+
+2015-03-17 02:29:33 +0100 Stephan Bosch <stephan@rename-it.nl> (0b5e52db)
+
+ Added tag 0.4.7.rc3 for changeset 87b2d3e43a44
+
+
+2015-03-17 02:29:22 +0100 Stephan Bosch <stephan@rename-it.nl> (3103de66)
+
+ Released v0.4.7.rc3 for Dovecot v2.2.16.
+
+
+M NEWS
+M configure.ac
+
+2015-03-16 22:27:17 +0100 Stephan Bosch <stephan@rename-it.nl> (23006f38)
+
+ lib-sieve: file storage: Fixed bug that caused missing active symlink to
+ cause a temporary error in some cases.
+
+
+M src/lib-sieve/storage/file/sieve-file-storage.c
+
+2015-03-16 22:09:55 +0100 Stephan Bosch <stephan@rename-it.nl> (7491fe59)
+
+ lib-sieve: file storage: Fixed bug in storage path normalization. A
+ conditional expression was inverted, causing the path to remain
+ unnormalized.
+
+
+M src/lib-sieve/storage/file/sieve-file-storage.c
+
+2015-03-15 00:15:54 +0100 Stephan Bosch <stephan@rename-it.nl> (54f75842)
+
+ Added signature for changeset fd050f466314 Messed up the previous attempt.
+
+
+M .hgsigs
+
+2015-03-15 00:07:20 +0100 Stephan Bosch <stephan@rename-it.nl> (606e4778)
+
+ Added signature for changeset b3439a979c2e
+
+
+M .hgsigs
+
+2015-03-15 00:05:39 +0100 Stephan Bosch <stephan@rename-it.nl> (d07e65ab)
+
+ Added tag 0.4.7.rc2 for changeset fd050f466314
+
+
+2015-03-15 00:05:14 +0100 Stephan Bosch <stephan@rename-it.nl> (5acb35f2)
+
+ Released v0.4.7.rc2 for Dovecot v2.2.16.
+
+
+M NEWS
+M configure.ac
+
+2015-03-14 23:21:06 +0100 Stephan Bosch <stephan@rename-it.nl> (85854f75)
+
+ lib-sieve: file storage: Fixed handling of invalid active script link. The
+ error status code wasn't set, so this was handled as an error rather than a
+ warning in the LDA plugin.
+
+
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+
+2015-03-14 23:06:37 +0100 Stephan Bosch <stephan@rename-it.nl> (df8c776b)
+
+ lib-sieve: file storage: Improved backwards compatibility with respect to
+ the active script being a regular file.
+
+
+M src/lib-sieve/storage/file/sieve-file-storage.c
+
+2015-03-14 18:20:22 +0100 Stephan Bosch <stephan@rename-it.nl> (42387a43)
+
+ lib-sieve: Added script metadata to binary dump output.
+
+
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/storage/dict/sieve-dict-script.c
+M src/lib-sieve/storage/ldap/sieve-ldap-script.c
+
+2015-03-14 15:52:15 +0100 Stephan Bosch <stephan@rename-it.nl> (dc0bc425)
+
+ lib-sieve: Improved debug messages about up-to-date status of a loaded
+ binary.
+
+
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/storage/dict/sieve-dict-script.c
+M src/lib-sieve/storage/file/sieve-file-script.c
+M src/lib-sieve/storage/ldap/sieve-ldap-script.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.h
+
+2015-03-14 15:31:53 +0100 Stephan Bosch <stephan@rename-it.nl> (11f38dd8)
+
+ lib-sieve: dict: Fixed memory allocation bug in script object.
+
+
+M src/lib-sieve/storage/dict/sieve-dict-script.c
+
+2015-03-12 22:14:44 +0100 Stephan Bosch <stephan@rename-it.nl> (8cc8d605)
+
+ lib-sieve: file storage: Forgot to compare stat.st_dev in equals() method.
+
+
+M src/lib-sieve/storage/file/sieve-file-script.c
+
+2015-03-12 21:42:31 +0100 Stephan Bosch <stephan@rename-it.nl> (386930cd)
+
+ sievec: Don't pass the filename as script name when compiling a whole
+ directory.
+
+
+M src/sieve-tools/sievec.c
+
+2015-03-12 21:41:03 +0100 Stephan Bosch <stephan@rename-it.nl> (bac0703b)
+
+ lib-sieve: file storage: Improved checking of active script link using
+ t_normpath().
+
+
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+
+2015-03-12 21:37:41 +0100 Stephan Bosch <stephan@rename-it.nl> (a82ebb0c)
+
+ lib-sieve: Restructured parsing of storage options.
+
+
+M src/lib-sieve/sieve-storage.c
+
+2015-03-14 14:42:30 +0100 Stephan Bosch <stephan@rename-it.nl> (0645eedd)
+
+ lib-sieve: Fixed handling of script stream errors.
+
+
+M src/lib-sieve/storage/file/sieve-file-script.c
+
+2015-03-12 21:34:10 +0100 Stephan Bosch <stephan@rename-it.nl> (9245e631)
+
+ lib-sieve: Implemented normalization for script storage locations for all
+ storage drivers. This is particularly important when the location is
+ recorded in the binary for checking whether it is up-to-date.
+
+
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/storage/dict/sieve-dict-script.c
+M src/lib-sieve/storage/dict/sieve-dict-storage.c
+M src/lib-sieve/storage/dict/sieve-dict-storage.h
+M src/lib-sieve/storage/file/Makefile.am
+M src/lib-sieve/storage/file/sieve-file-script.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+M src/lib-sieve/storage/ldap/sieve-ldap-script.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.c
+
+2015-03-12 21:03:28 +0100 Stephan Bosch <stephan@rename-it.nl> (a64bca4a)
+
+ lib-sieve: Implemented utility functions to normalize filesystem paths.
+
+
+M src/lib-sieve/util/Makefile.am
+A src/lib-sieve/util/realpath.c
+A src/lib-sieve/util/realpath.h
+
+2015-03-11 23:59:51 +0100 Stephan Bosch <stephan@rename-it.nl> (c2edac3b)
+
+ lib-sieve: script: Added more debug output about metadata up-to-date status.
+
+
+M src/lib-sieve/sieve-script.c
+
+2015-03-10 03:19:39 +0100 Stephan Bosch <stephan@rename-it.nl> (fb9f1f0e)
+
+ Added signature for changeset 27ad95fd05a0
+
+
+M .hgsigs
+
+2015-03-10 03:17:53 +0100 Stephan Bosch <stephan@rename-it.nl> (5e008647)
+
+ Added tag 0.4.7.rc1 for changeset 27ad95fd05a0
+
+
+2015-03-10 03:17:33 +0100 Stephan Bosch <stephan@rename-it.nl> (b63e87a0)
+
+ Released v0.4.7.rc1 for Dovecot v2.2.16.rc1.
+
+
+M NEWS
+M configure.ac
+
+2015-03-10 02:42:53 +0100 Stephan Bosch <stephan@rename-it.nl> (5280156c)
+
+ Updated README with addition of support for the metadata extensions.
+
+
+M README
+
+2015-03-06 21:36:40 +0100 Stephan Bosch <stephan@rename-it.nl> (ed5196bc)
+
+ lib-sieve: Moved lexical scanner to system pool.
+
+
+M src/lib-sieve/sieve-lexer.c
+
+2015-03-06 21:14:01 +0100 Stephan Bosch <stephan@rename-it.nl> (665fba16)
+
+ lib-sieve: Cleaned up error handling for the lexical scanner.
+
+
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+
+2015-03-06 20:02:15 +0100 Stephan Bosch <stephan@rename-it.nl> (d01da0de)
+
+ lib-sieve: editheader extension: Made protection against addition and
+ deletion of headers configurable separately. Also, the received and
+ auto-submitted headers are now only protected against deletion as required
+ in the RFC. Updated the documentation accordingly.
+
+
+M doc/extensions/editheader.txt
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.h
+M tests/extensions/editheader/protected.svtest
+
+2015-03-06 19:02:53 +0100 Stephan Bosch <stephan@rename-it.nl> (01b297b6)
+
+ metadata: Fixed testsuite after changes in Dovecot. Currently cannot freely
+ assing server metadata items for testing. Disabled tests for now.
+
+
+M tests/extensions/metadata/execute.svtest
+
+2015-03-06 18:59:46 +0100 Stephan Bosch <stephan@rename-it.nl> (35f7d173)
+
+ lda sieve plugin: Started using smtp_client_deinit_timeout() to give a
+ session timeout.
+
+
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-types.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+
+2015-03-06 17:12:35 +0100 Stephan Bosch <stephan@rename-it.nl> (9fe14573)
+
+ doveadm sieve plugin: Forgot to add new headers to distribution.
+
+
+M src/plugins/doveadm-sieve/Makefile.am
+
+2015-02-23 09:21:10 +0100 Stephan Bosch <stephan@rename-it.nl> (ccfd86f6)
+
+ lib-sieve: Fixed bug in `:matches' match-type that made a pattern without
+ wildcards match as if there were a '*' at the beginning.
+
+
+M src/lib-sieve/mcht-matches.c
+M tests/match-types/matches.svtest
+
+2015-02-21 18:44:30 +0100 Stephan Bosch <stephan@rename-it.nl> (13e14c9f)
+
+ doveadm sieve plugin: Forgot to change one sieve_script_delete() invocation
+ in previous change.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+
+2015-02-21 17:28:22 +0100 Stephan Bosch <stephan@rename-it.nl> (7246ef04)
+
+ doveadm sieve plugin: Implemented commands for managing Sieve scripts. This
+ allows performing ManageSieve actions at command line or through doveadm
+ server.
+
+
+M .hgignore
+M doc/man/Makefile.am
+A doc/man/doveadm-sieve.1.in
+A doc/man/global-options-formatter.inc
+A doc/man/global-options.inc
+A doc/man/option-A.inc
+A doc/man/option-S-socket.inc
+A doc/man/option-u-user.inc
+M doc/man/pigeonhole.7.in
+M doc/man/reporting-bugs.inc
+M doc/man/sed.sh
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/managesieve/cmd-deletescript.c
+M src/plugins/doveadm-sieve/Makefile.am
+A src/plugins/doveadm-sieve/doveadm-sieve-cmd-activate.c
+A src/plugins/doveadm-sieve/doveadm-sieve-cmd-delete.c
+A src/plugins/doveadm-sieve/doveadm-sieve-cmd-get.c
+A src/plugins/doveadm-sieve/doveadm-sieve-cmd-list.c
+A src/plugins/doveadm-sieve/doveadm-sieve-cmd-put.c
+A src/plugins/doveadm-sieve/doveadm-sieve-cmd-rename.c
+A src/plugins/doveadm-sieve/doveadm-sieve-cmd.c
+A src/plugins/doveadm-sieve/doveadm-sieve-cmd.h
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+A src/plugins/doveadm-sieve/doveadm-sieve-plugin.h
+A src/plugins/doveadm-sieve/doveadm-sieve-sync.c
+
+2015-02-19 01:00:19 +0100 Stephan Bosch <stephan@rename-it.nl> (ccd5660e)
+
+ managesieve: Forgot to dereference script object in RENAMESCRIPT command.
+
+
+M src/managesieve/cmd-renamescript.c
+
+2015-02-01 13:23:15 +0100 Stephan Bosch <stephan@rename-it.nl> (ddcb1828)
+
+ Updated TODO.
+
+
+M TODO
+
+2015-01-16 18:25:51 +0100 Stephan Bosch <stephan@rename-it.nl> (9514b62e)
+
+ lib-sieve: file storage: Restructured storage initialization to address
+ backwards compatibility issues.
+
+
+M src/lib-sieve/storage/file/sieve-file-script.c
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+M src/lib-sieve/storage/file/sieve-file-storage-list.c
+M src/lib-sieve/storage/file/sieve-file-storage-quota.c
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+M src/lib-sieve/storage/file/sieve-file-storage.h
+
+2015-01-16 18:23:49 +0100 Stephan Bosch <stephan@rename-it.nl> (3971b095)
+
+ lib-sieve: Make sure internal script storage errors clear previous error.
+
+
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-storage.c
+
+2015-01-08 02:07:51 +0100 Stephan Bosch <stephan@rename-it.nl> (116ace11)
+
+ Updated copyright notices to include the year 2015.
+
+
+M doc/man/pigeonhole.7.in
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-filter.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+M src/lib-managesieve/managesieve-arg.c
+M src/lib-managesieve/managesieve-arg.h
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-managesieve/managesieve-parser.h
+M src/lib-managesieve/managesieve-quote.c
+M src/lib-managesieve/managesieve-quote.h
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/cmp-i-ascii-casemap.c
+M src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/copy/sieve-ext-copy.h
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/date/ext-date.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.h
+M src/lib-sieve/plugins/duplicate/ext-duplicate.c
+M src/lib-sieve/plugins/duplicate/tst-duplicate.c
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.h
+M src/lib-sieve/plugins/editheader/ext-editheader-limits.h
+M src/lib-sieve/plugins/editheader/ext-editheader.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify-limits.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/ext-environment-common.h
+M src/lib-sieve/plugins/environment/ext-environment.c
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/ihave/cmd-error.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.h
+M src/lib-sieve/plugins/ihave/ext-ihave-common.c
+M src/lib-sieve/plugins/ihave/ext-ihave-common.h
+M src/lib-sieve/plugins/ihave/ext-ihave.c
+M src/lib-sieve/plugins/ihave/tst-ihave.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-limits.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/index/ext-index-common.c
+M src/lib-sieve/plugins/index/ext-index-common.h
+M src/lib-sieve/plugins/index/ext-index.c
+M src/lib-sieve/plugins/index/tag-index.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/plugins/mailbox/sieve-ext-mailbox.h
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/metadata/ext-metadata-common.h
+M src/lib-sieve/plugins/metadata/ext-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/notify/ext-notify-limits.h
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation-seconds.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/cmd-debug-log.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug-common.h
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary-code.c
+M src/lib-sieve/sieve-binary-debug.c
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-plugins.c
+M src/lib-sieve/sieve-plugins.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-storage-private.h
+M src/lib-sieve/sieve-storage-sync.c
+M src/lib-sieve/sieve-storage.c
+M src/lib-sieve/sieve-storage.h
+M src/lib-sieve/sieve-stringlist.c
+M src/lib-sieve/sieve-stringlist.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/storage/dict/sieve-dict-script.c
+M src/lib-sieve/storage/dict/sieve-dict-storage.c
+M src/lib-sieve/storage/dict/sieve-dict-storage.h
+M src/lib-sieve/storage/file/sieve-file-script-sequence.c
+M src/lib-sieve/storage/file/sieve-file-script.c
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+M src/lib-sieve/storage/file/sieve-file-storage-list.c
+M src/lib-sieve/storage/file/sieve-file-storage-quota.c
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+M src/lib-sieve/storage/file/sieve-file-storage.h
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+M src/lib-sieve/storage/ldap/sieve-ldap-script.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage-settings.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/lib-sieve/tst-truefalse.c
+M src/lib-sieve/util/edit-mail.c
+M src/lib-sieve/util/edit-mail.h
+M src/lib-sieve/util/program-client-local.c
+M src/lib-sieve/util/program-client-private.h
+M src/lib-sieve/util/program-client-remote.c
+M src/lib-sieve/util/program-client.c
+M src/lib-sieve/util/program-client.h
+M src/lib-sieve/util/rfc2822.c
+M src/lib-sieve/util/rfc2822.h
+M src/managesieve-login/client-authenticate.c
+M src/managesieve-login/client-authenticate.h
+M src/managesieve-login/client.c
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-login-settings-plugin.c
+M src/managesieve-login/managesieve-login-settings-plugin.h
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve-login/managesieve-login-settings.h
+M src/managesieve-login/managesieve-proxy.c
+M src/managesieve-login/managesieve-proxy.h
+M src/managesieve/cmd-capability.c
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-havespace.c
+M src/managesieve/cmd-listscripts.c
+M src/managesieve/cmd-logout.c
+M src/managesieve/cmd-noop.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/cmd-setactive.c
+M src/managesieve/main.c
+M src/managesieve/managesieve-capabilities.c
+M src/managesieve/managesieve-capabilities.h
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+M src/managesieve/managesieve-commands.c
+M src/managesieve/managesieve-commands.h
+M src/managesieve/managesieve-common.h
+M src/managesieve/managesieve-quota.c
+M src/managesieve/managesieve-quota.h
+M src/managesieve/managesieve-settings.c
+M src/managesieve/managesieve-settings.h
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.h
+M src/plugins/settings/pigeonhole-settings.c
+M src/plugins/sieve-extprograms/cmd-execute.c
+M src/plugins/sieve-extprograms/cmd-filter.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+M src/plugins/sieve-extprograms/ext-execute.c
+M src/plugins/sieve-extprograms/ext-filter.c
+M src/plugins/sieve-extprograms/ext-pipe.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.h
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.c
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.h
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-imap-metadata.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-arguments.c
+M src/testsuite/testsuite-arguments.h
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-binary.h
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-log.h
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-script.h
+M src/testsuite/testsuite-settings.c
+M src/testsuite/testsuite-settings.h
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/testsuite-substitutions.h
+M src/testsuite/testsuite-variables.c
+M src/testsuite/testsuite-variables.h
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-action.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2015-01-01 17:12:17 +0100 Stephan Bosch <stephan@rename-it.nl> (bc3c7ff7)
+
+ lib-sieve: Added more debug output to binary up-to-date checking.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/storage/file/sieve-file-script.c
+
+2014-12-30 23:01:04 +0100 Stephan Bosch <stephan@rename-it.nl> (9420e6de)
+
+ lib-sieve: Fixed crash in validation of the string parameter of the
+ comparator tag. It couldn't handle a missing parameter (which also means
+ missing arguments of the test itself in most cases). This is fixed by using
+ the sieve_validate_tag_parameter() utility function. Testsuite is also
+ extended.
+
+
+M src/lib-sieve/sieve-comparators.c
+M tests/compile/errors.svtest
+A tests/compile/errors/comparator.sieve
+
+2014-12-30 22:57:07 +0100 Stephan Bosch <stephan@rename-it.nl> (86f27058)
+
+ testsuite: Added syntax checks for body test.
+
+
+M Makefile.am
+A tests/extensions/body/errors.svtest
+A tests/extensions/body/errors/syntax.sieve
+
+2014-12-30 22:56:11 +0100 Stephan Bosch <stephan@rename-it.nl> (7260b4d4)
+
+ lib-sieve: Fixed parameter validation error message for tagged argument. It
+ had a whitespace where it didn't belong.
+
+
+M src/lib-sieve/sieve-validator.c
+
+2014-12-20 18:18:16 +0100 Stephan Bosch <stephan@rename-it.nl> (d9ca5247)
+
+ lib-sieve: Turned message envelope address parse errors into warnings.
+
+
+M src/lib-sieve/sieve-message.c
+
+2014-12-20 16:45:32 +0100 Stephan Bosch <stephan@rename-it.nl> (2c77b286)
+
+ lib-sieve: Accept non-standard domain names, e.g. containing '_'.
+
+
+M src/lib-sieve/sieve-address.c
+M tests/extensions/envelope.svtest
+
+2014-12-17 01:15:04 +0100 Stephan Bosch <stephan@rename-it.nl> (cffd007e)
+
+ Updated LGPL license.
+
+
+M COPYING.LGPL
+
+2014-12-17 01:12:43 +0100 Stephan Bosch <stephan@rename-it.nl> (797e9294)
+
+ lib-sieve: program client: Made sure supplemental group privileges are also
+ dropped.
+
+
+M src/lib-sieve/util/program-client-local.c
+
+2014-12-17 00:58:58 +0100 Stephan Bosch <stephan@rename-it.nl> (b279890d)
+
+ tests: Fixed extprograms test suite. Recent changes in handling of unknown
+ tags caused `make test-plugins' to fail.
+
+
+M tests/plugins/extprograms/execute/errors/syntax.sieve
+
+2014-12-17 00:35:47 +0100 Stephan Bosch <stephan@rename-it.nl> (00c807f2)
+
+ lib-sieve: Fixed printing of hybrid command type.
+
+
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+
+2014-11-22 00:17:13 +0100 Stephan Bosch <stephan@rename-it.nl> (60c8e9d4)
+
+ lib-sieve: Consolidated checking mailbox name.
+
+
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/metadata/tst-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+
+2014-11-21 01:23:15 +0100 Stephan Bosch <stephan@rename-it.nl> (aa8e4148)
+
+ lib-sieve: metadata extensions: Implemented proper checking of annotation
+ names everywhere. Also added testsuite items to test syntax.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+A tests/extensions/metadata/errors.svtest
+A tests/extensions/metadata/errors/syntax.sieve
+M tests/extensions/metadata/execute.svtest
+
+2014-11-20 01:04:00 +0100 Stephan Bosch <stephan@rename-it.nl> (f898a54a)
+
+ lib-sieve: Flush duplicate database during start phase of result execution
+ rather than commit phase. This will release the duplicate database lock
+ earlier, even before a mail storage transation is started.
+
+
+M src/lib-sieve/sieve-result.c
+
+2014-11-20 00:53:41 +0100 Stephan Bosch <stephan@rename-it.nl> (ccf3c957)
+
+ testsuite: Created tests for the Sieve servermetadata extension.
+
+
+M src/testsuite/cmd-test-imap-metadata.c
+M src/testsuite/testsuite-mailstore.c
+M tests/extensions/metadata/execute.svtest
+
+2014-11-20 00:51:09 +0100 Stephan Bosch <stephan@rename-it.nl> (2b08d727)
+
+ lib-sieve: servermetadata extension: Fixed segfault.
+
+
+M src/lib-sieve/plugins/metadata/tst-metadata.c
+
+2014-11-17 02:20:40 +0100 Stephan Bosch <stephan@rename-it.nl> (bad772f5)
+
+ Added basic testsuite items for new Sieve metadata support.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/metadata/tst-metadata.c
+M src/testsuite/Makefile.am
+A src/testsuite/cmd-test-imap-metadata.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite.c
+A tests/extensions/metadata/execute.svtest
+
+2014-11-16 23:16:38 +0100 Stephan Bosch <stephan@rename-it.nl> (31b2c8d7)
+
+ Merged concurrent changes.
+
+
+2014-11-16 23:13:58 +0100 Stephan Bosch <stephan@rename-it.nl> (f63b20cd)
+
+ lib-sieve: Finished support for mboxmetadata and servermetadata extensions.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+M src/lib-sieve/plugins/metadata/Makefile.am
+M src/lib-sieve/plugins/metadata/ext-metadata-common.h
+M src/lib-sieve/plugins/metadata/tst-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+M src/lib-sieve/sieve-extensions.c
+M src/sieve-tools/sieve-test.c
+
+2014-11-13 09:37:21 +0100 Stephan Bosch <stephan@rename-it.nl> (ab8d1ef0)
+
+ lib-sieve: Increased binary minor version due to changes in optional operand
+ codes.
+
+
+M src/lib-sieve/sieve-binary.h
+
+2014-11-13 09:36:13 +0100 Stephan Bosch <stephan@rename-it.nl> (79d6a5b8)
+
+ lib-sieve: Fixed bug in handling of binary errors for action side-effects
+ and message overrides.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+
+2014-11-12 22:21:14 +0100 Stephan Bosch <stephan@rename-it.nl> (0cb62bcc)
+
+ Updated README with with implementation status.
+
+
+M README
+
+2014-11-12 22:10:25 +0100 Stephan Bosch <stephan@rename-it.nl> (9a193393)
+
+ lib-sieve: Implemented the Sieve index extension (RFC 5260).
+
+
+M Makefile.am
+M configure.ac
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/index/Makefile.am
+A src/lib-sieve/plugins/index/ext-index-common.c
+A src/lib-sieve/plugins/index/ext-index-common.h
+A src/lib-sieve/plugins/index/ext-index.c
+A src/lib-sieve/plugins/index/tag-index.c
+M src/lib-sieve/sieve-extensions.c
+A tests/extensions/index/basic.svtest
+A tests/extensions/index/errors.svtest
+A tests/extensions/index/errors/syntax.sieve
+
+2014-11-12 22:10:24 +0100 Stephan Bosch <stephan@rename-it.nl> (842ebbec)
+
+ lib-sieve: Created message override infrastructure. This allows extension of
+ test commands that evaluate the message somehow. Currently this is
+ implemented only for the message header. Extensions can thereby influence
+ what headers are evaluated and how.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M tests/compile/errors.svtest
+
+2014-11-12 22:10:23 +0100 Stephan Bosch <stephan@rename-it.nl> (bddc00a5)
+
+ lib-sieve: Implemented the index stringlist class which selects an item of
+ the parent at a particular index.
+
+
+M src/lib-sieve/sieve-stringlist.c
+M src/lib-sieve/sieve-stringlist.h
+
+2014-11-12 22:09:44 +0100 Stephan Bosch <stephan@rename-it.nl> (fa4ae816)
+
+ lib-sieve: Made validator resolve all tagged command arguments before
+ validating them. This is needed so that argument validation functions can
+ reliably verify other arguments at arbitrary positions.
+
+
+M src/lib-sieve/sieve-validator.c
+
+2014-11-02 18:35:34 +0100 Stephan Bosch <stephan@rename-it.nl> (60012e68)
+
+ Added signature for changeset 99d796a8cd26
+
+
+M .hgsigs
+
+2014-11-02 18:32:40 +0100 Stephan Bosch <stephan@rename-it.nl> (8b664b06)
+
+ Added tag 0.4.6 for changeset 99d796a8cd26
+
+
+2014-11-02 18:32:06 +0100 Stephan Bosch <stephan@rename-it.nl> (a06cc4be)
+
+ Released v0.4.6 for Dovecot v2.2.15.
+
+
+M NEWS
+M configure.ac
+
+2014-10-31 00:50:28 +0100 Stephan Bosch <stephan@rename-it.nl> (b0be4ab4)
+
+ After make distclean the distributed tarball would fail to recompile.
+
+
+M Makefile.am
+
+2014-10-30 23:27:42 +0100 Stephan Bosch <stephan@rename-it.nl> (409858f5)
+
+ Added signature for changeset f5e3ef477a32
+
+
+M .hgsigs
+
+2014-10-30 23:25:20 +0100 Stephan Bosch <stephan@rename-it.nl> (1702fccc)
+
+ Added tag 0.4.5 for changeset f5e3ef477a32
+
+
+2014-10-30 23:25:07 +0100 Stephan Bosch <stephan@rename-it.nl> (890ae8e7)
+
+ Released v0.4.5 for Dovecot v2.2.15.
+
+
+M NEWS
+M configure.ac
+
+2014-10-30 23:15:45 +0100 Stephan Bosch <stephan@rename-it.nl> (00df2072)
+
+ Previous change actually didn't work completely.
+
+
+M configure.ac
+
+2014-10-30 22:40:16 +0100 Stephan Bosch <stephan@rename-it.nl> (41895b01)
+
+ Fixed distcheck problem caused by pigeonhole-version.h.
+
+
+M Makefile.am
+M configure.ac
+
+2014-10-30 18:47:26 +0100 Stephan Bosch <stephan@rename-it.nl> (26cb5e95)
+
+ New pigeonhole-version.h header was installed in the wrong directory.
+
+
+M Makefile.am
+
+2014-10-30 09:43:18 +0100 Stephan Bosch <stephan@rename-it.nl> (5be0f805)
+
+ lib-sieve: Fixed handling of implicit keep. The sieve_result_execute()
+ function returned the wrong status result.
+
+
+M src/lib-sieve/sieve-result.c
+
+2014-10-29 22:00:31 +0100 Stephan Bosch <stephan@rename-it.nl> (16b50682)
+
+ Added dummy settings plugin that adds a Pigeonhole version banner to
+ doveconf output.
+
+
+M configure.ac
+M src/plugins/Makefile.am
+A src/plugins/settings/Makefile.am
+A src/plugins/settings/pigeonhole-settings.c
+
+2014-10-29 21:37:07 +0100 Stephan Bosch <stephan@rename-it.nl> (178e1f5e)
+
+ Forgot to add and ignore new files in latest commit.
+
+
+M .hgignore
+A is-tagged.py
+A update-version.sh
+
+2014-10-29 03:05:43 +0100 Stephan Bosch <stephan@rename-it.nl> (a3a616c3)
+
+ Implmented reporting full Pigeonhole version with hg tag so that builds
+ between releases can be distinguished. Copied from Dovecot for the most
+ part.
+
+
+M Makefile.am
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.c
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.c
+
+2014-10-28 22:34:48 +0100 Stephan Bosch <stephan@rename-it.nl> (76c59355)
+
+ lib-sieve: sieve script: Made sure there is a script name for when
+ sieve_script_open() fails.
+
+
+M src/lib-sieve/storage/file/sieve-file-script.c
+
+2014-10-28 14:53:39 +0100 Stephan Bosch <stephan@rename-it.nl> (1552383d)
+
+ lib-sieve: Fixed potential segfault bug in file storage driver.
+
+
+M src/lib-sieve/storage/file/sieve-file-script.c
+
+2014-10-28 01:53:46 +0100 Stephan Bosch <stephan@rename-it.nl> (2c03f457)
+
+ Added signature for changeset b3303f675157
+
+
+M .hgsigs
+
+2014-10-28 01:39:32 +0100 Stephan Bosch <stephan@rename-it.nl> (e634184d)
+
+ Added tag 0.4.4 for changeset b3303f675157
+
+
+2014-10-28 01:39:14 +0100 Stephan Bosch <stephan@rename-it.nl> (cc57bb25)
+
+ Released v0.4.4 for Dovecot v2.2.15.
+
+
+M NEWS
+M configure.ac
+
+2014-10-28 00:54:15 +0100 Stephan Bosch <stephan@rename-it.nl> (52c305a3)
+
+ doveadm-sieve: Fixed timeout leaks occuring while running doveadm. This was
+ caused by a circular reference.
+
+
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-storage-private.h
+M src/lib-sieve/sieve-storage-sync.c
+M src/lib-sieve/sieve-storage.c
+
+2014-10-27 21:58:13 +0100 Stephan Bosch <stephan@rename-it.nl> (42693b97)
+
+ doveadm-sieve: Fixed problem with synchronizing the active script.
+
+
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-storage-private.h
+M src/lib-sieve/sieve-storage-sync.c
+M src/lib-sieve/sieve-storage.c
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2014-10-26 14:10:27 +0100 Stephan Bosch <stephan@rename-it.nl> (591a6272)
+
+ lib-sieve: storage: Fixed bug in synchronization intialization. Storage flag
+ checks were bogus.
+
+
+M src/lib-sieve/sieve-storage-sync.c
+
+2014-10-25 21:51:16 +0200 Stephan Bosch <stephan@rename-it.nl> (2403ce99)
+
+ Adjusted to datastack-related changes in Dovecot lib-storage.
+
+
+M src/lib-sieve/util/edit-mail.c
+
+2014-10-19 22:50:23 +0200 Stephan Bosch <stephan@rename-it.nl> (fd9d0bd4)
+
+ managesieve: If client gets disconnected due to iostream error, log the full
+ error.
+
+
+M src/managesieve/managesieve-client.c
+
+2014-10-19 18:14:20 +0200 Stephan Bosch <stephan@rename-it.nl> (59b3963e)
+
+ doveadm-sieve plugin: Improved debugging a bit.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2014-10-19 13:39:37 +0200 Stephan Bosch <stephan@rename-it.nl> (53b93a44)
+
+ managesieve-login: The AUTHENTICATE command returned bogus ALERT response
+ code.
+
+
+M src/managesieve-login/client-authenticate.c
+
+2014-10-19 13:37:38 +0200 Stephan Bosch <stephan@rename-it.nl> (9503c3a5)
+
+ managesieve-login: Fixed handling of invalid initial response argument to
+ AUTHENTICATE command.
+
+
+M src/managesieve-login/client-authenticate.c
+
+2014-10-19 13:36:57 +0200 Stephan Bosch <stephan@rename-it.nl> (a66396b3)
+
+ Forgot one file in last commit.
+
+
+M src/lib-managesieve/managesieve-parser.c
+
+2014-10-19 13:10:27 +0200 Stephan Bosch <stephan@rename-it.nl> (f365ceb3)
+
+ managesieve: Changed managesieve parser's quoted string stream to use
+ io_stream_set_error().
+
+
+M src/managesieve-login/client-authenticate.c
+M src/managesieve/cmd-putscript.c
+
+2014-10-19 11:01:17 +0200 Stephan Bosch <stephan@rename-it.nl> (4f55d83f)
+
+ lib-sieve: Improved handling of stream errors in lexical scannner.
+
+
+M src/lib-sieve/sieve-lexer.c
+
+2014-10-19 09:37:48 +0200 Stephan Bosch <stephan@rename-it.nl> (3b4e4daa)
+
+ lib-sieve: Removed implicitly resolved FIXME.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2014-10-19 09:34:03 +0200 Stephan Bosch <stephan@rename-it.nl> (83175c96)
+
+ managesieve: Fixed handling of o_stream_send_istream() errors during
+ GETSCRIPT command.
+
+
+M src/managesieve/cmd-getscript.c
+
+2014-10-19 01:02:02 +0200 Stephan Bosch <stephan@rename-it.nl> (617dcd99)
+
+ lib-sieve: Improved (temporary) error handling from mail storage and io
+ streams.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/duplicate/tst-duplicate.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/tst-exists.c
+M src/plugins/sieve-extprograms/cmd-execute.c
+M src/plugins/sieve-extprograms/cmd-filter.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+
+2014-10-17 21:07:36 +0200 Stephan Bosch <stephan@rename-it.nl> (6211d99e)
+
+ lib-sieve: Flush duplicate database before committing storage transactions.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-types.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2014-10-17 20:49:57 +0200 Stephan Bosch <stephan@rename-it.nl> (94c1a2b6)
+
+ lib-sieve: Restructured result execution, so that all actions which involve
+ mail storage are always committed before all others.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+
+2014-10-15 00:23:55 +0200 Stephan Bosch <stephan@rename-it.nl> (908467a2)
+
+ lib-sieve: Implemented sieve_redirect_envelope_from setting, which allows
+ configuring the envelope sender of redirected messages. Can either be set to
+ the envelope sender, recipient, or orignal recipient of the processed
+ message or it can be set explicitly to a static address.
+
+
+M INSTALL
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve.c
+M src/testsuite/cmd-test-config.c
+M tests/execute/smtp.svtest
+
+2014-10-14 03:22:23 +0200 Stephan Bosch <stephan@rename-it.nl> (ffdbb1f0)
+
+ lib-sieve: mailbox extension: The `:create' tag erroneously subscribed an
+ existing folder. It should only subscribe it when it is newly created.
+
+
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+
+2014-10-11 01:33:15 +0200 Stephan Bosch <stephan@rename-it.nl> (002ca395)
+
+ LDA Sieve plugin: Fixed handling of temporary SMTP errors. These caused a
+ BUG error to be reported during delivery. Solved by signalling the
+ occurrence of storage errors as a separate execution status flag, rather
+ than querying the last storage itself for errors, which won't work.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-types.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2014-10-11 00:44:27 +0200 Stephan Bosch <stephan@rename-it.nl> (00d27ba0)
+
+ Removed useless mail-storage includes.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/duplicate/tst-duplicate.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/storage/file/sieve-file-storage.h
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-size.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-smtp.c
+
+2014-10-11 00:42:39 +0200 Stephan Bosch <stephan@rename-it.nl> (ce5d301c)
+
+ lib-sieve: Omitted handling errors from mail_get_headers() in message header
+ stringlist. Mail storage errors now trigger a runtime error.
+
+
+M src/lib-sieve/sieve-message.c
+
+2014-10-08 00:32:28 +0200 Stephan Bosch <stephan@rename-it.nl> (f1bfb896)
+
+ lib-sieve: Addressed race condition writing to user error log file.
+
+
+M src/lib-sieve/sieve-error.c
+
+2014-10-07 23:12:20 +0200 Stephan Bosch <stephan@rename-it.nl> (eb775e8a)
+
+ lib-sieve-tool: Simplified seekable stream callback for raw mail. No longer
+ needed to create the temp directory.
+
+
+M src/lib-sieve-tool/mail-raw.c
+
+2014-09-12 12:17:38 +0200 Stephan Bosch <stephan@rename-it.nl> (72563215)
+
+ lib-sieve: duplicate extension: Fixed erroneous compile error about
+ conflicting tags when ":handle" argument was used last.
+
+
+M src/lib-sieve/plugins/duplicate/tst-duplicate.c
+
+2014-09-05 14:38:35 +0200 Stephan Bosch <stephan@rename-it.nl> (ccf79840)
+
+ Valgrindn needs --trace-children to work properly these days.
+
+
+M Makefile.am
+
+2014-08-28 15:38:39 +0200 Stephan Bosch <stephan@rename-it.nl> (2aea3112)
+
+ doveadm sieve plugin: Fixed segfault occuring when main script storage does
+ not support synchronization. Would occur with any other script storage
+ intialization error as well.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2014-08-28 11:34:37 +0200 Stephan Bosch <stephan@rename-it.nl> (08676552)
+
+ Doveadm Sieve plugin: Attempting synchronization with LDAP/DICT caused write
+ access error. If the main script storage does not allow synchronization, it
+ is now just logged as a debug message.
+
+
+M src/lib-sieve/sieve-storage-sync.c
+M src/lib-sieve/sieve-storage.c
+
+2014-08-27 00:19:40 +0200 Stephan Bosch <stephan@rename-it.nl> (cac0ac7a)
+
+ Fixed handling of SMTP errors. Logging was mixed up; it logged permanent
+ SMTP failures as errors rather than mere info. Redirect now handles
+ temporary failure as a separate error condition, causing LDA to return a
+ temporary failure if no other (storage) actions were performed.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+
+2014-08-24 00:27:40 +0200 Stephan Bosch <stephan@rename-it.nl> (2df6d4b5)
+
+ lib-sieve: Added version to script storage class. Updated binary version.
+
+
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-storage-private.h
+M src/lib-sieve/storage/dict/sieve-dict-storage.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.c
+
+2014-08-23 22:52:30 +0200 Stephan Bosch <stephan@rename-it.nl> (0de1dadc)
+
+ Added support for Japanese mail addresses with dots at non-standard places
+ in localpart. Based on patch by Timo Sirainen.
+
+
+M src/lib-sieve/sieve-address.c
+M tests/compile/errors/out-address.sieve
+M tests/extensions/envelope.svtest
+
+2014-08-23 21:16:34 +0200 Stephan Bosch <stephan@rename-it.nl> (f4677eca)
+
+ Changed handling of ENOSPACE to a normal temporary failure and added
+ handling of ENOQUOTA as a user error. Patch by Timo Sirainen.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/managesieve/managesieve-client.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2014-08-23 21:11:54 +0200 Stephan Bosch <stephan@rename-it.nl> (9f8863d3)
+
+ lib-sieve: file storage: Warning about active script not being a symlink was
+ triggered at inappropriate times. Fixed by issueing the warning only when
+ storage is opened as READWRITE (ManageSieve).
+
+
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+
+2014-08-05 18:25:12 +0200 Stephan Bosch <stephan@rename-it.nl> (9e6b63f8)
+
+ lib-sieve: editheader extension: Fixed several problems in deleteheader
+ command.
+
+
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/util/edit-mail.c
+M tests/extensions/editheader/deleteheader.svtest
+
+2014-08-05 03:55:56 +0200 Stephan Bosch <stephan@rename-it.nl> (c4575f2e)
+
+ lib-sieve: file storage: Fixed assert failure in script sequence code.
+ Single script was only initialized and not actually opened.
+
+
+M src/lib-sieve/storage/file/sieve-file-script-sequence.c
+M src/lib-sieve/storage/file/sieve-file-script.c
+M src/lib-sieve/storage/file/sieve-file-storage.h
+
+2014-08-05 03:47:36 +0200 Stephan Bosch <stephan@rename-it.nl> (5e42bce1)
+
+ lib-sieve: file storage: Fixed segfault bug in script sequence code.
+
+
+M src/lib-sieve/storage/file/sieve-file-script-sequence.c
+
+2014-07-31 02:17:50 +0200 Stephan Bosch <stephan@rename-it.nl> (2006f4cb)
+
+ lib-sieve: util: edit-mail: Fixed a few bugs in previous commit.
+
+
+M src/lib-sieve/util/edit-mail.c
+
+2014-07-31 01:37:22 +0200 Stephan Bosch <stephan@rename-it.nl> (c85782ca)
+
+ lib-sieve: util: edit-mail: Added header replacement API.
+
+
+M src/lib-sieve/util/edit-mail.c
+M src/lib-sieve/util/edit-mail.h
+
+2014-07-30 19:57:17 +0200 Stephan Bosch <stephan@rename-it.nl> (8fa71536)
+
+ lib-sieve: mailbox extension: Made :create tag available for new commands.
+
+
+M src/lib-sieve/plugins/mailbox/Makefile.am
+M src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+A src/lib-sieve/plugins/mailbox/sieve-ext-mailbox.h
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+
+2014-07-30 13:50:48 +0200 Stephan Bosch <stephan@rename-it.nl> (4e8120b9)
+
+ lib-sieve: variables extension: Added API for assigning cstrings to
+ variables.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2014-07-30 13:50:12 +0200 Stephan Bosch <stephan@rename-it.nl> (e6074922)
+
+ lib-sieve: Fixed problem in validator extension handling. The validate hook
+ only worked for one extension.
+
+
+M src/lib-sieve/sieve-validator.c
+
+2014-07-30 13:49:24 +0200 Stephan Bosch <stephan@rename-it.nl> (2432a185)
+
+ lib-sieve: Made binary code functions capable of skipping data.
+
+
+M src/lib-sieve/sieve-binary-code.c
+M src/lib-sieve/sieve-binary.h
+
+2014-07-30 00:15:08 +0200 Stephan Bosch <stephan@rename-it.nl> (fecb8e43)
+
+ lib-sieve: Restructured native extension declarations a bit.
+
+
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/sieve-extensions.c
+
+2014-07-29 01:34:25 +0200 Stephan Bosch <stephan@rename-it.nl> (c92959ec)
+
+ doveadm sieve plugin: Fixed segfault issue caused in lib-sieve. Erroneously
+ set pointer to NULL in sieve_storage_list_deinit().
+
+
+M src/lib-sieve/sieve-storage.c
+
+2014-07-28 09:27:59 +0200 Stephan Bosch <stephan@rename-it.nl> (71a92bec)
+
+ lib-sieve: ldap storage: Fixed --with-ldap=no compile.
+
+
+M src/lib-sieve/storage/ldap/sieve-ldap-db.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.h
+
+2014-07-26 01:17:51 +0200 Stephan Bosch <stephan@rename-it.nl> (ce342b01)
+
+ lib-sieve: ldap storage: Implemented checking config mtime for binary
+ recompile.
+
+
+M src/lib-sieve/storage/ldap/sieve-ldap-script.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage-settings.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.h
+
+2014-07-26 00:47:29 +0200 Stephan Bosch <stephan@rename-it.nl> (1e515e44)
+
+ Forgot to remove a few files in earlier lib-sieve/storage change.
+
+
+D src/lib-sieve/sieve-script-dict.c
+D src/lib-sieve/sieve-script-file.c
+
+2014-07-26 00:46:26 +0200 Stephan Bosch <stephan@rename-it.nl> (321dde03)
+
+ Fixed compile problem reported by OpenSUSE build service.
+
+
+M src/lib-sieve/storage/file/sieve-file-script-sequence.c
+M src/lib-sieve/storage/file/sieve-file-script.c
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+M src/lib-sieve/storage/file/sieve-file-storage-list.c
+M src/lib-sieve/storage/file/sieve-file-storage-quota.c
+M src/lib-sieve/storage/file/sieve-file-storage-save.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+M src/lib-sieve/storage/file/sieve-file-storage.h
+
+2014-07-25 15:59:40 +0200 Stephan Bosch <stephan@rename-it.nl> (19dd4638)
+
+ lda-sieve plugin: Dereferenced default script storage at wrong nesting
+ level, causing an assert failure.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2014-07-24 15:21:29 +0200 Stephan Bosch <stephan@rename-it.nl> (bace39ec)
+
+ lib-sieve: file storage: Erroneously always ignored active script setting.
+
+
+M src/lib-sieve/sieve-storage.c
+M src/lib-sieve/storage/file/sieve-file-storage.c
+
+2014-07-24 15:20:47 +0200 Stephan Bosch <stephan@rename-it.nl> (e25a71e4)
+
+ lib-sieve: file storage: Don't tempfail on missing active script.
+
+
+M src/lib-sieve/storage/file/sieve-file-storage-active.c
+
+2014-07-24 12:53:51 +0200 Stephan Bosch <stephan@rename-it.nl> (a1d29d31)
+
+ Fixed moduledir for Sieve plugins.
+
+
+M src/lib-sieve/storage/ldap/Makefile.am
+M src/plugins/sieve-extprograms/Makefile.am
+
+2014-07-24 09:27:14 +0200 Stephan Bosch <stephan@rename-it.nl> (85980973)
+
+ Adjusted documentation to mention LDAP support can be compiled as a plugin.
+
+
+M INSTALL
+M doc/script-location-ldap.txt
+
+2014-07-24 09:17:07 +0200 Stephan Bosch <stephan@rename-it.nl> (2a049da8)
+
+ lib-sieve: Fixed LDAP storage compiled as a plugin.
+
+
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.c
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.h
+
+2014-07-24 02:05:28 +0200 Stephan Bosch <stephan@rename-it.nl> (343c5793)
+
+ lib-sieve: Made LDAP plugin compile properly. LDAP storage as a plugin is
+ still not problem-free though.
+
+
+M src/lib-sieve/storage/ldap/Makefile.am
+M src/lib-sieve/storage/ldap/sieve-ldap-storage.c
+
+2014-07-24 02:04:47 +0200 Stephan Bosch <stephan@rename-it.nl> (a86e3fd8)
+
+ lib-sieve: Fixed file storage sequence implementation. Directory iteration
+ was very broken.
+
+
+M src/lib-sieve/storage/file/sieve-file-script-sequence.c
+M src/lib-sieve/storage/file/sieve-file-script.c
+
+2014-07-23 19:36:00 +0200 Stephan Bosch <stephan@rename-it.nl> (593b91e5)
+
+ lib-sieve: Created sieve LDAP storage driver.
+
+
+M INSTALL
+M TODO
+M configure.ac
+M doc/example-config/conf.d/90-sieve.conf
+A doc/example-config/sieve-ldap.conf
+A doc/script-location-ldap.txt
+M pigeonhole-config.h.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/sieve-storage.c
+M src/lib-sieve/storage/Makefile.am
+A src/lib-sieve/storage/ldap/Makefile.am
+A src/lib-sieve/storage/ldap/sieve-ldap-db.c
+A src/lib-sieve/storage/ldap/sieve-ldap-db.h
+A src/lib-sieve/storage/ldap/sieve-ldap-script.c
+A src/lib-sieve/storage/ldap/sieve-ldap-storage-settings.c
+A src/lib-sieve/storage/ldap/sieve-ldap-storage.c
+A src/lib-sieve/storage/ldap/sieve-ldap-storage.h
+
+2014-07-23 19:28:07 +0200 Stephan Bosch <stephan@rename-it.nl> (5a8c6b89)
+
+ lib-sieve: Implemented support for generic Sieve storages. Doveadm-sieve
+ plugin may be broken at this point; not tested so far.
+
+
+M TODO
+M configure.ac
+M src/Makefile.am
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-script-dict.c
+D src/lib-sieve/sieve-script-file.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+A src/lib-sieve/sieve-storage-private.h
+A src/lib-sieve/sieve-storage-sync.c
+A src/lib-sieve/sieve-storage.c
+A src/lib-sieve/sieve-storage.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+A src/lib-sieve/storage/Makefile.am
+A src/lib-sieve/storage/dict/Makefile.am
+A src/lib-sieve/storage/dict/sieve-dict-script.c
+A src/lib-sieve/storage/dict/sieve-dict-storage.c
+A src/lib-sieve/storage/dict/sieve-dict-storage.h
+A src/lib-sieve/storage/file/Makefile.am
+A src/lib-sieve/storage/file/sieve-file-script-sequence.c
+A src/lib-sieve/storage/file/sieve-file-script.c
+A src/lib-sieve/storage/file/sieve-file-storage-active.c
+A src/lib-sieve/storage/file/sieve-file-storage-list.c
+R054 src/lib-sievestorage/sieve-storage-quota.c src/lib-sieve/storage/file/sieve-file-storage-quota.c
+A src/lib-sieve/storage/file/sieve-file-storage-save.c
+A src/lib-sieve/storage/file/sieve-file-storage.c
+A src/lib-sieve/storage/file/sieve-file-storage.h
+D src/lib-sievestorage/Makefile.am
+D src/lib-sievestorage/sieve-storage-list.c
+D src/lib-sievestorage/sieve-storage-list.h
+D src/lib-sievestorage/sieve-storage-private.h
+D src/lib-sievestorage/sieve-storage-quota.h
+D src/lib-sievestorage/sieve-storage-save.c
+D src/lib-sievestorage/sieve-storage-save.h
+D src/lib-sievestorage/sieve-storage-script.c
+D src/lib-sievestorage/sieve-storage-script.h
+D src/lib-sievestorage/sieve-storage.c
+D src/lib-sievestorage/sieve-storage.h
+M src/managesieve/Makefile.am
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-havespace.c
+M src/managesieve/cmd-listscripts.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/cmd-setactive.c
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-quota.c
+M src/plugins/Makefile.am
+M src/plugins/doveadm-sieve/Makefile.am
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sievec.c
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-script.c
+M tests/extensions/include/execute.svtest
+
+2014-06-26 23:25:43 +0200 Stephan Bosch <stephan@rename-it.nl> (4ae41e1d)
+
+ doveadm sieve plugin: Fixed assert crash occuring when Sieve script
+ attribute assignment fails.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2014-06-19 00:10:53 +0200 Stephan Bosch <stephan@rename-it.nl> (8a7cecee)
+
+ managesieve: Compared to imap and incorporated a few differences from there.
+ Most important change is that mail service_user was not freed.
+
+
+M src/managesieve/main.c
+M src/managesieve/managesieve-client.c
+
+2014-06-18 00:08:03 +0200 Stephan Bosch <stephan@rename-it.nl> (38732434)
+
+ Some ATTR_FORMAT additions by Timo.
+
+
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.h
+
+2014-06-17 23:43:10 +0200 Stephan Bosch <stephan@rename-it.nl> (975707d3)
+
+ lib-sieve: program client: Fixed copy-paste error in destroy function. Would
+ cause a segfault. Reported by Coverity.
+
+
+M src/lib-sieve/util/program-client.c
+
+2014-06-17 23:37:46 +0200 Stephan Bosch <stephan@rename-it.nl> (53940810)
+
+ lib-sieve: edit mail: Fixed header iteration. Handling of
+ edit_mail_header_find() result was incoherent. Problem reported by Coverity.
+
+
+M src/lib-sieve/util/edit-mail.c
+
+2014-06-17 23:28:53 +0200 Stephan Bosch <stephan@rename-it.nl> (a3c55d8c)
+
+ sieve extprograms plugin: Fixed dead code problems. Reported by Coverity.
+
+
+M src/plugins/sieve-extprograms/cmd-execute.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+
+2014-06-17 23:19:37 +0200 Stephan Bosch <stephan@rename-it.nl> (840ce64b)
+
+ lib-sieve: relational extension: Fixed error handling of :value match.
+ Switch statement item is never reached and return value was bool instead of
+ int. Problem reported by Coverity.
+
+
+M src/lib-sieve/plugins/relational/mcht-value.c
+
+2014-06-17 23:04:24 +0200 Stephan Bosch <stephan@rename-it.nl> (19b4dee4)
+
+ lib-sievestorage: Fixed file path comparison function. Forgot a few '*'
+ there. Reported by Coverity.
+
+
+M src/lib-sievestorage/sieve-storage-script.c
+
+2014-06-17 22:52:32 +0200 Stephan Bosch <stephan@rename-it.nl> (2d78f622)
+
+ lib-sieve: edit mail: Fixed header unfolding. Forgot break in switch
+ statement. Reported by Coverity.
+
+
+M src/lib-sieve/util/edit-mail.c
+
+2014-06-17 22:45:23 +0200 Stephan Bosch <stephan@rename-it.nl> (1dc9b818)
+
+ lib-sieve: program client: Forgot break in switch statement for handling of
+ response from script service. Reported by Coverity.
+
+
+M src/lib-sieve/util/program-client-remote.c
+
+2014-06-17 22:38:12 +0200 Stephan Bosch <stephan@rename-it.nl> (543c10a8)
+
+ testsuite: Fixed out-of-bounds read in (currently unused) string
+ substitution implementation. Reported by Coverity.
+
+
+M src/testsuite/testsuite-substitutions.c
+
+2014-06-17 22:28:06 +0200 Stephan Bosch <stephan@rename-it.nl> (511700be)
+
+ sieve-storage: Fixed resource leak in storage listing implementation
+ occuring at error. Reported by Coverity.
+
+
+M src/lib-sievestorage/sieve-storage-list.c
+
+2014-06-17 22:13:52 +0200 Stephan Bosch <stephan@rename-it.nl> (62313f89)
+
+ Use the new [io]_stream_create_fd_*autoclose() functions wherever possible.
+ Parallel to identical Dovecot change.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/sieve-script-file.c
+M src/lib-sieve/sieve-script-private.h
+M src/testsuite/testsuite-smtp.c
+
+2014-06-17 20:58:23 +0200 Stephan Bosch <stephan@rename-it.nl> (7b7a9e09)
+
+ managesieve: Remove the client from clients-list at the very end of the
+ destroy function. Parallel to identical Dovecot change for imap and pop3.
+
+
+M src/managesieve/managesieve-client.c
+
+2014-06-17 20:48:50 +0200 Stephan Bosch <stephan@rename-it.nl> (7719fc03)
+
+ lib-sieve: code dumper: Fixed handling of undefined extensions. Reported by
+ Coverity.
+
+
+M src/lib-sieve/sieve-code-dumper.c
+
+2014-06-17 20:44:47 +0200 Stephan Bosch <stephan@rename-it.nl> (a14ee75d)
+
+ lib-sieve: Small change in Sieve generator to make static analyzer happier.
+ Reported by Coverity.
+
+
+M src/lib-sieve/sieve-generator.c
+
+2014-06-17 20:41:53 +0200 Stephan Bosch <stephan@rename-it.nl> (d9cbd268)
+
+ doveadm sieve plugin: Fixed dereference before NULL check problem. Found by
+ Coverity.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2014-06-17 20:35:18 +0200 Stephan Bosch <stephan@rename-it.nl> (b928bbd9)
+
+ lib: pair VA_COPY with va_end. A va_copy creates a initialised va_list, as
+ if a va_start had been done on it. Therefore, pedantically, a va_end should
+ also be done on it. On most platforms this is a no-op, and for those where
+ it isn't, the pairing is important.
+
+ This change matches parallel change in Dovecot. Also signalled by Coverity.
+
+M src/lib-sieve/sieve-error.c
+M src/testsuite/testsuite-log.c
+
+2014-05-15 19:48:27 +0200 Stephan Bosch <stephan@rename-it.nl> (c71c21d9)
+
+ Fixed several problems reported by CLang 3.4.
+
+
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/util/edit-mail.c
+M src/testsuite/testsuite-script.c
+
+2014-05-12 21:27:13 +0200 Stephan Bosch <stephan@rename-it.nl> (8d984203)
+
+ Wrong date in NEWS.
+
+
+M NEWS
+
+2014-05-12 21:14:44 +0200 Stephan Bosch <stephan@rename-it.nl> (25c38e42)
+
+ Added signature for changeset 1c6130ff5dd6
+
+
+M .hgsigs
+
+2014-05-12 21:12:34 +0200 Stephan Bosch <stephan@rename-it.nl> (fb6b23fe)
+
+ Added tag 0.4.3 for changeset 1c6130ff5dd6
+
+
+2014-05-12 21:12:24 +0200 Stephan Bosch <stephan@rename-it.nl> (84dde15e)
+
+ Released v0.4.3 for Dovecot v2.2.13.
+
+
+M NEWS
+M configure.ac
+
+2014-05-12 20:40:39 +0200 Stephan Bosch <stephan@rename-it.nl> (d2206ede)
+
+ lib-sieve: sieve-error.c: Made static analyzer happier.
+
+
+M src/lib-sieve/sieve-error.c
+
+2014-05-12 20:22:30 +0200 Stephan Bosch <stephan@rename-it.nl> (45db1c22)
+
+ lib-sieve: include extension: Fixed problem with handling of duplicate
+ includes. Flags weren't actually updated.
+
+
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2014-05-09 08:55:02 +0200 Stephan Bosch <stephan@rename-it.nl> (15e090d6)
+
+ testsuite: editheader: Made test failure messages a bit more verbose.
+
+
+M tests/extensions/editheader/addheader.svtest
+
+2014-05-09 01:32:52 +0200 Stephan Bosch <stephan@rename-it.nl> (e2abf9e2)
+
+ lib-sieve: redirect: Adjusted loop detection to show leniency to resent
+ messages.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2014-05-08 21:23:24 +0200 Stephan Bosch <stephan@rename-it.nl> (1bbbe727)
+
+ lib-sieve: program-client: Made sure that programs are never forked with
+ root privileges.
+
+
+M src/lib-sieve/util/program-client-local.c
+M src/lib-sieve/util/program-client.h
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+
+2014-05-07 21:17:43 +0200 Stephan Bosch <stephan@rename-it.nl> (2ad87784)
+
+ lib-sieve: editheader: Made control characters allowed for editheader,
+ except NUL. NOTE: Dovecot doesn't currently MIME-encode these in the
+ headers.
+
+
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M tests/extensions/editheader/addheader.svtest
+M tests/extensions/editheader/errors.svtest
+M tests/extensions/editheader/errors/field-value.sieve
+
+2014-05-07 20:15:07 +0200 Stephan Bosch <stephan@rename-it.nl> (0683c506)
+
+ lib-sieve: Fixed indenting problem in runtime trace output. Also cleaned up
+ the surrounding code a bit.
+
+
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+
+2014-05-07 20:03:10 +0200 Stephan Bosch <stephan@rename-it.nl> (b4ab2e7c)
+
+ lib-sieve: Added final result execution stage for the duplicate extension.
+ This way, a duplicate is only marked when the script execution succeeds, as
+ required in the specification.
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+
+2014-05-05 17:09:10 +0200 Stephan Bosch <stephan@rename-it.nl> (b3dccbd0)
+
+ lib-sieve: vacation extension: Fixed log message for discarded response.
+ Presence of :addresses argument was represented incorrectly.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2014-05-01 00:07:27 +0200 Stephan Bosch <stephan@rename-it.nl> (ee69b175)
+
+ lib-sieve: editheader: Adjusted to change in Dovecot lib-storage mail API.
+
+
+M src/lib-sieve/util/edit-mail.c
+
+2014-04-29 02:13:35 +0200 Stephan Bosch <stephan@rename-it.nl> (923b1b94)
+
+ lib-sieve: Adjusted to more SMTP API changes in Dovecot. SMTP API now
+ supports adding multiple recipients to a single SMTP transaction. This makes
+ enotify/notify more efficient, since only one message is actually sent.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-types.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite.c
+M tests/deprecated/notify/mailto.svtest
+
+2014-04-28 22:08:47 +0200 Stephan Bosch <stephan@rename-it.nl> (5dc50ad9)
+
+ lib-sieve: Switched to new Dovecot SMTP API.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-types.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+
+2014-04-25 23:53:40 +0200 Stephan Bosch <stephan@rename-it.nl> (ba7aff60)
+
+ lib-sieve: Fixed sieve_result_global_log_error to log only as i_info in
+ administrator log (syslog) if executed from multiscript context. Previously,
+ this would work correcly only from the user's personal script and not from
+ multiscript (sieve_before/sieve_after).
+
+
+M src/lib-sieve/sieve-error.c
+
+2014-04-15 23:11:46 +0200 Stephan Bosch <stephan@rename-it.nl> (793ee9b0)
+
+ Dovecot change: Replaced mail_get_real_mail() with mail_get_backend_mail().
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/util/edit-mail.c
+
+2014-03-04 22:28:56 +0100 Stephan Bosch <stephan@rename-it.nl> (f5505c87)
+
+ lib-sieve: Upgraded "vnd.dovecot.duplicate" to "duplicate". Backwards
+ compatibility is provided for vnd.dovecot.duplicate. Still need to fix the
+ constraint that it must not track duplicates from failed Sieve executions.
+
+
+M Makefile.am
+M README
+M configure.ac
+A doc/extensions/duplicate.txt
+D doc/extensions/vnd.dovecot.duplicate.txt
+A doc/rfc/draft-ietf-appsawg-sieve-duplicate-03.txt
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+R092 src/lib-sieve/plugins/vnd.dovecot/duplicate/Makefile.am src/lib-sieve/plugins/duplicate/Makefile.am
+R077 src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.c src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+R085 src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.h src/lib-sieve/plugins/duplicate/ext-duplicate-common.h
+A src/lib-sieve/plugins/duplicate/ext-duplicate.c
+R073 src/lib-sieve/plugins/vnd.dovecot/duplicate/tst-duplicate.c src/lib-sieve/plugins/duplicate/tst-duplicate.c
+M src/lib-sieve/plugins/vnd.dovecot/Makefile.am
+M src/lib-sieve/plugins/vnd.dovecot/debug/cmd-debug-log.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug-common.h
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c
+D src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate.c
+M src/lib-sieve/sieve-extensions.c
+M src/plugins/sieve-extprograms/cmd-execute.c
+M src/plugins/sieve-extprograms/cmd-filter.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+M src/plugins/sieve-extprograms/ext-execute.c
+M src/plugins/sieve-extprograms/ext-filter.c
+M src/plugins/sieve-extprograms/ext-pipe.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.h
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.c
+A tests/extensions/duplicate/errors.svtest
+A tests/extensions/duplicate/errors/conflict-vnd.sieve
+A tests/extensions/duplicate/errors/conflict.sieve
+R100 tests/extensions/vnd.dovecot/duplicate/errors/syntax.sieve tests/extensions/duplicate/errors/syntax-vnd.sieve
+A tests/extensions/duplicate/errors/syntax.sieve
+R100 tests/extensions/vnd.dovecot/duplicate/execute.svtest tests/extensions/duplicate/execute-vnd.svtest
+A tests/extensions/duplicate/execute.svtest
+D tests/extensions/vnd.dovecot/duplicate/errors.svtest
+
+2014-02-25 00:49:08 +0100 Stephan Bosch <stephan@rename-it.nl> (fdcfea49)
+
+ lib-sieve: program-client: Removed stale assert.
+
+
+M src/lib-sieve/util/program-client-local.c
+
+2014-01-12 23:23:50 +0100 Stephan Bosch <stephan@rename-it.nl> (c167b196)
+
+ Prevent compiled binaries in testsuite from ending up in distribution
+ tarball.
+
+
+M Makefile.am
+
+2014-01-07 18:57:38 +0100 Stephan Bosch <stephan@rename-it.nl> (0172e14c)
+
+ lib-sieve: Changed sieve_script_binary_get_directory() to
+ sieve_script_binary_get_prefix(). This function now returns the binary
+ prefix (file path until '.svbin) rather than just the path of the directory
+ where the binary would be stored.
+
+
+M src/lib-sieve/sieve-script-file.c
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+
+2014-01-07 18:54:57 +0100 Stephan Bosch <stephan@rename-it.nl> (37dc5b60)
+
+ lda-sieve plugin: Changed name of main script.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2014-01-05 11:16:25 +0100 Stephan Bosch <stephan@rename-it.nl> (a20f038b)
+
+ Fixed Valgrind in testsuite using libtool --mode=execute.
+
+
+M Makefile.am
+
+2014-01-05 11:15:45 +0100 Stephan Bosch <stephan@rename-it.nl> (690c4483)
+
+ lib-sieve/util: Fixed small memory leak in program client.
+
+
+M src/lib-sieve/util/program-client-local.c
+
+2014-01-05 10:40:38 +0100 Stephan Bosch <stephan@rename-it.nl> (4021b059)
+
+ Adjusted dovecot.m4 to make second-level plugin packages work properly at
+ distcheck.
+
+
+M m4/dovecot.m4
+
+2014-01-04 02:13:44 +0100 Stephan Bosch <stephan@rename-it.nl> (5e7bf46c)
+
+ lib-sieve/util: program-client: Added support for retrieving side-channel
+ data through extra fds. Some programs can be instructed to output special
+ status information to an extra fd other than stdout or stderr. Also added an
+ option to drop stderr output from program to /dev/null.
+
+
+M src/lib-sieve/util/program-client-local.c
+M src/lib-sieve/util/program-client-private.h
+M src/lib-sieve/util/program-client-remote.c
+M src/lib-sieve/util/program-client.c
+M src/lib-sieve/util/program-client.h
+
+2014-01-01 23:58:16 +0100 Stephan Bosch <stephan@rename-it.nl> (0fc64c0e)
+
+ Updated copyright notices to include the year 2014.
+
+
+M doc/man/pigeonhole.7.in
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-filter.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+M src/lib-managesieve/managesieve-arg.c
+M src/lib-managesieve/managesieve-arg.h
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-managesieve/managesieve-parser.h
+M src/lib-managesieve/managesieve-quote.c
+M src/lib-managesieve/managesieve-quote.h
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/cmp-i-ascii-casemap.c
+M src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/copy/sieve-ext-copy.h
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/date/ext-date.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.h
+M src/lib-sieve/plugins/editheader/ext-editheader-limits.h
+M src/lib-sieve/plugins/editheader/ext-editheader.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify-limits.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/ext-environment-common.h
+M src/lib-sieve/plugins/environment/ext-environment.c
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/ihave/cmd-error.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.h
+M src/lib-sieve/plugins/ihave/ext-ihave-common.c
+M src/lib-sieve/plugins/ihave/ext-ihave-common.h
+M src/lib-sieve/plugins/ihave/ext-ihave.c
+M src/lib-sieve/plugins/ihave/tst-ihave.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-limits.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/metadata/ext-metadata-common.h
+M src/lib-sieve/plugins/metadata/ext-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadata.c
+M src/lib-sieve/plugins/metadata/tst-metadataexists.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/notify/ext-notify-limits.h
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation-seconds.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/cmd-debug-log.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug-common.h
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.c
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.h
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate.c
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/tst-duplicate.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary-code.c
+M src/lib-sieve/sieve-binary-debug.c
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-plugins.c
+M src/lib-sieve/sieve-plugins.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-script-dict.c
+M src/lib-sieve/sieve-script-file.c
+M src/lib-sieve/sieve-script-file.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-stringlist.c
+M src/lib-sieve/sieve-stringlist.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/lib-sieve/tst-truefalse.c
+M src/lib-sieve/util/edit-mail.c
+M src/lib-sieve/util/edit-mail.h
+M src/lib-sieve/util/program-client-local.c
+M src/lib-sieve/util/program-client-private.h
+M src/lib-sieve/util/program-client-remote.c
+M src/lib-sieve/util/program-client.c
+M src/lib-sieve/util/program-client.h
+M src/lib-sieve/util/rfc2822.c
+M src/lib-sieve/util/rfc2822.h
+M src/lib-sievestorage/sieve-storage-list.c
+M src/lib-sievestorage/sieve-storage-list.h
+M src/lib-sievestorage/sieve-storage-private.h
+M src/lib-sievestorage/sieve-storage-quota.c
+M src/lib-sievestorage/sieve-storage-quota.h
+M src/lib-sievestorage/sieve-storage-save.c
+M src/lib-sievestorage/sieve-storage-save.h
+M src/lib-sievestorage/sieve-storage-script.c
+M src/lib-sievestorage/sieve-storage-script.h
+M src/lib-sievestorage/sieve-storage.c
+M src/lib-sievestorage/sieve-storage.h
+M src/managesieve-login/client-authenticate.c
+M src/managesieve-login/client-authenticate.h
+M src/managesieve-login/client.c
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-login-settings-plugin.c
+M src/managesieve-login/managesieve-login-settings-plugin.h
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve-login/managesieve-login-settings.h
+M src/managesieve-login/managesieve-proxy.c
+M src/managesieve-login/managesieve-proxy.h
+M src/managesieve/cmd-capability.c
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-havespace.c
+M src/managesieve/cmd-listscripts.c
+M src/managesieve/cmd-logout.c
+M src/managesieve/cmd-noop.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/cmd-setactive.c
+M src/managesieve/main.c
+M src/managesieve/managesieve-capabilities.c
+M src/managesieve/managesieve-capabilities.h
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+M src/managesieve/managesieve-commands.c
+M src/managesieve/managesieve-commands.h
+M src/managesieve/managesieve-common.h
+M src/managesieve/managesieve-quota.c
+M src/managesieve/managesieve-quota.h
+M src/managesieve/managesieve-settings.c
+M src/managesieve/managesieve-settings.h
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.h
+M src/plugins/sieve-extprograms/cmd-execute.c
+M src/plugins/sieve-extprograms/cmd-filter.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+M src/plugins/sieve-extprograms/ext-execute.c
+M src/plugins/sieve-extprograms/ext-filter.c
+M src/plugins/sieve-extprograms/ext-pipe.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.h
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.c
+M src/plugins/sieve-extprograms/sieve-extprograms-plugin.h
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-arguments.c
+M src/testsuite/testsuite-arguments.h
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-binary.h
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-log.h
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-script.h
+M src/testsuite/testsuite-settings.c
+M src/testsuite/testsuite-settings.h
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/testsuite-substitutions.h
+M src/testsuite/testsuite-variables.c
+M src/testsuite/testsuite-variables.h
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-action.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2013-12-30 17:54:23 +0100 Stephan Bosch <stephan@rename-it.nl> (41018d2e)
+
+ lib-sieve: Added macros for argument generation errors.
+
+
+M src/lib-sieve/sieve-commands.h
+
+2013-12-28 09:43:33 +0100 Stephan Bosch <stephan@rename-it.nl> (021a007e)
+
+ Fixed messy documentation indent caused by earlier change.
+
+
+M doc/extensions/spamtest-virustest.txt
+
+2013-12-28 09:41:24 +0100 Stephan Bosch <stephan@rename-it.nl> (8e67eb94)
+
+ lib-sieve: spamtest/virustest extensions: Tests were erroneously performed
+ against the original message. When used together with extprograms filter to
+ add the spam headers, the changes were not being used by the spamtest and
+ virustest extensions.
+
+
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+A tests/plugins/extprograms/bin/spamc
+M tests/plugins/extprograms/filter/execute.svtest
+
+2013-12-28 09:24:42 +0100 Stephan Bosch <stephan@rename-it.nl> (b50a4b4f)
+
+ doc/extensions/spamtest-virustest.txt: Clarified that these extensions use
+ the extended POSIX regular expressions.
+
+
+M doc/extensions/spamtest-virustest.txt
+
+2013-12-25 21:57:38 +0100 Stephan Bosch <stephan@rename-it.nl> (a9240aba)
+
+ Fixed consistent spelling mistake.
+
+
+M NEWS
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/util/edit-mail.c
+M tests/compile/redirect.sieve
+
+2013-12-25 21:48:15 +0100 Stephan Bosch <stephan@rename-it.nl> (0f0cbe31)
+
+ Fixed compiler warning.
+
+
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.c
+
+2013-12-25 21:45:47 +0100 Stephan Bosch <stephan@rename-it.nl> (9fba343d)
+
+ sieve_extprograms plugin: Changed program client such that the filter
+ command only needs to create a temporary file when the program output is
+ very large. This commit also includes a small change that makes it possible
+ to run a program several times.
+
+
+M src/lib-sieve/util/program-client-local.c
+M src/lib-sieve/util/program-client-private.h
+M src/lib-sieve/util/program-client-remote.c
+M src/lib-sieve/util/program-client.c
+M src/lib-sieve/util/program-client.h
+M src/plugins/sieve-extprograms/cmd-filter.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.h
+
+2013-12-25 21:42:05 +0100 Stephan Bosch <stephan@rename-it.nl> (b0dfde0e)
+
+ lib-sieve: Added post_save hook to binary object.
+
+
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary.h
+
+2013-12-25 21:40:19 +0100 Stephan Bosch <stephan@rename-it.nl> (b59f6ec6)
+
+ lib-sieve: Added method to script object for obtaining the directory where
+ the script binary is stored.
+
+
+M src/lib-sieve/sieve-script-dict.c
+M src/lib-sieve/sieve-script-file.c
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+
+2013-12-25 21:36:55 +0100 Stephan Bosch <stephan@rename-it.nl> (d673f117)
+
+ lib-sieve: Added path to temporary directory to Sieve instance object.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2013-12-21 21:32:13 +0100 Stephan Bosch <stephan@rename-it.nl> (160ddddd)
+
+ Moved script-client from extprograms plugin to lib-sieve/util and renamed it
+ to program-client for generic use.
+
+
+M src/lib-sieve/util/Makefile.am
+R058 src/plugins/sieve-extprograms/script-client-local.c src/lib-sieve/util/program-client-local.c
+A src/lib-sieve/util/program-client-private.h
+R051 src/plugins/sieve-extprograms/script-client-remote.c src/lib-sieve/util/program-client-remote.c
+A src/lib-sieve/util/program-client.c
+A src/lib-sieve/util/program-client.h
+M src/plugins/sieve-extprograms/Makefile.am
+D src/plugins/sieve-extprograms/script-client-private.h
+D src/plugins/sieve-extprograms/script-client.c
+D src/plugins/sieve-extprograms/script-client.h
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+
+2013-12-21 21:10:13 +0100 Stephan Bosch <stephan@rename-it.nl> (389457bb)
+
+ lib-sieve: Moved utility source modules to sub-directory. In the future,
+ much of these can be moved to Dovecot.
+
+
+M configure.ac
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/editheader/Makefile.am
+M src/lib-sieve/plugins/enotify/mailto/Makefile.am
+M src/lib-sieve/plugins/ihave/Makefile.am
+M src/lib-sieve/plugins/metadata/Makefile.am
+M src/lib-sieve/plugins/notify/Makefile.am
+M src/lib-sieve/plugins/subaddress/Makefile.am
+M src/lib-sieve/plugins/vacation/Makefile.am
+M src/lib-sieve/plugins/vnd.dovecot/debug/Makefile.am
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/Makefile.am
+A src/lib-sieve/util/Makefile.am
+R100 src/lib-sieve/edit-mail.c src/lib-sieve/util/edit-mail.c
+R100 src/lib-sieve/edit-mail.h src/lib-sieve/util/edit-mail.h
+R100 src/lib-sieve/rfc2822.c src/lib-sieve/util/rfc2822.c
+R100 src/lib-sieve/rfc2822.h src/lib-sieve/util/rfc2822.h
+
+2013-12-21 15:09:32 +0100 Stephan Bosch <stephan@rename-it.nl> (9c96a4c3)
+
+ Sieve extprograms plugin: Fixed 'Bad filedescriptor' error occurring when
+ disconnecting script client.
+
+
+M src/plugins/sieve-extprograms/script-client.c
+
+2013-12-13 21:35:58 +0100 Stephan Bosch <stephan@rename-it.nl> (16e57463)
+
+ Sieve extprograms plugin: Fixed fd leak and handling of output shutdown.
+ Output stream remained open, including the flush io, causing a second assert
+ failure. Whether this fixes the problem entirely remains to be seen.
+
+
+M src/plugins/sieve-extprograms/script-client-local.c
+M src/plugins/sieve-extprograms/script-client.c
+
+2013-11-20 19:34:28 +0100 Stephan Bosch <stephan@rename-it.nl> (e556155c)
+
+ Small improvements to the test suite.
+
+
+M tests/test-header.svtest
+
+2013-11-15 23:13:32 +0100 Stephan Bosch <stephan@rename-it.nl> (ae7d86cd)
+
+ Sieve extprograms plugin: Improved handing of extension configuration.
+
+
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+
+2013-11-11 01:44:19 +0100 Stephan Bosch <stephan@rename-it.nl> (5d3094d7)
+
+ Merged changes from Pigeonhole v0.3 tree.
+
+
+2013-11-11 01:31:08 +0100 Stephan Bosch <stephan@rename-it.nl> (a59a694e)
+
+ lib-sieve: deprecated notify extension: Fixed segfault problems in message
+ string substitution.
+
+
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M tests/deprecated/notify/basic.svtest
+
+2013-11-09 11:42:07 +0100 Stephan Bosch <stephan@rename-it.nl> (51fee5e5)
+
+ lib-sievestorage: Fixed active link verification to handle redundant path
+ slashes correctly.
+
+
+M src/lib-sievestorage/sieve-storage-script.c
+
+2013-11-03 02:02:56 +0100 Stephan Bosch <stephan@rename-it.nl> (3d455add)
+
+ lib-sieve: Added skeletons for mboxmetadata and servermetadata extensions.
+ This is still an unfinished feature.
+
+
+M configure.ac
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/metadata/Makefile.am
+A src/lib-sieve/plugins/metadata/ext-metadata-common.h
+A src/lib-sieve/plugins/metadata/ext-metadata.c
+A src/lib-sieve/plugins/metadata/tst-metadata.c
+A src/lib-sieve/plugins/metadata/tst-metadataexists.c
+M src/lib-sieve/sieve-extensions.c
+
+2013-10-11 07:57:21 +0200 Stephan Bosch <stephan@rename-it.nl> (b23aa783)
+
+ lib-sieve: vacation extension: Fixed interaction of
+ sieve_vacation_dont_check_recipient with sieve_vacation_send_from_recipient
+ setting. If sieve_vacation_dont_check_recipient was active,
+ sieve_vacation_send_from_recipient had no effect.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2013-10-06 22:14:01 +0200 Stephan Bosch <stephan@rename-it.nl> (5033c8cd)
+
+ Sieve extprograms plugin: Forgot to disable the alarm() timeouts set for
+ script execution. This may cause later syscalls to exit with EINTR
+ unexpectedly.
+
+
+M src/plugins/sieve-extprograms/script-client-local.c
+
+2013-09-26 21:44:37 +0200 Stephan Bosch <stephan@rename-it.nl> (9d606b9f)
+
+ Added signature for changeset 87d8f0aae957
+
+
+M .hgsigs
+
+2013-09-26 21:43:09 +0200 Stephan Bosch <stephan@rename-it.nl> (5757a3f0)
+
+ Added signature for changeset 2176d400eca4
+
+
+M .hgsigs
+
+2013-09-26 21:41:35 +0200 Stephan Bosch <stephan@rename-it.nl> (fb73bf70)
+
+ Added tag 0.3.6 for changeset 87d8f0aae957
+
+
+2013-09-26 21:41:24 +0200 Stephan Bosch <stephan@rename-it.nl> (1d852227)
+
+ Released v0.3.6 for Dovecot v2.1.17.
+
+
+M NEWS
+M configure.in
+
+2013-09-26 21:40:34 +0200 Stephan Bosch <stephan@rename-it.nl> (eeeb8cbe)
+
+ Added tag 0.4.2 for changeset 2176d400eca4
+
+
+2013-09-26 21:40:22 +0200 Stephan Bosch <stephan@rename-it.nl> (a0808437)
+
+ Released v0.4.2 for Dovecot v2.2.6.
+
+
+M NEWS
+M configure.ac
+
+2013-09-23 22:01:38 +0200 Stephan Bosch <stephan@rename-it.nl> (18f75c6b)
+
+ lib-sieve: vacation extension: Added support for sending vacation messages
+ with an actual sender. Use sieve_vacation_send_from_recipient to enable this
+ behavior. Documentation in doc/extensions/vacation.txt is updated.
+
+
+M doc/extensions/vacation.txt
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M tests/extensions/vacation/message.svtest
+
+2013-09-23 20:58:02 +0200 Stephan Bosch <stephan@rename-it.nl> (2e1a3ddd)
+
+ managesieve: Updated to changes in Dovecot listeners regarding SO_REUSEPORT.
+
+
+M src/managesieve-login/managesieve-login-settings.c
+
+2013-09-22 11:51:38 +0200 Stephan Bosch <stephan@rename-it.nl> (f995169c)
+
+ doveadm sieve plugin: Fixed the `Invalid value for default sieve attribute'
+ problem. The attribute type code data was allocated on the stack rather than
+ statically, causing the returned stream to point to invalid data.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-09-17 23:57:05 +0200 Stephan Bosch <stephan@rename-it.nl> (11e2c26c)
+
+ doveadm sieve plugin: Changed root attribute for Sieve.
+
+
+M src/lib-sievestorage/sieve-storage.h
+
+2013-09-17 23:55:59 +0200 Stephan Bosch <stephan@rename-it.nl> (e6be8418)
+
+ doveadm sieve plugin: Small initialization fix.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-09-16 01:15:55 +0200 Stephan Bosch <stephan@rename-it.nl> (e01cb4d9)
+
+ Merged changes from v0.3 tree.
+
+
+2013-09-16 00:55:29 +0200 Stephan Bosch <stephan@rename-it.nl> (ed345afe)
+
+ lib-sieve: variables extension: Fixed code corruption bug in 'set' command.
+ Bug whould occur when modifier was used and the value became "" at some
+ point. In that case not all operands (modifiers) were read, causing the
+ subsequent operation to start at an erroneous position.
+
+
+M src/lib-sieve/plugins/variables/cmd-set.c
+
+2013-09-16 00:46:21 +0200 Stephan Bosch <stephan@rename-it.nl> (5fe59daf)
+
+ sieve-dump tool: Fixed hex output. Messed up signed/unsigned characters.
+
+
+M src/lib-sieve/sieve-binary-dumper.c
+
+2013-09-16 00:43:55 +0200 Stephan Bosch <stephan@rename-it.nl> (e56c6e53)
+
+ lib-sieve: variables extension: fixed data stack problem in 'set' command.
+
+
+M src/lib-sieve/plugins/variables/cmd-set.c
+
+2013-09-15 17:47:53 +0200 Stephan Bosch <stephan@rename-it.nl> (0449820b)
+
+ lib-sieve: Fixed code block read bounds checking.
+
+
+M src/lib-sieve/sieve-binary-code.c
+
+2013-09-15 12:47:33 +0200 Stephan Bosch <stephan@rename-it.nl> (d8269667)
+
+ doveadm-sieve plugin: Fixed segfault bug.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-09-15 12:43:25 +0200 Stephan Bosch <stephan@rename-it.nl> (8a861359)
+
+ Merged changes from Pigeonhole 0.3 tree.
+
+
+2013-09-15 12:19:10 +0200 Stephan Bosch <stephan@rename-it.nl> (5d695ea3)
+
+ lib-sieve: spamtest virustest extensions: Fixed end-of-string testing in
+ configuration parser.
+
+
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+
+2013-09-04 18:12:44 +0200 Stephan Bosch <stephan@rename-it.nl> (05f714c2)
+
+ doveadm-sieve plugin: Fixed a few crash issues. Patches by Timo Sirainen.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-08-15 21:07:56 +0200 Stephan Bosch <stephan@rename-it.nl> (219ad23f)
+
+ Merged changes from Pigeonhole v0.3 tree.
+
+
+2013-08-15 21:02:37 +0200 Stephan Bosch <stephan@rename-it.nl> (dbf6ec23)
+
+ Various fixes for CLang warnings. Patch by Timo Sirainen (modified).
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-validator.c
+M src/managesieve-login/client-authenticate.c
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite.c
+
+2013-08-15 20:48:54 +0200 Stephan Bosch <stephan@rename-it.nl> (932477e5)
+
+ lib-sieve: include extension: Fixed implementation of new :options flag.
+ Mixed up pre-existing boolean once parameter with new flags parameter. This
+ probably means that :optional partially implied :once for previous
+ revisions.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+
+2013-08-15 20:15:08 +0200 Stephan Bosch <stephan@rename-it.nl> (a23ea5cd)
+
+ lda-sieve plugin: Don't access already freed memory when deinitializing.
+ Patch by Timo Sirainen (modified).
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2013-08-15 19:59:18 +0200 Stephan Bosch <stephan@rename-it.nl> (65847885)
+
+ extprograms plugin: Compiler warning fix for 32bit systems. Patch by Timo
+ Sirainen.
+
+
+M src/plugins/sieve-extprograms/script-client-local.c
+
+2013-07-10 23:34:34 +0200 Stephan Bosch <stephan@rename-it.nl> (8dc55ce8)
+
+ Updated Sieve extension status in comments.
+
+
+M src/lib-sieve/plugins/editheader/ext-editheader.c
+M src/lib-sieve/plugins/environment/ext-environment.c
+M src/lib-sieve/plugins/ihave/ext-ihave.c
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M src/lib-sieve/plugins/vacation/ext-vacation-seconds.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate.c
+M src/plugins/sieve-extprograms/ext-execute.c
+M src/plugins/sieve-extprograms/ext-filter.c
+M src/plugins/sieve-extprograms/ext-pipe.c
+
+2013-07-03 22:06:58 +0200 Stephan Bosch <stephan@rename-it.nl> (c705c2a2)
+
+ Added signature for changeset f1535e2255cd
+
+
+M .hgsigs
+
+2013-07-03 22:05:13 +0200 Stephan Bosch <stephan@rename-it.nl> (383ec2ec)
+
+ Added tag 0.4.1 for changeset f1535e2255cd
+
+
+2013-07-03 22:05:04 +0200 Stephan Bosch <stephan@rename-it.nl> (3ae0c2bb)
+
+ Released v0.4.1 for Dovecot v2.2.4.
+
+
+M NEWS
+M configure.ac
+
+2013-07-03 21:35:12 +0200 Stephan Bosch <stephan@rename-it.nl> (e29f2b98)
+
+ Merged changes from Pigeonhole v0.3 tree.
+
+
+2013-06-18 22:04:50 +0200 Stephan Bosch <stephan@rename-it.nl> (2e5ed35b)
+
+ Fixed deprecated INCLUDE= assignment in Makefile.am
+
+
+M src/lib-sievestorage/Makefile.am
+
+2013-06-18 08:34:26 +0200 Stephan Bosch <stephan@rename-it.nl> (f8b9adf0)
+
+ lib-sievestorage: Removed PATH_MAX limitation for active symlink. Fixes
+ issue for GNU/Hurd.
+
+
+M src/lib-sievestorage/sieve-storage-script.c
+
+2013-06-18 08:24:40 +0200 Stephan Bosch <stephan@rename-it.nl> (46bf4c6c)
+
+ Fixed line endings in X-Sieve headers added by redirect command. Modified
+ patch by Andriy Syrovenko.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2013-06-18 08:11:37 +0200 Stephan Bosch <stephan@rename-it.nl> (bb90042a)
+
+ Don't access ns->storage. Patch by Timo Sirainen.
+
+
+M src/sieve-tools/sieve-filter.c
+
+2013-06-02 16:08:22 +0200 Stephan Bosch <stephan@rename-it.nl> (af703f2e)
+
+ Finished support for temporary failures. This change is bigger than I would
+ have liked, so this needs to be tested more.
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-script-dict.c
+M src/lib-sieve/sieve-script-file.c
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sievestorage/sieve-storage.c
+M src/managesieve/managesieve-client.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/sieve-extprograms/cmd-pipe.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite.c
+
+2013-05-24 13:12:24 +0200 Stephan Bosch <stephan@rename-it.nl> (f47475ae)
+
+ Merged changes from Pigeonhole v0.3 tree.
+
+
+2013-05-24 13:07:23 +0200 Stephan Bosch <stephan@rename-it.nl> (bbb5be0c)
+
+ managesieve-login: Fixed '[' ']' stupidity for response codes. Emerged when
+ Sieve and ManageSieve were merged into Pigeonhole.
+
+
+M src/managesieve-login/client.c
+
+2013-05-20 21:20:04 +0200 Stephan Bosch <stephan@rename-it.nl> (ba95ae62)
+
+ Sieve extprograms plugin: Fixed interaction between pipe command and remote
+ script service. The output from the script service was never read, causing a
+ broken pipe error at the script service. Apparently, this was broken since
+ the I/O handling for extprograms was last revised.
+
+
+M src/plugins/sieve-extprograms/script-client-remote.c
+M src/plugins/sieve-extprograms/script-client.c
+
+2013-05-15 21:59:32 +0200 Stephan Bosch <stephan@rename-it.nl> (51c2d126)
+
+ lib-sieve: Fixed datastack problem in message header composition.
+
+
+M src/lib-sieve/rfc2822.c
+
+2013-05-12 19:14:18 +0200 Stephan Bosch <stephan@rename-it.nl> (66085257)
+
+ Fixed setting name in example-config/conf.d/20-managesieve.conf.
+
+
+M doc/example-config/conf.d/20-managesieve.conf
+
+2013-05-09 16:39:41 +0200 Stephan Bosch <stephan@rename-it.nl> (8e08342a)
+
+ Forgot to update Dovecot version in README and man pages.
+
+
+M README
+M doc/man/pigeonhole.7.in
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-filter.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+
+2013-05-09 15:41:42 +0200 Stephan Bosch <stephan@rename-it.nl> (cf64d222)
+
+ Added signature for changeset 3a8dc1250e9b
+
+
+M .hgsigs
+
+2013-05-09 15:40:25 +0200 Stephan Bosch <stephan@rename-it.nl> (71e1f2a2)
+
+ Added tag 0.4.0 for changeset 3a8dc1250e9b
+
+
+2013-05-09 15:39:17 +0200 Stephan Bosch <stephan@rename-it.nl> (9791b4af)
+
+ Released v0.4.0 for Dovecot v2.2.1.
+
+
+2013-05-09 15:21:43 +0200 Stephan Bosch <stephan@rename-it.nl> (58d7ff3d)
+
+ Added signature for changeset 374ec9399958
+
+
+M .hgsigs
+
+2013-05-09 15:19:32 +0200 Stephan Bosch <stephan@rename-it.nl> (d228de08)
+
+ Updated dovecot.m4 to latest version.
+
+
+M m4/dovecot.m4
+
+2013-05-09 15:18:13 +0200 Stephan Bosch <stephan@rename-it.nl> (a41a16ce)
+
+ Added tag 0.3.5 for changeset 374ec9399958
+
+
+2013-05-09 15:18:05 +0200 Stephan Bosch <stephan@rename-it.nl> (46755a82)
+
+ Released v0.3.5 for Dovecot v2.1.16.
+
+
+M NEWS
+M configure.in
+
+2013-05-09 15:11:13 +0200 Stephan Bosch <stephan@rename-it.nl> (fb122b93)
+
+ Fixed problem in `make distcheck`. Added --disable-shared to
+ DISTCHECK_CONFIGURE_FLAGS (in dovecot.m4) to prevent libtool from relinking
+ the libraries.
+
+
+M m4/dovecot.m4
+
+2013-05-09 12:22:39 +0200 Stephan Bosch <stephan@rename-it.nl> (19e0ed1e)
+
+ Removed UNSTABLE notice from configure.
+
+
+M configure.ac
+
+2013-05-09 12:21:31 +0200 Stephan Bosch <stephan@rename-it.nl> (d0367e8b)
+
+ Merged changed from Pigeonhole v0.3.
+
+
+2013-05-09 11:28:44 +0200 Stephan Bosch <stephan@rename-it.nl> (77ec8981)
+
+ doveadm-sieve: Fixed synchronization of script deletions. Sieve storage now
+ updates sieve attributes in the user's INBOX if used by ManageSieve.
+
+
+M src/lib-sievestorage/sieve-storage-private.h
+M src/lib-sievestorage/sieve-storage-save.c
+M src/lib-sievestorage/sieve-storage-script.c
+M src/lib-sievestorage/sieve-storage.c
+M src/lib-sievestorage/sieve-storage.h
+M src/managesieve/managesieve-client.c
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-05-06 22:48:59 +0200 Stephan Bosch <stephan@rename-it.nl> (9337fee9)
+
+ doveadm-sieve: Fix ping-pong problem in active Sieve script synchronization.
+ Patch by Timo Sirainen.
+
+
+M src/lib-sievestorage/sieve-storage.c
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-05-02 21:37:36 +0200 Stephan Bosch <stephan@rename-it.nl> (6b7fe6f5)
+
+ lib-sieve: editheader extension: Fixed interaction with body extension.
+ Forgot to rewind mail stream before header parsing. Wrapped mail stream is
+ obtained long before parsing, so if it is used in the mean time, it must be
+ rewound to the beginning.
+
+
+M src/lib-sieve/edit-mail.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M tests/extensions/editheader/deleteheader.svtest
+
+2013-04-23 22:55:03 +0200 Stephan Bosch <stephan@rename-it.nl> (59625262)
+
+ doveadm-sieve: Fixed mtime updates. Patch by Timo Sirainen.
+
+
+M src/lib-sievestorage/sieve-storage-private.h
+M src/lib-sievestorage/sieve-storage-save.c
+M src/lib-sievestorage/sieve-storage-script.c
+M src/lib-sievestorage/sieve-storage-script.h
+M src/lib-sievestorage/sieve-storage.c
+M src/managesieve/cmd-setactive.c
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-04-20 21:27:15 +0200 Stephan Bosch <stephan@rename-it.nl> (03a16d96)
+
+ doveadm-sieve: Set mtime of modified scripts and sieve dir to timestamp from
+ dsync. Still does not fix the ping-pong issue.
+
+
+M src/lib-sievestorage/sieve-storage-save.c
+M src/lib-sievestorage/sieve-storage-save.h
+M src/lib-sievestorage/sieve-storage.c
+M src/lib-sievestorage/sieve-storage.h
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-04-19 23:21:35 +0200 Stephan Bosch <stephan@rename-it.nl> (3b6c9b06)
+
+ doveadm-sieve: Made active script last_change time always dependent on
+ sieve_dir mtime. Change is preliminary. Still doing some experiments,
+ 'ping-pong' problem is not solved.
+
+
+M src/lib-sievestorage/sieve-storage-save.c
+M src/lib-sievestorage/sieve-storage-script.c
+
+2013-04-19 22:26:32 +0200 Stephan Bosch <stephan@rename-it.nl> (06bfdd06)
+
+ doveadm-sieve: Prevented Sieve storage from logging useless while
+ synchronizing. Added flag to prevent warnings about non-link active scripts
+ and disable critical error logging. A rather fundamental synchronization
+ problem remains to be solved.
+
+
+M src/lib-sievestorage/sieve-storage-private.h
+M src/lib-sievestorage/sieve-storage-script.c
+M src/lib-sievestorage/sieve-storage.c
+M src/lib-sievestorage/sieve-storage.h
+M src/managesieve/managesieve-client.c
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-04-19 09:46:49 +0200 Stephan Bosch <stephan@rename-it.nl> (3b0fc8c3)
+
+ Made preparations for first v0.4 release.
+
+
+M INSTALL
+M NEWS
+M README
+M TODO
+M doc/plugins/sieve_extprograms.txt
+
+2013-04-19 09:45:15 +0200 Stephan Bosch <stephan@rename-it.nl> (35c7ebad)
+
+ Fixed distcheck failure on sieve_extprograms plugin testsuite.
+
+
+M src/testsuite/testsuite-variables.c
+A tests/plugins/extprograms/bin/sleep10
+M tests/plugins/extprograms/execute/command.svtest
+M tests/plugins/extprograms/execute/errors.svtest
+M tests/plugins/extprograms/execute/execute.svtest
+M tests/plugins/extprograms/filter/command.svtest
+M tests/plugins/extprograms/filter/errors.svtest
+M tests/plugins/extprograms/filter/execute.svtest
+M tests/plugins/extprograms/pipe/command.svtest
+M tests/plugins/extprograms/pipe/errors.svtest
+M tests/plugins/extprograms/pipe/errors/timeout.sieve
+M tests/plugins/extprograms/pipe/execute.svtest
+
+2013-04-19 09:15:01 +0200 Stephan Bosch <stephan@rename-it.nl> (aa2cfbaa)
+
+ Fixed test suite for vnd.dovecot.execute extension. Testsuite hostname is
+ now true local hostname.
+
+
+M tests/plugins/extprograms/execute/execute.svtest
+
+2013-04-12 20:25:02 +0200 Stephan Bosch <stephan@rename-it.nl> (0e0a359c)
+
+ Fixed doveconf crash caused by previous change. Patch by Timo Sirainen.
+
+
+M src/lib-sieve/sieve.c
+
+2013-04-11 22:40:07 +0200 Stephan Bosch <stephan@rename-it.nl> (9fc9fa97)
+
+ lib-sieve: environment extension: Finally finished this extension a much as
+ possible. Some environment items in the base specification are not (yet)
+ applicable to Dovecot and are therefore not supported.
+
+
+M README
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M tests/extensions/environment/basic.svtest
+M tests/extensions/environment/rfc.svtest
+
+2013-04-11 20:42:41 +0200 Stephan Bosch <stephan@rename-it.nl> (7d4ca027)
+
+ doveadm-sieve: Updated to dsync changes in Dovecot mail storage API. Patch
+ by Timo Sirainen.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-04-07 23:42:04 +0200 Stephan Bosch <stephan@rename-it.nl> (365c8db9)
+
+ Compile warning fixes.
+
+
+M src/plugins/sieve-extprograms/script-client-remote.c
+M src/plugins/sieve-extprograms/sieve-extprograms-common.h
+
+2013-04-07 05:12:57 +0200 Stephan Bosch <stephan@rename-it.nl> (100602de)
+
+ testsuite: fixed local timezone dependency in date extension tests.
+
+
+M tests/extensions/date/basic.svtest
+
+2013-04-07 02:30:11 +0200 Stephan Bosch <stephan@rename-it.nl> (6744a189)
+
+ Updated TODO to include items related to sieve_extprograms plugin.
+
+
+M TODO
+
+2013-04-07 02:25:46 +0200 Stephan Bosch <stephan@rename-it.nl> (b08ad1e5)
+
+ Added sieve_extprograms plugin to the main Pigeonhole tree. It is still a
+ plugin, but no longer a separate package.
+
+
+M INSTALL
+M Makefile.am
+M configure.ac
+M doc/Makefile.am
+A doc/example-config/conf.d/90-sieve-extprograms.conf
+M doc/example-config/conf.d/90-sieve.conf
+M doc/example-config/conf.d/Makefile.am
+A doc/plugins/sieve_extprograms.txt
+A doc/rfc/spec-bosch-sieve-extprograms.txt
+A doc/rfc/xml/reference.DSN.xml
+A doc/rfc/xml/reference.MDN.xml
+A doc/rfc/xml/reference.NET-UNICODE.xml
+A doc/rfc/xml/reference.RFC.3894.xml
+A doc/rfc/xml/reference.RFC.5429.xml
+A doc/rfc/xml/reference.SUBADDRESS.xml
+A doc/rfc/xml/reference.UTF-8.xml
+A doc/rfc/xml/spec-bosch-sieve-extprograms.xml
+M src/plugins/Makefile.am
+A src/plugins/sieve-extprograms/Makefile.am
+A src/plugins/sieve-extprograms/cmd-execute.c
+A src/plugins/sieve-extprograms/cmd-filter.c
+A src/plugins/sieve-extprograms/cmd-pipe.c
+A src/plugins/sieve-extprograms/ext-execute.c
+A src/plugins/sieve-extprograms/ext-filter.c
+A src/plugins/sieve-extprograms/ext-pipe.c
+A src/plugins/sieve-extprograms/script-client-local.c
+A src/plugins/sieve-extprograms/script-client-private.h
+A src/plugins/sieve-extprograms/script-client-remote.c
+A src/plugins/sieve-extprograms/script-client.c
+A src/plugins/sieve-extprograms/script-client.h
+A src/plugins/sieve-extprograms/sieve-extprograms-common.c
+A src/plugins/sieve-extprograms/sieve-extprograms-common.h
+A src/plugins/sieve-extprograms/sieve-extprograms-plugin.c
+A src/plugins/sieve-extprograms/sieve-extprograms-plugin.h
+A tests/plugins/extprograms/bin/addheader
+A tests/plugins/extprograms/bin/cat
+A tests/plugins/extprograms/bin/env
+A tests/plugins/extprograms/bin/frame
+A tests/plugins/extprograms/bin/modify
+A tests/plugins/extprograms/bin/program
+A tests/plugins/extprograms/bin/replace
+A tests/plugins/extprograms/bin/sleep2
+A tests/plugins/extprograms/bin/stderr
+A tests/plugins/extprograms/errors.svtest
+A tests/plugins/extprograms/errors/arguments.sieve
+A tests/plugins/extprograms/errors/programname.sieve
+A tests/plugins/extprograms/execute/command.svtest
+A tests/plugins/extprograms/execute/errors.svtest
+A tests/plugins/extprograms/execute/errors/syntax.sieve
+A tests/plugins/extprograms/execute/errors/variables.sieve
+A tests/plugins/extprograms/execute/execute.svtest
+A tests/plugins/extprograms/filter/command.svtest
+A tests/plugins/extprograms/filter/errors.svtest
+A tests/plugins/extprograms/filter/errors/syntax.sieve
+A tests/plugins/extprograms/filter/execute.svtest
+A tests/plugins/extprograms/pipe/command.svtest
+A tests/plugins/extprograms/pipe/errors.svtest
+A tests/plugins/extprograms/pipe/errors/syntax.sieve
+A tests/plugins/extprograms/pipe/errors/timeout.sieve
+A tests/plugins/extprograms/pipe/execute.svtest
+
+2013-04-07 00:58:40 +0200 Stephan Bosch <stephan@rename-it.nl> (9279e66b)
+
+ Updated TODO.
+
+
+M TODO
+
+2013-04-07 00:41:19 +0200 Stephan Bosch <stephan@rename-it.nl> (f3ae16df)
+
+ Merged changes from Pigeonhole v0.3 tree.
+
+
+2013-04-07 00:33:41 +0200 Stephan Bosch <stephan@rename-it.nl> (f4ceacd2)
+
+ doveadm-sieve: Fixed handling of non-link active script. Unsetting the
+ normal active script attribute would 'rescue' the non-link script and turn
+ it into a symlink.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-04-06 22:37:46 +0200 Stephan Bosch <stephan@rename-it.nl> (08892a5d)
+
+ Added signature for changeset 493202676845
+
+
+M .hgsigs
+
+2013-04-06 22:37:39 +0200 Stephan Bosch <stephan@rename-it.nl> (4db2bd64)
+
+ Added tag 0.3.4 for changeset 493202676845
+
+
+2013-04-06 22:37:02 +0200 Stephan Bosch <stephan@rename-it.nl> (173e9dd5)
+
+ Released v0.3.4 for Dovecot v2.1.16.
+
+
+M NEWS
+M TODO
+M configure.in
+
+2013-04-06 16:54:57 +0200 Stephan Bosch <stephan@rename-it.nl> (8c9ef2fc)
+
+ Updated copyright notices to include the year 2013.
+
+
+M src/lib-managesieve/managesieve-arg.c
+M src/lib-managesieve/managesieve-arg.h
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-managesieve/managesieve-parser.h
+M src/lib-managesieve/managesieve-quote.c
+M src/lib-managesieve/managesieve-quote.h
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/cmp-i-ascii-casemap.c
+M src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/edit-mail.c
+M src/lib-sieve/edit-mail.h
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/copy/sieve-ext-copy.h
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/date/ext-date.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.h
+M src/lib-sieve/plugins/editheader/ext-editheader-limits.h
+M src/lib-sieve/plugins/editheader/ext-editheader.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify-limits.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/ext-environment-common.h
+M src/lib-sieve/plugins/environment/ext-environment.c
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/ihave/cmd-error.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.h
+M src/lib-sieve/plugins/ihave/ext-ihave-common.c
+M src/lib-sieve/plugins/ihave/ext-ihave-common.h
+M src/lib-sieve/plugins/ihave/ext-ihave.c
+M src/lib-sieve/plugins/ihave/tst-ihave.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-limits.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/notify/ext-notify-limits.h
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation-seconds.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/cmd-debug-log.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug-common.h
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.c
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.h
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate.c
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/tst-duplicate.c
+M src/lib-sieve/rfc2822.c
+M src/lib-sieve/rfc2822.h
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary-code.c
+M src/lib-sieve/sieve-binary-debug.c
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-plugins.c
+M src/lib-sieve/sieve-plugins.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-script-dict.c
+M src/lib-sieve/sieve-script-file.c
+M src/lib-sieve/sieve-script-file.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-stringlist.c
+M src/lib-sieve/sieve-stringlist.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/lib-sieve/tst-truefalse.c
+M src/lib-sievestorage/sieve-storage-list.c
+M src/lib-sievestorage/sieve-storage-list.h
+M src/lib-sievestorage/sieve-storage-private.h
+M src/lib-sievestorage/sieve-storage-quota.c
+M src/lib-sievestorage/sieve-storage-quota.h
+M src/lib-sievestorage/sieve-storage-save.c
+M src/lib-sievestorage/sieve-storage-save.h
+M src/lib-sievestorage/sieve-storage-script.c
+M src/lib-sievestorage/sieve-storage-script.h
+M src/lib-sievestorage/sieve-storage.c
+M src/lib-sievestorage/sieve-storage.h
+M src/managesieve-login/client-authenticate.c
+M src/managesieve-login/client-authenticate.h
+M src/managesieve-login/client.c
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-login-settings-plugin.c
+M src/managesieve-login/managesieve-login-settings-plugin.h
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve-login/managesieve-login-settings.h
+M src/managesieve-login/managesieve-proxy.c
+M src/managesieve-login/managesieve-proxy.h
+M src/managesieve/cmd-capability.c
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-havespace.c
+M src/managesieve/cmd-listscripts.c
+M src/managesieve/cmd-logout.c
+M src/managesieve/cmd-noop.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/cmd-setactive.c
+M src/managesieve/main.c
+M src/managesieve/managesieve-capabilities.c
+M src/managesieve/managesieve-capabilities.h
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+M src/managesieve/managesieve-commands.c
+M src/managesieve/managesieve-commands.h
+M src/managesieve/managesieve-common.h
+M src/managesieve/managesieve-quota.c
+M src/managesieve/managesieve-quota.h
+M src/managesieve/managesieve-settings.c
+M src/managesieve/managesieve-settings.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.h
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-arguments.c
+M src/testsuite/testsuite-arguments.h
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-binary.h
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-log.h
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-script.h
+M src/testsuite/testsuite-settings.c
+M src/testsuite/testsuite-settings.h
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/testsuite-substitutions.h
+M src/testsuite/testsuite-variables.c
+M src/testsuite/testsuite-variables.h
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-action.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2013-04-05 18:08:19 +0200 Stephan Bosch <stephan@rename-it.nl> (572bc510)
+
+ doveadm-sieve: Adjusted to Dovecot API change.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-04-03 00:08:05 +0200 Stephan Bosch <stephan@rename-it.nl> (dff5598c)
+
+ doveadm-sieve: Prevented initializing the Sieve storage multiple times.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-04-02 23:14:37 +0200 Stephan Bosch <stephan@rename-it.nl> (5a27c7eb)
+
+ Merged changes from Pigeonhole v0.3 tree.
+
+
+2013-04-02 23:14:13 +0200 Stephan Bosch <stephan@rename-it.nl> (c2b71b1b)
+
+ doveadm-sieve: Implemented handling the situation when the main active
+ script is a regular file. Tested whether this change breaks ManageSieve and
+ basic dsync, but not much more. More tests pending. If you use sync be
+ careful with this commit.
+
+
+M src/lib-sieve/sieve-plugins.c
+M src/lib-sievestorage/sieve-storage-list.c
+M src/lib-sievestorage/sieve-storage-save.c
+M src/lib-sievestorage/sieve-storage-save.h
+M src/lib-sievestorage/sieve-storage-script.c
+M src/lib-sievestorage/sieve-storage-script.h
+M src/lib-sievestorage/sieve-storage.c
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-04-02 23:09:14 +0200 Stephan Bosch <stephan@rename-it.nl> (7261c0cb)
+
+ lib-sieve: Fixed plugin module load functionality. Initializing multiple
+ Sieve instances would hang.
+
+
+M src/lib-sieve/sieve-plugins.c
+
+2013-03-28 22:14:21 +0100 Stephan Bosch <stephan@rename-it.nl> (824b68d6)
+
+ Merged changes from Pigeonhole v0.3 tree.
+
+
+2013-03-28 22:12:03 +0100 Stephan Bosch <stephan@rename-it.nl> (c6ee18c9)
+
+ lib-sievestorage: Fixed a few potential problems in script save code.
+
+
+M src/lib-sievestorage/sieve-storage-save.c
+
+2013-03-28 21:33:31 +0100 Stephan Bosch <stephan@rename-it.nl> (7cde39ab)
+
+ Merged changes from Pigeonhole v0.3 tree.
+
+
+2013-03-28 21:31:59 +0100 Stephan Bosch <stephan@rename-it.nl> (856ccbb4)
+
+ lib-sievestorage: A few debug messages were still logged using i_info()
+ instead of i_debug().
+
+
+M src/lib-sievestorage/sieve-storage-script.c
+M src/lib-sievestorage/sieve-storage.c
+
+2013-03-28 21:27:53 +0100 Stephan Bosch <stephan@rename-it.nl> (e4ec7f70)
+
+ doveadm-sieve: Implemented obtaining last modification time for the active
+ script attribute. It compiles, doesn't break normal ManageSieve operation,
+ but it remains untested otherwise.
+
+
+M src/lib-sievestorage/sieve-storage-private.h
+M src/lib-sievestorage/sieve-storage-script.c
+M src/lib-sievestorage/sieve-storage-script.h
+M src/lib-sievestorage/sieve-storage.c
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-03-25 12:34:13 +0100 Stephan Bosch <stephan@rename-it.nl> (d0fd30b5)
+
+ doveadm-sieve: Crash instead of writing empty .sieve files. Patch by Timo
+ Sirainen.
+
+
+M src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-03-23 12:14:14 +0100 Stephan Bosch <stephan@rename-it.nl> (884351e8)
+
+ Fixed compile order for previous change.
+
+
+M src/Makefile.am
+
+2013-03-22 23:09:57 +0100 Stephan Bosch <stephan@rename-it.nl> (9d33676d)
+
+ Committed Timo's patch that adds a plugin that provides Sieve dsync support.
+ http://dovecot.org/patches/2.2/doveadm-sieve-plugin.diff Made some small
+ modifications. This code should not interfere with normal ManageSieve
+ operation, so I commit this right now without much testing. The actual
+ doveadm sieve plugin has a few open issues that need to be resolved still.
+
+
+M configure.ac
+M src/lib-sievestorage/Makefile.am
+M src/lib-sievestorage/sieve-storage.c
+M src/lib-sievestorage/sieve-storage.h
+M src/managesieve/Makefile.am
+M src/plugins/Makefile.am
+A src/plugins/doveadm-sieve/Makefile.am
+A src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
+
+2013-03-04 22:26:15 +0100 Stephan Bosch <stephan@rename-it.nl> (59de1b42)
+
+ lib-sieve: Fixed segfault bug in reject. Passed senv->script_context rather
+ than senv itself. Somehow the compiler fails to warn about this.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2013-03-03 18:07:30 +0100 Stephan Bosch <stephan@rename-it.nl> (6d707527)
+
+ Merged changes from Pigeonhole v0.3.
+
+
+2013-03-03 18:03:33 +0100 Stephan Bosch <stephan@rename-it.nl> (e6a1b593)
+
+ LDA Sieve plugin: further reduced useless error messages in administrator
+ log.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2013-03-03 17:35:37 +0100 Stephan Bosch <stephan@rename-it.nl> (079c5271)
+
+ LDA Sieve plugin: fixed bug in opening script files for multiscript. Used
+ sieve_script_create instead of sieve_script_create_open. Changed plugin
+ debug output a bit as well.
+
+
+M src/lib-sieve/sieve-script.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2013-03-03 16:55:05 +0100 Stephan Bosch <stephan@rename-it.nl> (4d0cf9d8)
+
+ Merged changes from Pigeonhole v0.3.
+
+
+2013-03-03 16:52:39 +0100 Stephan Bosch <stephan@rename-it.nl> (f2f90bb2)
+
+ LDA Sieve plugin: fixed stupid mistake in error handling for multiscript.
+ Used errno instead of error variable.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2013-03-02 23:27:13 +0100 Stephan Bosch <stephan@rename-it.nl> (d9a984ac)
+
+ lib-sieve: added debug message showing Pigeonhole version at initialization.
+ Very useful to show that debugging is enabled and what version of pigeonhole
+ is actually running.
+
+
+M src/lib-sieve/sieve.c
+
+2013-03-02 22:36:55 +0100 Stephan Bosch <stephan@rename-it.nl> (d56dd089)
+
+ LDA Sieve plugin: adjusted script compile/load error reporting. Made normal
+ compile error an info log item in the administrator log.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2013-02-28 23:37:31 +0100 Stephan Bosch <stephan@rename-it.nl> (783fdcae)
+
+ Sieve: editheader: fixed bug in header cloning for snapshot. Forgot to
+ increment count for the clone.
+
+
+M src/lib-sieve/edit-mail.c
+M tests/extensions/editheader/alternating.svtest
+
+2013-02-28 23:06:47 +0100 Stephan Bosch <stephan@rename-it.nl> (58f32d2c)
+
+ Sieve: editheader: fixed bug in full header parsing when addheader :last is
+ used.
+
+
+M src/lib-sieve/edit-mail.c
+
+2013-02-06 21:24:30 +0100 Stephan Bosch <stephan@rename-it.nl> (dec32238)
+
+ managesieve: Fixed bug in skipping of CRLF at end of AUTHENTICATE command.
+ Setting skip_newline is useless when the connection is transfered to another
+ process after successful login.
+
+
+M src/managesieve-login/client-authenticate.c
+
+2013-01-26 09:10:26 +0100 Stephan Bosch <stephan@rename-it.nl> (f26a0dc3)
+
+ lib-sieve: Increased a few initial memory pool sizes.
+
+
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-validator.c
+
+2013-01-26 08:52:27 +0100 Stephan Bosch <stephan@rename-it.nl> (81245ddf)
+
+ Changed behavior of redirect in case of a duplicate message delivery or a
+ mail loop. If a duplicate is detected the implicit keep is canceled, as
+ though the redirect was successful. This prevents getting local deliveries.
+ The original SMTP recipient is used when it is available to augment the
+ entry in the LDA duplicate database. This way, duplicates are only detected
+ when (initially) addressed to the same recipient. The main goal of the
+ duplicate detection is mail loop prevention, but this also has the effect
+ that mere duplicate deliveries are handled specially whithout a good reason.
+ We should fix this in a future version.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2013-01-14 12:57:58 +0100 Stephan Bosch <stephan@rename-it.nl> (7f559d44)
+
+ Merged changes from Pigeonhole v0.3 tree.
+
+
+2013-01-09 00:55:49 +0100 Stephan Bosch <stephan@rename-it.nl> (40a0bb91)
+
+ Fixed SMTP crash. By Timo Sirainen.
+
+
+M src/lib-sieve/sieve-smtp.c
+
+2013-01-09 00:38:07 +0100 Stephan Bosch <stephan@rename-it.nl> (35e2fff1)
+
+ Adjusted to changes in Dovecot.
+
+
+M src/lib-sieve/edit-mail.c
+
+2012-12-26 11:52:03 +0100 Stephan Bosch <stephan@rename-it.nl> (312ce006)
+
+ Fixed compile on Mageia Linux. Added LIBDOVECOT_STORAGE to library
+ dependencies in src/lib-sieve/Makefile.am.
+
+
+M src/lib-sieve/Makefile.am
+
+2012-12-22 22:27:34 +0100 Stephan Bosch <stephan@rename-it.nl> (7da1a76d)
+
+ lib-sieve: Prevent passing NULL sender to raw mail storage when active
+ message is substituted.
+
+
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-message.c
+
+2012-11-26 21:16:54 +0100 Stephan Bosch <stephan@rename-it.nl> (ca6601ba)
+
+ lib-sieve: vacation extension: Fixed determination of From: address for when
+ sieve_vacation_dont_check_recipient is active.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2012-10-29 22:42:34 +0100 Stephan Bosch <stephan@rename-it.nl> (19c2f6a6)
+
+ Renamed configure.in to configure.ac. Apparently automakes in future won't
+ support configure.in anymore.
+
+
+R100 configure.in configure.ac
+
+2012-10-17 22:22:02 +0200 Stephan Bosch <stephan@rename-it.nl> (9791083b)
+
+ lib-sieve: Fixed a stupidity in the dict script implementation.
+
+
+M src/lib-sieve/sieve-script-dict.c
+
+2012-10-17 22:11:16 +0200 Stephan Bosch <stephan@rename-it.nl> (aa0b16ea)
+
+ Updated installation documentation for vnd.dovecot.duplicate extension.
+
+
+M doc/extensions/vnd.dovecot.duplicate.txt
+
+2012-10-17 22:10:50 +0200 Stephan Bosch <stephan@rename-it.nl> (4e9e42df)
+
+ lib-sieve: vnd.dovecot.duplicate: Fixed default max period setting.
+
+
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.c
+
+2012-10-17 21:49:55 +0200 Stephan Bosch <stephan@rename-it.nl> (7f18f33d)
+
+ Improved specification of the vnd.dovecot.duplicate extension.
+
+
+M doc/rfc/spec-bosch-sieve-duplicate.txt
+A doc/rfc/xml/reference.INCLUDE.xml
+M doc/rfc/xml/spec-bosch-sieve-duplicate.xml
+
+2012-10-17 02:55:07 +0200 Stephan Bosch <stephan@rename-it.nl> (266bc73e)
+
+ lib-sieve: vnd.dovecot.duplicate extension: Only track duplicate when Sieve
+ script executes successfully.
+
+
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.c
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.h
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/tst-duplicate.c
+
+2012-10-17 02:15:04 +0200 Stephan Bosch <stephan@rename-it.nl> (7dc1be65)
+
+ lib-sieve: vnd.dovecot.duplicate extension: Fixed segfault occurring in
+ testsuite.
+
+
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/tst-duplicate.c
+
+2012-10-17 02:09:55 +0200 Stephan Bosch <stephan@rename-it.nl> (aa3bcb0f)
+
+ lib-sieve: vnd.dovecot.duplicate extension: fixed bug in previous change.
+ Forgot to initialize variable, causing a segfault at runtime.
+
+
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/tst-duplicate.c
+
+2012-10-16 21:33:15 +0200 Stephan Bosch <stephan@rename-it.nl> (a425a57d)
+
+ lib-sieve: vnd.dovecot.duplicate extension: Added new features to the
+ duplicate test. It is now possible to track duplicates based on arbitrary
+ headers or even arbitrary string values using the new :header and :value
+ arguments respectively. The experation time can be configured using the new
+ :seconds argument. This change is backwards compatible as long as the name
+ argument wasn't used. This is now a :handle <handle> argument.
+
+
+M doc/rfc/spec-bosch-sieve-duplicate.txt
+A doc/rfc/xml/reference.IMAP4FLAGS.xml
+A doc/rfc/xml/reference.MAILBOX.xml
+A doc/rfc/xml/reference.VACATION.xml
+M doc/rfc/xml/spec-bosch-sieve-duplicate.xml
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.c
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.h
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate.c
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/tst-duplicate.c
+M tests/extensions/vnd.dovecot/duplicate/errors.svtest
+M tests/extensions/vnd.dovecot/duplicate/errors/syntax.sieve
+M tests/extensions/vnd.dovecot/duplicate/execute.svtest
+
+2012-10-13 10:36:11 +0200 Stephan Bosch <stephan@rename-it.nl> (5f6ea36e)
+
+ Adjusted to Dovecot dict API changes.
+
+
+M src/lib-sieve/sieve-script-dict.c
+
+2012-10-13 10:35:19 +0200 Stephan Bosch <stephan@rename-it.nl> (f617c4e6)
+
+ Merged changes from Pigeonhole v0.3.
+
+
+2012-10-13 10:30:57 +0200 Stephan Bosch <stephan@rename-it.nl> (9224df2b)
+
+ lib-sieve: dict script: fixed potential segfault occuring when dict
+ initialization fails.
+
+
+M src/lib-sieve/sieve-script-dict.c
+
+2012-10-12 19:25:10 +0200 Stephan Bosch <stephan@rename-it.nl> (98d9957d)
+
+ Incorporated Dovecot plugin ABI changes (forgot a few issues).
+
+
+M src/lib-sieve/sieve-plugins.c
+M src/managesieve-login/managesieve-login-settings-plugin.c
+M src/managesieve/managesieve-settings.c
+
+2012-10-12 00:54:03 +0200 Stephan Bosch <stephan@rename-it.nl> (4ba1f32c)
+
+ Incorporated Dovecot plugin ABI changes.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2012-10-11 22:07:50 +0200 Stephan Bosch <stephan@rename-it.nl> (7adde42a)
+
+ ManageSieve: fixed handling of unkown commands pre-login. Forgot to skip
+ line upon error.
+
+
+M src/managesieve-login/client.c
+
+2012-10-11 20:26:03 +0200 Stephan Bosch <stephan@rename-it.nl> (7e18cd0b)
+
+ lib-sieve: Further improved handling of quota errors. Added means to log
+ user errors/warnings as info in master log. Previous change was inadequate
+ because an error was still logged.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2012-10-11 01:48:29 +0200 Stephan Bosch <stephan@rename-it.nl> (8fc29444)
+
+ lib-sieve: fileinto/keep: don't log quota errors to syslog but rather to
+ user's log. Prevents administrator frustration about useless log messages
+ caused by users with too much mail.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2012-10-03 18:00:50 +0200 Stephan Bosch <stephan@rename-it.nl> (58abc04e)
+
+ Adjusted to changes in Dovecot network API.
+
+
+M src/managesieve-login/client.h
+M src/managesieve/managesieve-client.c
+
+2012-09-26 21:52:32 +0200 Stephan Bosch <stephan@rename-it.nl> (4fba9b25)
+
+ testsuite: date extension: Added test for date comparisons.
+
+
+M tests/extensions/date/basic.svtest
+
+2012-09-26 21:51:46 +0200 Stephan Bosch <stephan@rename-it.nl> (dd6875f5)
+
+ lib-sieve: date extension: Generate warning when invalid date part is
+ specified.
+
+
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/date/tst-date.c
+
+2012-09-23 17:14:58 +0200 Stephan Bosch <stephan@rename-it.nl> (5e955ec3)
+
+ Merged changes from Pigeonhole v0.3.
+
+
+2012-09-23 17:09:26 +0200 Stephan Bosch <stephan@rename-it.nl> (7e1f287a)
+
+ lib-sieve: mailbox extension: After creating mailbox only open it, don't
+ bother syncing it.
+
+
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+
+2012-09-20 01:22:29 +0200 Stephan Bosch <stephan@rename-it.nl> (ed882314)
+
+ lib-sieve: include extension: didn't get semantics of mixing optional and
+ non-optional includes for the same script quite right.
+
+
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2012-09-20 00:57:02 +0200 Stephan Bosch <stephan@rename-it.nl> (bb91536d)
+
+ sieve-tools: The -D option wasn't enabled and documented for all tools.
+ Change backported from Pigeonhole v0.4 tree, which means that this change
+ will duplicate there upon merge.
+
+
+M doc/man/sieve-dump.1.in
+M doc/man/sievec.1.in
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sievec.c
+
+2012-09-20 00:54:17 +0200 Stephan Bosch <stephan@rename-it.nl> (349732f6)
+
+ lib-sieve: include extension: fixed missing error cleanup that caused a
+ resource leak.
+
+
+M src/lib-sieve/plugins/include/ext-include-binary.c
+
+2012-09-20 00:51:09 +0200 Stephan Bosch <stephan@rename-it.nl> (66dabb2f)
+
+ Fixed a few resource leaks caused by previous change.
+
+
+M src/lib-sieve/plugins/include/ext-include-binary.c
+
+2012-09-20 00:22:36 +0200 Stephan Bosch <stephan@rename-it.nl> (e09ca009)
+
+ lib-sieve: Finished implementation of include extension. Added support for
+ the :optional tag of the include command. Changed Sieve script API in the
+ process; opening the script is now available as a separate step.
+
+
+M Makefile.am
+M README
+M TODO
+D doc/rfc/draft-ietf-sieve-include-05.txt
+A doc/rfc/include.rfc6609.txt
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-script-dict.c
+M src/lib-sieve/sieve-script-file.c
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve.c
+M src/lib-sievestorage/sieve-storage-script.c
+M src/managesieve/cmd-getscript.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+A tests/extensions/include/execute/optional.sieve
+A tests/extensions/include/included/optional-1.sieve
+A tests/extensions/include/included/optional-2.sieve
+A tests/extensions/include/optional.svtest
+
+2012-09-20 00:18:10 +0200 Stephan Bosch <stephan@rename-it.nl> (9e05b84b)
+
+ sieve-tools: The -D option wasn't enabled and documented for all tools.
+
+
+M doc/man/sieve-dump.1.in
+M doc/man/sievec.1.in
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sievec.c
+
+2012-09-19 22:44:10 +0200 Stephan Bosch <stephan@rename-it.nl> (c8e81d26)
+
+ Last commit was quite inadequate.
+
+
+M src/managesieve-login/managesieve-login-settings-plugin.c
+
+2012-09-19 21:59:08 +0200 Stephan Bosch <stephan@rename-it.nl> (db52d175)
+
+ Updated to changes in Dovecot config API.
+
+
+M src/managesieve-login/managesieve-login-settings-plugin.c
+
+2012-09-18 21:30:45 +0200 Stephan Bosch <stephan@rename-it.nl> (a69b29f2)
+
+ Added signature for changeset 64474c359678
+
+
+M .hgsigs
+
+2012-09-18 21:29:16 +0200 Stephan Bosch <stephan@rename-it.nl> (37e477e4)
+
+ Added tag 0.3.3 for changeset 64474c359678
+
+
+2012-09-18 21:29:11 +0200 Stephan Bosch <stephan@rename-it.nl> (4ad40fc1)
+
+ Released v0.3.3 for Dovecot v2.1.10.
+
+
+M NEWS
+M configure.in
+
+2012-09-18 20:42:25 +0200 Stephan Bosch <stephan@rename-it.nl> (56c73516)
+
+ Fixed compile against installed Dovecot headers. This was broken by the
+ ld.gold fix.
+
+
+M src/lib-sieve/Makefile.am
+
+2012-09-18 16:20:22 +0200 Stephan Bosch <stephan@rename-it.nl> (89d4adbc)
+
+ Added signature for changeset 265061e0d3f4
+
+
+M .hgsigs
+
+2012-09-18 16:13:09 +0200 Stephan Bosch <stephan@rename-it.nl> (2dc8ed62)
+
+ Added tag 0.3.2 for changeset 265061e0d3f4
+
+
+2012-09-18 16:12:44 +0200 Stephan Bosch <stephan@rename-it.nl> (0102b7f1)
+
+ Released v0.3.2 for Dovecot v2.1.9.
+
+
+M configure.in
+
+2012-09-18 16:01:48 +0200 Stephan Bosch <stephan@rename-it.nl> (f212df40)
+
+ Updated NEWS file for next release.
+
+
+M NEWS
+
+2012-09-18 14:44:44 +0200 Stephan Bosch <stephan@rename-it.nl> (a7a64d56)
+
+ Minor change to TODO.
+
+
+M TODO
+
+2012-09-18 14:37:55 +0200 Stephan Bosch <stephan@rename-it.nl> (20aaacaf)
+
+ lib-sieve: Added version numbers to Sieve extensions. Those version numbers
+ are now also stored in the binary, making sure it is recompiled when a new
+ version of an extension is used. This avoids updating the binary version for
+ minor changes to extensions and also makes this work for plugins.
+
+
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-extensions.h
+
+2012-09-18 14:02:12 +0200 Stephan Bosch <stephan@rename-it.nl> (17129d97)
+
+ lib-sieve: Changed the way Sieve extensions are defined to a more compact
+ format.
+
+
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/date/ext-date.c
+M src/lib-sieve/plugins/editheader/ext-editheader.c
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/environment/ext-environment.c
+M src/lib-sieve/plugins/ihave/ext-ihave.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/ext-vacation-seconds.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-match-types.c
+M src/testsuite/ext-testsuite.c
+
+2012-09-18 12:10:53 +0200 Stephan Bosch <stephan@rename-it.nl> (ca8505ea)
+
+ lib-sieve: date extension: composition of iso8601 dates is moved to Dovecot.
+
+
+M src/lib-sieve/plugins/date/ext-date-common.c
+
+2012-09-18 11:59:47 +0200 Stephan Bosch <stephan@rename-it.nl> (dbca1b6a)
+
+ Updated to recent changes in Dovecot.
+
+
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/sieve-script-dict.c
+
+2012-09-09 10:45:46 +0200 Stephan Bosch <stephan@rename-it.nl> (40792452)
+
+ sieve-refilter: improved man page documentation by explicitly specifying the
+ syntax used for mailbox arguments.
+
+
+M doc/man/sieve-filter.1.in
+
+2012-09-06 09:00:59 +0200 Stephan Bosch <stephan@rename-it.nl> (6daa706c)
+
+ Adjusted to buffer API change in Dovecot.
+
+
+M src/managesieve/main.c
+
+2012-09-02 18:54:01 +0200 Stephan Bosch <stephan@rename-it.nl> (032ddf89)
+
+ Small compile fix.
+
+
+M src/lib-sieve/Makefile.am
+
+2012-08-29 19:35:17 +0200 Stephan Bosch <stephan@rename-it.nl> (ff9841b6)
+
+ lib-sieve: fixed edit-mail istream to work with latest Dovecot. Testsuite
+ failed with an assertion, because the stream returned -2 at an unexpected
+ time. I've restructured the buffering implementation to prevent this. The
+ testsuite succeeds now, but this needs to be tested more thoroughly.
+
+
+M src/lib-sieve/edit-mail.c
+
+2012-08-28 23:07:36 +0200 Stephan Bosch <stephan@rename-it.nl> (6fc44fad)
+
+ Adjusted to changes in Dovecot istream API.
+
+
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-sieve/edit-mail.c
+M src/lib-sieve/sieve-lexer.c
+
+2012-08-20 09:13:32 +0200 Stephan Bosch <stephan@rename-it.nl> (52a41995)
+
+ Adjusted to some more changes in Dovecot API.
+
+
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/sieve-extensions.c
+M src/testsuite/testsuite-settings.c
+
+2012-08-20 08:43:55 +0200 Stephan Bosch <stephan@rename-it.nl> (c245aa45)
+
+ Adjusted to changes in Dovecot API regarding arrays and hash tables. Also
+ contains a few other small fixes by Timo.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/edit-mail.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.c
+M src/lib-sieve/plugins/ihave/ext-ihave-common.h
+M src/lib-sieve/plugins/ihave/tst-ihave.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-stringlist.c
+M src/lib-sieve/sieve-validator.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/managesieve-capabilities.c
+M src/managesieve/managesieve-commands.c
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-settings.c
+M src/testsuite/testsuite-smtp.c
+
+2012-08-16 22:28:06 +0200 Stephan Bosch <stephan@rename-it.nl> (7534c8c0)
+
+ lib-sieve: spamvirustest: improved trace debugging of score calculation.
+
+
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+
+2012-08-15 00:55:05 +0200 Stephan Bosch <stephan@rename-it.nl> (e3d60566)
+
+ sieve-tools: sievec and sieve-dump now ignore mail_uid and mail_gid settings
+ when run as root. Before, sievec and sieve-dump would switch to
+ mail_uid:mail_gid and then fail to compile/dump a root script.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/testsuite.c
+
+2012-08-12 16:16:21 +0200 Stephan Bosch <stephan@rename-it.nl> (4dcfc2d4)
+
+ lib-sieve: Adjusted edit-mail.c to changes in Dovecot mail storage API.
+
+
+M src/lib-sieve/edit-mail.c
+
+2012-08-12 16:02:36 +0200 Stephan Bosch <stephan@rename-it.nl> (87759d7e)
+
+ Merged changes from Pigeonhole v0.3.
+
+
+2012-08-12 15:50:27 +0200 Stephan Bosch <stephan@rename-it.nl> (10986994)
+
+ Removed trailing whitespace everywhere.
+
+
+M AUTHORS
+M COPYING
+M INSTALL
+M Makefile.am
+M NEWS
+M README
+M TODO
+M configure.in
+M doc/devel/DESIGN
+M doc/example-config/conf.d/20-managesieve.conf
+M doc/example-config/conf.d/90-sieve.conf
+M doc/extensions/editheader.txt
+M doc/extensions/include.txt
+M doc/extensions/spamtest-virustest.txt
+M doc/extensions/vacation.txt
+M doc/man/pigeonhole.7.in
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-filter.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+M doc/script-location-dict.txt
+M src/lib-managesieve/Makefile.am
+M src/lib-managesieve/managesieve-arg.c
+M src/lib-managesieve/managesieve-arg.h
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-managesieve/managesieve-parser.h
+M src/lib-managesieve/managesieve-quote.c
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/cmp-i-ascii-casemap.c
+M src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/edit-mail.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/Makefile.am
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/Makefile.am
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/date/ext-date.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/plugins/editheader/ext-editheader-limits.h
+M src/lib-sieve/plugins/editheader/ext-editheader.c
+M src/lib-sieve/plugins/enotify/Makefile.am
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify-limits.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/ext-environment-common.h
+M src/lib-sieve/plugins/environment/ext-environment.c
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.h
+M src/lib-sieve/plugins/ihave/ext-ihave-common.c
+M src/lib-sieve/plugins/ihave/ext-ihave.c
+M src/lib-sieve/plugins/ihave/tst-ihave.c
+M src/lib-sieve/plugins/imap4flags/Makefile.am
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/notify/ext-notify-limits.h
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/Makefile.am
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation-seconds.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/Makefile.am
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.c
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.h
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate.c
+M src/lib-sieve/plugins/vnd.dovecot/duplicate/tst-duplicate.c
+M src/lib-sieve/rfc2822.c
+M src/lib-sieve/rfc2822.h
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary-code.c
+M src/lib-sieve/sieve-binary-debug.c
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-plugins.c
+M src/lib-sieve/sieve-plugins.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-script-dict.c
+M src/lib-sieve/sieve-script-file.c
+M src/lib-sieve/sieve-script-file.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-stringlist.c
+M src/lib-sieve/sieve-stringlist.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/lib-sieve/tst-truefalse.c
+M src/lib-sievestorage/Makefile.am
+M src/lib-sievestorage/sieve-storage-list.c
+M src/lib-sievestorage/sieve-storage-list.h
+M src/lib-sievestorage/sieve-storage-private.h
+M src/lib-sievestorage/sieve-storage-quota.c
+M src/lib-sievestorage/sieve-storage-quota.h
+M src/lib-sievestorage/sieve-storage-save.c
+M src/lib-sievestorage/sieve-storage-script.c
+M src/lib-sievestorage/sieve-storage.c
+M src/lib-sievestorage/sieve-storage.h
+M src/managesieve-login/client-authenticate.c
+M src/managesieve-login/client.c
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-login-settings-plugin.c
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve-login/managesieve-proxy.c
+M src/managesieve/Makefile.am
+M src/managesieve/cmd-capability.c
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-listscripts.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/cmd-setactive.c
+M src/managesieve/managesieve-capabilities.c
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+M src/managesieve/managesieve-commands.c
+M src/managesieve/managesieve-quota.c
+M src/managesieve/managesieve-settings.c
+M src/plugins/lda-sieve/Makefile.am
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/Makefile.am
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-arguments.c
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-binary.h
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-script.h
+M src/testsuite/testsuite-settings.c
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/testsuite-substitutions.h
+M src/testsuite/testsuite-variables.c
+M src/testsuite/testsuite-variables.h
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-action.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+M tests/compile/errors.svtest
+M tests/compile/errors/address.sieve
+M tests/compile/errors/envelope.sieve
+M tests/compile/errors/if.sieve
+M tests/compile/errors/keep.sieve
+M tests/compile/errors/lexer.sieve
+M tests/compile/errors/out-address.sieve
+M tests/compile/errors/parser.sieve
+M tests/compile/errors/require.sieve
+M tests/compile/errors/size.sieve
+M tests/compile/errors/tag.sieve
+M tests/compile/errors/typos.sieve
+M tests/compile/errors/unsupported.sieve
+M tests/compile/recover.svtest
+M tests/control-if.svtest
+M tests/deprecated/notify/basic.svtest
+M tests/deprecated/notify/mailto.svtest
+M tests/execute/actions.svtest
+M tests/execute/actions/redirect.sieve
+M tests/execute/errors.svtest
+M tests/execute/examples.svtest
+M tests/execute/mailstore.svtest
+M tests/extensions/body/basic.svtest
+M tests/extensions/body/content.svtest
+M tests/extensions/body/raw.svtest
+M tests/extensions/date/basic.svtest
+M tests/extensions/date/zones.svtest
+M tests/extensions/editheader/addheader.svtest
+M tests/extensions/editheader/alternating.svtest
+M tests/extensions/editheader/deleteheader.svtest
+M tests/extensions/editheader/errors.svtest
+M tests/extensions/editheader/errors/command-syntax.sieve
+M tests/extensions/editheader/protected.svtest
+M tests/extensions/encoded-character.svtest
+M tests/extensions/enotify/basic.svtest
+M tests/extensions/enotify/errors/uri-mailto.sieve
+M tests/extensions/enotify/mailto.svtest
+M tests/extensions/enotify/valid_notify_method.svtest
+M tests/extensions/envelope.svtest
+M tests/extensions/environment/rfc.svtest
+M tests/extensions/imap4flags/basic.svtest
+M tests/extensions/imap4flags/execute.svtest
+M tests/extensions/imap4flags/execute/flags-side-effect.sieve
+M tests/extensions/imap4flags/hasflag.svtest
+M tests/extensions/imap4flags/multiscript.svtest
+M tests/extensions/include/execute.svtest
+M tests/extensions/regex/basic.svtest
+M tests/extensions/regex/match-values.svtest
+M tests/extensions/relational/basic.svtest
+M tests/extensions/relational/comparators.svtest
+M tests/extensions/relational/errors/validation.sieve
+M tests/extensions/relational/rfc.svtest
+M tests/extensions/spamvirustest/spamtest.svtest
+M tests/extensions/subaddress/basic.svtest
+M tests/extensions/subaddress/rfc.svtest
+M tests/extensions/vacation/execute.svtest
+M tests/extensions/vacation/execute/no-handle.sieve
+M tests/extensions/vacation/message.svtest
+M tests/extensions/vacation/reply.svtest
+M tests/extensions/vacation/utf-8.svtest
+M tests/extensions/variables/basic.svtest
+M tests/extensions/variables/errors/limits.sieve
+M tests/extensions/variables/match.svtest
+M tests/extensions/variables/modifiers.svtest
+M tests/extensions/variables/quoting.svtest
+M tests/extensions/variables/regex.svtest
+M tests/extensions/variables/string.svtest
+M tests/match-types/contains.svtest
+M tests/match-types/is.svtest
+M tests/match-types/matches.svtest
+M tests/multiscript/basic.svtest
+M tests/multiscript/conflicts.svtest
+M tests/test-address.svtest
+M tests/test-allof.svtest
+M tests/test-anyof.svtest
+M tests/test-exists.svtest
+M tests/test-header.svtest
+M tests/testsuite.svtest
+
+2012-08-09 23:01:43 +0200 Stephan Bosch <stephan@rename-it.nl> (9dc2b1c1)
+
+ Merged changes from Pigeonhole v0.3 tree.
+
+
+2012-08-09 22:58:53 +0200 Stephan Bosch <stephan@rename-it.nl> (0cfb762d)
+
+ Created specification for the vnd.dovecot.debug extension. Also fixed a
+ small mistake in the spefication for the vnd.dovecot.duplicate extension.
+
+
+A doc/rfc/spec-bosch-sieve-debug.txt
+A doc/rfc/xml/reference.VARIABLES.xml
+A doc/rfc/xml/spec-bosch-sieve-debug.xml
+M doc/rfc/xml/spec-bosch-sieve-duplicate.xml
+
+2012-08-07 00:36:11 +0200 Stephan Bosch <stephan@rename-it.nl> (68353bbc)
+
+ lib-sieve: increase action instance count (for limit checking) only when an
+ action is actually created.
+
+
+M src/lib-sieve/sieve-result.c
+
+2012-08-07 00:34:12 +0200 Stephan Bosch <stephan@rename-it.nl> (2ce4a474)
+
+ lib-sieve: fixed potential action duplication bug.
+
+
+M src/lib-sieve/sieve-result.c
+
+2012-08-06 23:14:19 +0200 Stephan Bosch <stephan@rename-it.nl> (ba927a91)
+
+ lib-sieve: made action limit error messages more verbose.
+
+
+M src/lib-sieve/sieve-result.c
+
+2012-08-05 18:42:12 +0200 Stephan Bosch <stephan@rename-it.nl> (93c6c79b)
+
+ Testsuite: fixed compiler warning.
+
+
+M src/testsuite/testsuite-variables.c
+
+2012-08-05 00:30:14 +0200 Stephan Bosch <stephan@rename-it.nl> (b06f10dd)
+
+ Testsuite: added support for executing sub-scripts and added tst variables
+ namespace. Added test for interaction between include extension and dict
+ script location support.
+
+
+M src/testsuite/Makefile.am
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-script.h
+A src/testsuite/testsuite-variables.c
+A src/testsuite/testsuite-variables.h
+M src/testsuite/testsuite.c
+M tests/extensions/include/execute.svtest
+A tests/extensions/include/execute/namespace.sieve
+A tests/extensions/include/included-global/namespace.dict
+A tests/extensions/include/included/namespace.dict
+
+2012-08-04 09:34:21 +0200 Stephan Bosch <stephan@rename-it.nl> (aedfe1ee)
+
+ Testsuite: fixed displaying debug messages.
+
+
+M src/testsuite/testsuite-log.c
+
+2012-08-03 19:52:36 +0200 Stephan Bosch <stephan@rename-it.nl> (14877e2b)
+
+ Include: fixed namespace separation of :global and :personal scripts. Sieve
+ script equality function implementation was wrong.
+
+
+M src/lib-sieve/sieve-script-dict.c
+M src/lib-sieve/sieve-script-file.c
+M src/lib-sieve/sieve-script.c
+M tests/extensions/include/execute.svtest
+A tests/extensions/include/included-global/namespace.sieve
+A tests/extensions/include/included/namespace.sieve
+
+2012-07-31 01:24:28 +0200 Stephan Bosch <stephan@rename-it.nl> (c882d9ee)
+
+ Merged changes from Pigeonhole v0.2 tree.
+
+
+2012-07-31 01:18:15 +0200 Stephan Bosch <stephan@rename-it.nl> (6beefee9)
+
+ Fix linkage with ld.gold. Patch by Eray Aslan.
+
+
+M src/lib-sieve/Makefile.am
+
+2012-07-30 10:14:42 +0200 Stephan Bosch <stephan@rename-it.nl> (a2d3329a)
+
+ Fixed several Clang compile warnings and a few potential bugs. Patch by Timo
+ Sirainen.
+
+
+M src/lib-sieve/rfc2822.h
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sievestorage/sieve-storage.c
+M src/testsuite/testsuite-log.c
+
+2012-07-25 09:08:11 +0200 Stephan Bosch <stephan@rename-it.nl> (7d1fd8e3)
+
+ Editheader: name of added header is now first sanitized to have capital
+ letters where conventional.
+
+
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+
+2012-07-16 21:36:23 +0200 Stephan Bosch <stephan@rename-it.nl> (24e432c4)
+
+ Example config: disabled default sections for managesieve and
+ managesieve-login services. This currently breaks uninstall when the
+ settings plugins are removed and 20-managesieve.conf remains in conf.d
+ directory. These sections only need to be active in the config file when
+ settings for the services themselves need to be disabled.
+
+
+M doc/example-config/conf.d/20-managesieve.conf
+
+2012-07-13 10:06:46 +0200 Stephan Bosch <stephan@rename-it.nl> (8ba3be21)
+
+ ManageSieve: fixed segfault caused by Dovecot API change.
+
+
+M src/lib-managesieve/managesieve-parser.c
+
+2012-07-13 00:57:00 +0200 Stephan Bosch <stephan@rename-it.nl> (f27c14e2)
+
+ Merged changes from Dovecot v2.1.
+
+
+2012-07-12 23:57:50 +0200 Stephan Bosch <stephan@rename-it.nl> (b26b4408)
+
+ ManageSieve: fixed segfault bug triggered by CHECKSCRIPT command.
+
+
+M src/lib-sievestorage/sieve-storage-save.c
+
+2012-07-12 23:40:52 +0200 Stephan Bosch <stephan@rename-it.nl> (db63d938)
+
+ Adjusted to Dovecot API changes.
+
+
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve/edit-mail.c
+
+2012-05-26 00:16:35 +0200 Stephan Bosch <stephan@rename-it.nl> (416ee290)
+
+ Added signature for changeset e9ed5d5cef4b
+
+
+M .hgsigs
+
+2012-05-26 00:14:18 +0200 Stephan Bosch <stephan@rename-it.nl> (b65bde7e)
+
+ Added tag 0.3.1 for changeset e9ed5d5cef4b
+
+
+2012-05-26 00:14:05 +0200 Stephan Bosch <stephan@rename-it.nl> (28ac609c)
+
+ Released v0.3.1 for Dovecot v2.1.6.
+
+
+M NEWS
+M configure.in
+
+2012-05-20 12:16:43 +0200 Stephan Bosch <stephan@rename-it.nl> (e60a6449)
+
+ Merged changes from Pigeonhole v0.2 tree.
+
+
+2012-05-20 12:06:25 +0200 Stephan Bosch <stephan@rename-it.nl> (7f017b49)
+
+ Merged changes from Pigeonhole v0.2 tree.
+
+
+2012-05-20 11:33:49 +0200 Stephan Bosch <stephan@rename-it.nl> (7f2b3f53)
+
+ Merged minor changes from Pigeonhole v0.2 tree (causes a few duplicate
+ commit messages).
+
+
+2012-05-11 02:54:42 +0200 Stephan Bosch <stephan@rename-it.nl> (8c8d51e5)
+
+ Incorporated sieve_duplicate plugin into main Pigeonhole tree as a normal
+ extension (vnd.dovecot.duplicate). Also restructured doc dir a bit in the
+ process.
+
+
+M INSTALL
+M Makefile.am
+M configure.in
+M doc/Makefile.am
+R100 doc/editheader.txt doc/extensions/editheader.txt
+R100 doc/include.txt doc/extensions/include.txt
+R100 doc/spamtest-virustest.txt doc/extensions/spamtest-virustest.txt
+R100 doc/vacation.txt doc/extensions/vacation.txt
+A doc/extensions/vnd.dovecot.duplicate.txt
+A doc/rfc/Makefile.am
+A doc/rfc/spec-bosch-sieve-duplicate.txt
+A doc/rfc/xml/reference.KEYWORDS.xml
+A doc/rfc/xml/reference.SIEVE.xml
+A doc/rfc/xml/spec-bosch-sieve-duplicate.xml
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/vnd.dovecot/Makefile.am
+A src/lib-sieve/plugins/vnd.dovecot/duplicate/Makefile.am
+A src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.c
+A src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.h
+A src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate.c
+A src/lib-sieve/plugins/vnd.dovecot/duplicate/tst-duplicate.c
+M src/lib-sieve/sieve-extensions.c
+A tests/extensions/vnd.dovecot/duplicate/errors.svtest
+A tests/extensions/vnd.dovecot/duplicate/errors/syntax.sieve
+A tests/extensions/vnd.dovecot/duplicate/execute.svtest
+
+2012-05-11 02:45:33 +0200 Stephan Bosch <stephan@rename-it.nl> (568d37a7)
+
+ Fixed compiler warning.
+
+
+M src/lib-sieve/sieve-validator.c
+
+2012-05-04 11:40:39 +0200 Stephan Bosch <stephan@rename-it.nl> (f34cbfcc)
+
+ LDA Sieve plugin: fixed sieve_before bug that made it only work when
+ mail_debug=yes.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2012-05-02 01:17:49 +0200 Stephan Bosch <stephan@rename-it.nl> (8dd6c6a0)
+
+ Fixed several small issues, including a few potential segfault bugs, based
+ on static analysis. Clang static analyzer is happy now.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/edit-mail.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve.c
+M src/lib-sievestorage/sieve-storage-quota.c
+M src/managesieve-login/managesieve-login-settings-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/testsuite.c
+
+2012-04-30 09:10:44 +0200 Stephan Bosch <stephan@rename-it.nl> (ae68404f)
+
+ Added support for specifying multiple sieve_before and sieve_after paths.
+ Additional paths are specified by adding a sequence number (starting at 2)
+ to the setting name. Added support for specifying home-relative paths for
+ sieve_before and sieve_after. This enables administrators to specify
+ user-specific global Sieve scripts that cannot be viewed or changed by
+ virtual users.
+
+
+M INSTALL
+M README
+M doc/example-config/conf.d/90-sieve.conf
+M src/lib-sieve/sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2012-04-27 02:28:13 +0200 Stephan Bosch <stephan@rename-it.nl> (2881344a)
+
+ Fixed segfault bug. Forgot to change Sieve SMTP API to use scriptenv in
+ stead of script_context directly.
+
+
+M src/lib-sieve/sieve-smtp.c
+
+2012-04-24 19:33:19 +0200 Stephan Bosch <stephan@rename-it.nl> (4a9c81b9)
+
+ sievec tool: fixed segfault bug and another bug making it omit actually
+ saving the binary.
+
+
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-script-file.c
+M src/lib-sieve/sieve.c
+
+2012-04-24 13:08:36 +0200 Stephan Bosch <stephan@rename-it.nl> (00d405f0)
+
+ lib-managesieve: changed EPROTO error to EIO in ManageSieve string stream
+ because it is apparently not known in BSD.
+
+
+M src/lib-managesieve/managesieve-parser.c
+M src/managesieve-login/client-authenticate.c
+M src/managesieve/cmd-putscript.c
+
+2012-04-22 17:16:08 +0200 Stephan Bosch <stephan@rename-it.nl> (ca89209f)
+
+ lib-sieve: fixed cleanup bug in dict script implementation.
+
+
+M src/lib-sieve/sieve-script-dict.c
+M src/lib-sieve/sieve-script.c
+
+2012-04-22 15:36:06 +0200 Stephan Bosch <stephan@rename-it.nl> (767f2b5d)
+
+ Finished documentation example for SQL dict script location type.
+
+
+M doc/script-location-dict.txt
+
+2012-04-22 15:11:14 +0200 Stephan Bosch <stephan@rename-it.nl> (b714ae82)
+
+ LDA Sieve: fixed bug in debug message.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2012-04-22 11:30:28 +0200 Stephan Bosch <stephan@rename-it.nl> (70256226)
+
+ Added support for retrieving Sieve scripts from dict lookup. - Built
+ generic interface for alternative script sources. - Implemented dict
+ script location. NOTE: ManageSieve will not work with this yet, nor will
+ sieve_before/sieve_after.
+
+
+M INSTALL
+M TODO
+A doc/script-location-dict.txt
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+A src/lib-sieve/sieve-script-dict.c
+A src/lib-sieve/sieve-script-file.c
+A src/lib-sieve/sieve-script-file.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sievestorage/sieve-storage-list.c
+M src/lib-sievestorage/sieve-storage-quota.c
+M src/lib-sievestorage/sieve-storage-save.c
+M src/lib-sievestorage/sieve-storage-script.c
+M src/lib-sievestorage/sieve-storage.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/managesieve-capabilities.c
+M src/managesieve/managesieve-client.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite.c
+M tests/extensions/environment/basic.svtest
+
+2012-03-26 21:07:14 +0200 Stephan Bosch <stephan@rename-it.nl> (215eb1ee)
+
+ Updated dovecot.m4.
+
+
+M m4/dovecot.m4
+
+2012-03-19 22:33:12 +0100 Stephan Bosch <stephan@rename-it.nl> (e5a3004b)
+
+ sieve-tools: forgot to enable debug in error handlers.
+
+
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+
+2012-03-15 21:29:33 +0100 Stephan Bosch <stephan@rename-it.nl> (d2978b65)
+
+ managesieve-login: fixed x86 compile warning.
+
+
+M src/managesieve-login/client-authenticate.c
+
+2012-03-08 11:02:05 +0100 Stephan Bosch <stephan@rename-it.nl> (389e72ee)
+
+ Added a "session ID" string for managesieve connections, available in
+ %{session} variable. This change matches a similar change in Dovecot for
+ IMAP/POP3. Also includes other small changes that make ManageSieve match
+ IMAP implementation a little more closely.
+
+
+M src/managesieve/main.c
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+M src/managesieve/managesieve-common.h
+
+2012-03-07 22:04:06 +0100 Stephan Bosch <stephan@rename-it.nl> (b00f1672)
+
+ Gave stamp.h.in some content to prevent it from disappearing in patch files.
+
+
+M stamp.h.in
+
+2012-02-29 22:51:56 +0100 Stephan Bosch <stephan@rename-it.nl> (985dbe10)
+
+ Adjusted Sieve implementation and testsuite to Dovecot's new
+ smtp_client_open() API.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/edit-mail.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/rfc2822.c
+M src/lib-sieve/rfc2822.h
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-types.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+
+2012-02-29 20:07:24 +0100 Stephan Bosch <stephan@rename-it.nl> (cf5d3ac8)
+
+ Fixed bug that caused SunStudio CC compile failure (reported by Piotr
+ Tarnowski).
+
+
+M src/lib-sieve/sieve.c
+
+2012-02-29 20:07:24 +0100 Stephan Bosch <stephan@rename-it.nl> (36ffcba3)
+
+ Fixed bug that caused SunStudio CC compile failure (reported by Piotr
+ Tarnowski).
+
+
+M src/lib-sieve/sieve.c
+
+2012-02-22 21:43:35 +0100 Stephan Bosch <stephan@rename-it.nl> (6dde8d4a)
+
+ lib-sieve: made error handler part of public runtime environment.
+
+
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-runtime.h
+
+2012-02-22 21:43:35 +0100 Stephan Bosch <stephan@rename-it.nl> (cf2e9e48)
+
+ lib-sieve: made error handler part of public runtime environment.
+
+
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-runtime.h
+
+2012-02-16 22:07:32 +0100 Stephan Bosch <stephan@rename-it.nl> (4b97b4b7)
+
+ Added signature for changeset fe7bd7ee6c2e
+
+
+M .hgsigs
+
+2012-02-16 22:02:56 +0100 Stephan Bosch <stephan@rename-it.nl> (5edd59df)
+
+ Added tag 0.3.0 for changeset fe7bd7ee6c2e
+
+
+2012-02-16 22:02:35 +0100 Stephan Bosch <stephan@rename-it.nl> (eb0b1b2a)
+
+ Released v0.3.0 for Dovecot v2.1.0.
+
+
+M NEWS
+
+2012-02-13 00:01:30 +0100 Stephan Bosch <stephan@rename-it.nl> (18eed660)
+
+ Applied sieve-body-fix.patch. Fixes behavior of body test with multipart
+ MIME body parts. Testsuite needs to be extended accordingly.
+
+
+M TODO
+M src/lib-sieve/plugins/body/ext-body-common.c
+
+2012-02-12 23:53:31 +0100 Stephan Bosch <stephan@rename-it.nl> (dc004ab1)
+
+ Updated to Dovecot v2.2. Updated version number to v0.4.0 and added a
+ warning to configure. Applied generic-login.patch.
+
+
+M configure.in
+M src/managesieve-login/client-authenticate.c
+M src/managesieve-login/client-authenticate.h
+M src/managesieve-login/client.c
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-proxy.c
+M src/managesieve-login/managesieve-proxy.h
+
+2012-01-28 14:25:41 +0100 Stephan Bosch <stephan@rename-it.nl> (9f516ae0)
+
+ ManageSieve: cleaned up parser and updated it to match newer structure of
+ imap parser.
+
+
+M src/lib-managesieve/Makefile.am
+A src/lib-managesieve/managesieve-arg.c
+A src/lib-managesieve/managesieve-arg.h
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-managesieve/managesieve-parser.h
+M src/managesieve-login/client-authenticate.c
+M src/managesieve-login/client-authenticate.h
+M src/managesieve-login/client.c
+M src/managesieve-login/managesieve-proxy.c
+M src/managesieve/cmd-havespace.c
+M src/managesieve/cmd-noop.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+
+2012-01-27 18:57:42 +0100 Stephan Bosch <stephan@rename-it.nl> (74b3be42)
+
+ managesieve-login: matched proxy and auth_verbose changes in Dovecot.
+
+
+M src/managesieve-login/managesieve-proxy.c
+
+2012-01-27 17:22:17 +0100 Stephan Bosch <stephan@rename-it.nl> (c4734e6a)
+
+ testsuite: fixed compile warning.
+
+
+M src/testsuite/cmd-test-message.c
+
+2012-01-23 00:43:37 +0100 Stephan Bosch <stephan@rename-it.nl> (a1ef6659)
+
+ ManageSieve: fixed quota problem in previous change.
+
+
+M src/managesieve/cmd-putscript.c
+
+2012-01-22 21:57:45 +0100 Stephan Bosch <stephan@rename-it.nl> (7f428312)
+
+ ManageSieve: added support for reading quoted and literal strings as a
+ stream. Fixes support for handing large SASL responses. Also resolves
+ long-standing FIXME regarding the second parameter of PUTSCRIPT: it can now
+ be a quoted string. Includes a few small changes in the login daemon that
+ were done in the dovecot equivalents before.
+
+
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-managesieve/managesieve-parser.h
+M src/lib-sievestorage/sieve-storage-quota.c
+M src/lib-sievestorage/sieve-storage-quota.h
+M src/managesieve-login/client-authenticate.c
+M src/managesieve-login/client.c
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-proxy.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-quota.c
+M src/managesieve/managesieve-quota.h
+
+2012-01-20 22:26:53 +0100 Stephan Bosch <stephan@rename-it.nl> (b684406b)
+
+ managesieve: Added -t parameter to specify post-login script timeout
+ (Dovecot change).
+
+
+M src/managesieve/main.c
+
+2012-01-12 18:43:13 +0100 Stephan Bosch <stephan@rename-it.nl> (b55a8548)
+
+ managesieve-login: Include hostname and timestamp in "temporary auth
+ failure" message.
+
+
+M src/managesieve-login/client-authenticate.c
+
+2012-01-07 16:35:56 +0100 Stephan Bosch <stephan@rename-it.nl> (2e952941)
+
+ Updated copyright notices to include year 2012.
+
+
+M doc/man/pigeonhole.7.in
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-filter.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-managesieve/managesieve-parser.h
+M src/lib-managesieve/managesieve-quote.c
+M src/lib-managesieve/managesieve-quote.h
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/cmp-i-ascii-casemap.c
+M src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/edit-mail.c
+M src/lib-sieve/edit-mail.h
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/copy/sieve-ext-copy.h
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/date/ext-date.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.h
+M src/lib-sieve/plugins/editheader/ext-editheader-limits.h
+M src/lib-sieve/plugins/editheader/ext-editheader.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify-limits.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/ext-environment-common.h
+M src/lib-sieve/plugins/environment/ext-environment.c
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/ihave/cmd-error.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.h
+M src/lib-sieve/plugins/ihave/ext-ihave-common.c
+M src/lib-sieve/plugins/ihave/ext-ihave-common.h
+M src/lib-sieve/plugins/ihave/ext-ihave.c
+M src/lib-sieve/plugins/ihave/tst-ihave.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-limits.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/notify/ext-notify-limits.h
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation-seconds.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/cmd-debug-log.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug-common.h
+M src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c
+M src/lib-sieve/rfc2822.c
+M src/lib-sieve/rfc2822.h
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary-code.c
+M src/lib-sieve/sieve-binary-debug.c
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-plugins.c
+M src/lib-sieve/sieve-plugins.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-stringlist.c
+M src/lib-sieve/sieve-stringlist.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/lib-sieve/tst-truefalse.c
+M src/lib-sievestorage/sieve-storage-list.c
+M src/lib-sievestorage/sieve-storage-list.h
+M src/lib-sievestorage/sieve-storage-private.h
+M src/lib-sievestorage/sieve-storage-quota.c
+M src/lib-sievestorage/sieve-storage-quota.h
+M src/lib-sievestorage/sieve-storage-save.c
+M src/lib-sievestorage/sieve-storage-save.h
+M src/lib-sievestorage/sieve-storage-script.c
+M src/lib-sievestorage/sieve-storage-script.h
+M src/lib-sievestorage/sieve-storage.c
+M src/lib-sievestorage/sieve-storage.h
+M src/managesieve-login/client-authenticate.c
+M src/managesieve-login/client-authenticate.h
+M src/managesieve-login/client.c
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-login-settings-plugin.c
+M src/managesieve-login/managesieve-login-settings-plugin.h
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve-login/managesieve-login-settings.h
+M src/managesieve-login/managesieve-proxy.c
+M src/managesieve-login/managesieve-proxy.h
+M src/managesieve/cmd-capability.c
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-havespace.c
+M src/managesieve/cmd-listscripts.c
+M src/managesieve/cmd-logout.c
+M src/managesieve/cmd-noop.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/cmd-setactive.c
+M src/managesieve/main.c
+M src/managesieve/managesieve-capabilities.c
+M src/managesieve/managesieve-capabilities.h
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+M src/managesieve/managesieve-commands.c
+M src/managesieve/managesieve-commands.h
+M src/managesieve/managesieve-common.h
+M src/managesieve/managesieve-quota.c
+M src/managesieve/managesieve-quota.h
+M src/managesieve/managesieve-settings.c
+M src/managesieve/managesieve-settings.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.h
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-arguments.c
+M src/testsuite/testsuite-arguments.h
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-binary.h
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-log.h
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-script.h
+M src/testsuite/testsuite-settings.c
+M src/testsuite/testsuite-settings.h
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/testsuite-substitutions.h
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-action.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2012-01-07 16:01:10 +0100 Stephan Bosch <stephan@rename-it.nl> (204f7fb0)
+
+ LDA Sieve plugin: renamed sieve_global_path setting to sieve_default for
+ clarity. Old name is now deprecated. Support for the even older
+ global_script_path name for this setting is dropped.
+
+
+M INSTALL
+M README
+M doc/example-config/conf.d/90-sieve.conf
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2012-01-07 12:42:01 +0100 Stephan Bosch <stephan@rename-it.nl> (ca3aa5d2)
+
+ lib-sieve: added means to prohibit use of redirect action. Setting
+ sieve_max_redirects=0 now means that redirects are prohibited rather than
+ unlimited. Now there is always a limit, but it can be enormous if the
+ administrator wants to.
+
+
+M INSTALL
+M doc/example-config/conf.d/90-sieve.conf
+M src/lib-sieve/cmd-redirect.c
+
+2012-01-06 23:20:59 +0100 Stephan Bosch <stephan@rename-it.nl> (2683ec85)
+
+ Fixed indentation problems in documentation.
+
+
+M INSTALL
+M doc/editheader.txt
+M doc/include.txt
+M doc/spamtest-virustest.txt
+M doc/vacation.txt
+
+2012-01-06 23:03:12 +0100 Stephan Bosch <stephan@rename-it.nl> (a7ce01ed)
+
+ Updated documentation and example config.
+
+
+M doc/editheader.txt
+M doc/example-config/conf.d/20-managesieve.conf
+M doc/example-config/conf.d/90-sieve.conf
+M doc/spamtest-virustest.txt
+M doc/vacation.txt
+
+2011-12-27 22:21:34 +0100 Stephan Bosch <stephan@rename-it.nl> (ae679d44)
+
+ lib-sieve: fixed bug in message snapshots. Message substitutions would not
+ always cause a proper snapshot.
+
+
+M src/lib-sieve/sieve-message.c
+
+2011-12-27 21:29:19 +0100 Stephan Bosch <stephan@rename-it.nl> (68615e53)
+
+ lib-sieve: fixed memory leak in previous change.
+
+
+M src/lib-sieve/sieve-message.c
+
+2011-12-27 21:11:49 +0100 Stephan Bosch <stephan@rename-it.nl> (216f8883)
+
+ lib-sieve: added support for substituting the entire message. This is needed
+ for the new extprograms plugin.
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/testsuite/testsuite-message.c
+
+2011-12-27 11:56:25 +0100 Stephan Bosch <stephan@rename-it.nl> (6b3cd6de)
+
+ lib-sieve-tool: mail_raw: started using mail_temp_dir setting.
+
+
+M src/lib-sieve-tool/mail-raw.c
+
+2011-12-20 20:05:21 +0100 Stephan Bosch <stephan@rename-it.nl> (c527430b)
+
+ lib-sieve: adjusted code fetch api for handling omitted operands better.
+ Removes quite a bit of duplicated source code.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+
+2011-12-17 18:58:48 +0100 Stephan Bosch <stephan@rename-it.nl> (afeb564b)
+
+ lib-sieve: made uniform scriptname <-> filename conversion functions. This
+ puts the ".sieve" and ".svbin" file extension definitions in a single
+ locatio. IMPORTANT: this fixes a bug in the include extension that
+ implicitly mapped script names like "name.sieve" to "name".
+
+
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve.c
+M src/lib-sievestorage/sieve-storage-list.c
+M src/lib-sievestorage/sieve-storage-quota.c
+M src/lib-sievestorage/sieve-storage-save.c
+M src/lib-sievestorage/sieve-storage-script.c
+M src/lib-sievestorage/sieve-storage-script.h
+M src/lib-sievestorage/sieve-storage.c
+M src/sieve-tools/sievec.c
+M src/testsuite/testsuite-binary.c
+M tests/extensions/include/errors/circular-1.sieve
+M tests/extensions/include/errors/circular-2.sieve
+M tests/extensions/include/included/circular-one.sieve
+M tests/extensions/include/included/circular-three-2.sieve
+M tests/extensions/include/included/circular-three.sieve
+M tests/extensions/include/included/circular-two.sieve
+M tests/extensions/include/included/once-2.sieve
+M tests/extensions/include/included/twice-2.sieve
+
+2011-12-17 16:07:16 +0100 Stephan Bosch <stephan@rename-it.nl> (ab5ab2d8)
+
+ lib-managesieve-storage: added code to cleanup tmp directory every once in a
+ while. This is borrowed from Dovecot's lib-storage/index/maildir.
+
+
+M src/lib-sievestorage/sieve-storage-private.h
+M src/lib-sievestorage/sieve-storage.c
+
+2011-12-17 15:04:59 +0100 Stephan Bosch <stephan@rename-it.nl> (8e9c7953)
+
+ Fixed interaction of Sieve include extension with ManageSieve. Upon upload,
+ the include extension is more lenient towards circular includes and missing
+ scripts as required by RFC. The script is now also verified upon SETACTIVE
+ when it was not active before. However, this new SETACTIVE behavior is not
+ optimal for the situation where the active script was updated with PUTSCRIPT
+ and contains an nonexistent include (ignored during upload). This can still
+ cause runtime errors, since an already active script is not verified again
+ during SETACTIVE.
+
+
+M TODO
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/lib-sievestorage/sieve-storage-save.c
+M src/lib-sievestorage/sieve-storage-save.h
+M src/lib-sievestorage/sieve-storage-script.c
+M src/lib-sievestorage/sieve-storage-script.h
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-setactive.c
+
+2011-12-17 14:47:23 +0100 Stephan Bosch <stephan@rename-it.nl> (6469f6e6)
+
+ lib-sieve: fixed copy-paste error in sieve_get_warnings() It returned the
+ number of errors in stead of the number of warnings.
+
+
+M src/lib-sieve/sieve-error.c
+
+2011-12-17 00:08:01 +0100 Stephan Bosch <stephan@rename-it.nl> (3c4d93f2)
+
+ Updated man pages.
+
+
+M doc/man/pigeonhole.7.in
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-filter.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+
+2011-12-16 23:40:34 +0100 Stephan Bosch <stephan@rename-it.nl> (826318f8)
+
+ lib-sieve: made sure that modified messages are not stored in the source
+ mailbox when it was opened read-only. This is currently only relevant for
+ the sieve-filter tool to avoid duplicating messages in the source folder.
+ This can happen when the messages are modified (e.g. by the editheader
+ extension) and the source folder is opened read-only, thus preventing
+ deletion of the original message.
+
+
+M src/lib-sieve/edit-mail.c
+M src/lib-sieve/sieve-actions.c
+
+2011-12-12 21:27:59 +0100 Stephan Bosch <stephan@rename-it.nl> (be8cf864)
+
+ lib-sieve: store action: copy flags and keywords from input mail, also when
+ imap4flags extension is not active. This is currently only relevant for
+ sieve-filter, which now properly preserves flags with this change.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2011-12-12 09:01:53 +0100 Stephan Bosch <stephan@rename-it.nl> (ce44f0e0)
+
+ Updated man pages with recent extension configuration changes.
+
+
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-filter.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+
+2011-12-12 00:49:22 +0100 Stephan Bosch <stephan@rename-it.nl> (92dff71e)
+
+ Updated TODO.
+
+
+M TODO
+
+2011-12-12 00:46:59 +0100 Stephan Bosch <stephan@rename-it.nl> (9ffcf2d8)
+
+ lib-sieve: added support for restricting certain extensions to
+ (admin-controled) global scripts - Added sieve_global_extensions setting.
+
+
+M INSTALL
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/plugins/ihave/ext-ihave-binary.c
+M src/lib-sieve/plugins/ihave/tst-ihave.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-plugins.c
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/managesieve/cmd-putscript.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite.c
+
+2011-12-12 00:25:47 +0100 Stephan Bosch <stephan@rename-it.nl> (c93b0aee)
+
+ lib-sieve: made sure error locations never report `line 0'.
+
+
+M src/lib-sieve/sieve-error.c
+
+2011-12-12 00:23:04 +0100 Stephan Bosch <stephan@rename-it.nl> (a4372719)
+
+ lib-sieve: fixed potention segfault occuring when interpreter initialization
+ fails.
+
+
+M src/lib-sieve/sieve.c
+
+2011-12-07 22:59:14 +0100 Stephan Bosch <stephan@rename-it.nl> (d28ae8d8)
+
+ Completed sieve-filter tool to a useful state. - Now compiles regularly
+ without --with-unfinished-features - Still experimental though, so be
+ careful. - Changed command structure a bit, removing the useless -M option.
+
+
+M TODO
+M doc/man/Makefile.am
+M doc/man/sieve-filter.1.in
+M src/sieve-tools/Makefile.am
+M src/sieve-tools/sieve-filter.c
+
+2011-12-05 22:28:54 +0100 Stephan Bosch <stephan@rename-it.nl> (3a40223e)
+
+ lib-sieve: fixed -Wunused-but-set-variable compiler warning in edit-mail.c.
+
+
+M src/lib-sieve/edit-mail.c
+
+2011-11-29 22:47:13 +0100 Stephan Bosch <stephan@rename-it.nl> (8f1242ad)
+
+ lib-sieve: implementation of editheader extension completed - Updated
+ documentation. - Made editheader extension disabled by default
+
+
+M INSTALL
+M TODO
+A doc/editheader.txt
+M src/lib-sieve/sieve-extensions.c
+
+2011-11-29 22:21:13 +0100 Stephan Bosch <stephan@rename-it.nl> (eef4dfb5)
+
+ lib-sieve: editheader: implemented configurable length limit.
+
+
+M TODO
+M src/lib-sieve/plugins/editheader/Makefile.am
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.h
+A src/lib-sieve/plugins/editheader/ext-editheader-limits.h
+M tests/extensions/editheader/errors.svtest
+A tests/extensions/editheader/errors/size-limit-runtime.sieve
+A tests/extensions/editheader/errors/size-limit.sieve
+
+2011-11-29 01:10:32 +0100 Stephan Bosch <stephan@rename-it.nl> (0525a3ba)
+
+ testsuite: editheader: fixed test name for command syntax checks.
+
+
+M tests/extensions/editheader/errors.svtest
+
+2011-11-29 01:09:27 +0100 Stephan Bosch <stephan@rename-it.nl> (482a640e)
+
+ lib-sieve: vacation: made vacation action header checks use the modified
+ message (editheader).
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2011-11-29 00:57:27 +0100 Stephan Bosch <stephan@rename-it.nl> (b44d9b1d)
+
+ testsuite: editheader: added command syntax checks.
+
+
+M TODO
+M tests/extensions/editheader/errors.svtest
+A tests/extensions/editheader/errors/command-syntax.sieve
+
+2011-11-28 23:32:14 +0100 Stephan Bosch <stephan@rename-it.nl> (be2eed8c)
+
+ lib-sieve: editheader: made deleteheader match ignore leading and trailing
+ whitespace.
+
+
+M src/lib-sieve/edit-mail.c
+M tests/extensions/editheader/deleteheader.svtest
+
+2011-11-28 22:13:18 +0100 Stephan Bosch <stephan@rename-it.nl> (b10608f7)
+
+ lib-sieve: editheader: added simple configuration for protected headers.
+
+
+M Makefile.am
+M TODO
+M src/lib-sieve/plugins/editheader/Makefile.am
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.c
+M src/lib-sieve/plugins/editheader/ext-editheader-common.h
+M src/lib-sieve/plugins/editheader/ext-editheader.c
+A tests/extensions/editheader/protected.svtest
+
+2011-11-28 08:53:43 +0100 Stephan Bosch <stephan@rename-it.nl> (8ff3a4e3)
+
+ lib-sieve: editheader: fixed normal implicit keep. This was broken by
+ previous change. It now properly uses the final version of the message
+ instead of the original.
+
+
+M src/lib-sieve/sieve-result.c
+M tests/extensions/editheader/addheader.svtest
+M tests/extensions/editheader/deleteheader.svtest
+
+2011-11-28 00:49:01 +0100 Stephan Bosch <stephan@rename-it.nl> (d4ef9291)
+
+ Updated TODO.
+
+
+M TODO
+
+2011-11-28 00:40:43 +0100 Stephan Bosch <stephan@rename-it.nl> (42223b14)
+
+ lib-sieve: editheader: fixed implicit keep after runtime error. It did not
+ use the original message in this case.
+
+
+M src/lib-sieve/sieve-actions.c
+M tests/extensions/editheader/errors.svtest
+A tests/extensions/editheader/errors/runtime-error.sieve
+
+2011-11-26 14:19:42 +0100 Stephan Bosch <stephan@rename-it.nl> (a700efef)
+
+ testsuite: editheader extension: added various tests for folded headers.
+
+
+M tests/extensions/editheader/addheader.svtest
+M tests/extensions/editheader/deleteheader.svtest
+
+2011-11-26 14:19:09 +0100 Stephan Bosch <stephan@rename-it.nl> (a2e5e13a)
+
+ lib-sieve: editheader extension: fixed handling of pre-folded header values
+ for added header fields.
+
+
+M src/lib-sieve/edit-mail.c
+
+2011-11-26 14:18:05 +0100 Stephan Bosch <stephan@rename-it.nl> (a84da972)
+
+ lib-sieve: editheader extension: fixed compile warning caused by spurious
+ comma.
+
+
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+
+2011-11-26 14:06:50 +0100 Stephan Bosch <stephan@rename-it.nl> (3b45ef6c)
+
+ testsuite: added test_message_print command to print the current message
+ content.
+
+
+M src/testsuite/cmd-test-message.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-common.h
+
+2011-11-26 11:49:07 +0100 Stephan Bosch <stephan@rename-it.nl> (5831629a)
+
+ testsuite: editheader extension: added error tests for header value
+ verification.
+
+
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+M src/lib-sieve/rfc2822.c
+M tests/extensions/editheader/errors.svtest
+A tests/extensions/editheader/errors/field-value.sieve
+
+2011-11-26 11:29:07 +0100 Stephan Bosch <stephan@rename-it.nl> (a948375b)
+
+ lib-sieve: fixed bug caused by last change to rfc2822 header verification.
+
+
+M src/lib-sieve/rfc2822.c
+
+2011-11-26 11:11:43 +0100 Stephan Bosch <stephan@rename-it.nl> (896a84a7)
+
+ testsuite: editheader extension: added error tests for header field name
+ verification.
+
+
+M Makefile.am
+A tests/extensions/editheader/errors.svtest
+A tests/extensions/editheader/errors/field-name-runtime.sieve
+A tests/extensions/editheader/errors/field-name.sieve
+
+2011-11-26 11:11:02 +0100 Stephan Bosch <stephan@rename-it.nl> (69c22fa4)
+
+ lib-sieve: editheader extension: added runtime header field name
+ verification.
+
+
+M src/lib-sieve/plugins/editheader/cmd-addheader.c
+M src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+
+2011-11-26 11:09:58 +0100 Stephan Bosch <stephan@rename-it.nl> (01b034aa)
+
+ lib-sieve: updated rfc2822 header field body verification to exclude
+ non-printing characters (RFC5322).
+
+
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+M src/lib-sieve/rfc2822.c
+M src/lib-sieve/rfc2822.h
+
+2011-11-24 00:50:11 +0100 Stephan Bosch <stephan@rename-it.nl> (5621b7cd)
+
+ lib-sieve: editheader extension: added utf8-decoding-related testsuite item.
+
+
+M tests/extensions/editheader/utf8.svtest
+
+2011-11-24 00:24:47 +0100 Stephan Bosch <stephan@rename-it.nl> (9e662c12)
+
+ Added editheader support.
+
+
+M Makefile.am
+M README
+M TODO
+M configure.in
+A doc/rfc/editheader.rfc5293.txt
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+A src/lib-sieve/edit-mail.c
+A src/lib-sieve/edit-mail.h
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/editheader/Makefile.am
+A src/lib-sieve/plugins/editheader/cmd-addheader.c
+A src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+A src/lib-sieve/plugins/editheader/ext-editheader-common.c
+A src/lib-sieve/plugins/editheader/ext-editheader-common.h
+A src/lib-sieve/plugins/editheader/ext-editheader.c
+M src/lib-sieve/rfc2822.c
+M src/lib-sieve/rfc2822.h
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-size.c
+M src/testsuite/testsuite-message.c
+A tests/extensions/editheader/addheader.svtest
+A tests/extensions/editheader/alternating.svtest
+A tests/extensions/editheader/deleteheader.svtest
+A tests/extensions/editheader/utf8.svtest
+
+2011-11-19 17:51:03 +0100 Stephan Bosch <stephan@rename-it.nl> (13120b95)
+
+ Upgraded package version to 0.3.0 and updated documentation.
+
+
+M INSTALL
+M NEWS
+M README
+M TODO
+M configure.in
+M doc/man/pigeonhole.7.in
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-filter.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+
+2011-11-19 17:17:20 +0100 Stephan Bosch <stephan@rename-it.nl> (28a9e0a5)
+
+ Upgraded to Dovecot v2.1.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/sieve-actions.c
+M src/managesieve-login/client.c
+M src/testsuite/testsuite-mailstore.c
+
+2011-11-19 17:02:15 +0100 Stephan Bosch <stephan@rename-it.nl> (8e018db3)
+
+ Added signature for changeset 873baa85e220
+
+
+M .hgsigs
+
+2011-11-19 16:59:41 +0100 Stephan Bosch <stephan@rename-it.nl> (6bb95846)
+
+ Added tag 0.2.5 for changeset 873baa85e220
+
+
+2011-11-19 16:59:27 +0100 Stephan Bosch <stephan@rename-it.nl> (335451a8)
+
+ Released v0.2.5 for Dovecot v2.0.16.
+
+
+M NEWS
+M configure.in
+
+2011-11-09 17:26:18 +0100 Stephan Bosch <stephan@rename-it.nl> (f4dd33c5)
+
+ managesieve-login: Use default_vsz_limit instead of adding our own. This
+ change matches identical changes for Dovecot's imap-login and pop3-login.
+
+
+M src/managesieve-login/managesieve-login-settings.c
+
+2011-10-05 19:10:44 +0200 Stephan Bosch <stephan@rename-it.nl> (db06d68b)
+
+ lib-sieve: vacation extension: further tinkered on log message about
+ implicitly delivered messages.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2011-10-05 19:03:28 +0200 Stephan Bosch <stephan@rename-it.nl> (89f76105)
+
+ sieve-test tool: mixed up original and final envelope recipient in actual
+ implementation.
+
+
+M src/sieve-tools/sieve-test.c
+
+2011-10-05 18:45:10 +0200 Stephan Bosch <stephan@rename-it.nl> (de64342d)
+
+ Updated documentation of sieve tools.
+
+
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-filter.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+
+2011-10-05 17:43:37 +0200 Stephan Bosch <stephan@rename-it.nl> (15423beb)
+
+ lib-sieve: vacation extension: made discard message for implicit deliver
+ more verbose.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2011-09-21 11:33:00 +0200 Stephan Bosch <stephan@rename-it.nl> (14132546)
+
+ test suite: forgot to remove test_result_print command in previous change.
+
+
+M tests/extensions/vacation/message.svtest
+
+2011-09-21 00:55:58 +0200 Stephan Bosch <stephan@rename-it.nl> (1bd391b5)
+
+ lib-sieve: vacation: handled FIXME regarding the use of variables in the
+ :handle argument. Variables are now handled correctly.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2011-09-21 00:54:52 +0200 Stephan Bosch <stephan@rename-it.nl> (74418886)
+
+ test suite: added test for usage of variables in vacation command.
+
+
+M tests/extensions/vacation/message.svtest
+
+2011-09-17 09:04:55 +0200 Stephan Bosch <stephan@rename-it.nl> (e0d8e180)
+
+ Merged concurrent changes.
+
+
+2011-09-17 00:31:55 +0200 Stephan Bosch <stephan@rename-it.nl> (d6c297c8)
+
+ Last change did not even compile.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2011-09-17 00:00:03 +0200 Stephan Bosch <stephan@rename-it.nl> (07ef39ee)
+
+ lda-sieve: fall back to global recipient_delimiter setting if
+ plugin/recipient_delimiter is not set.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2011-09-16 17:57:56 +0200 Stephan Bosch <stephan@rename-it.nl> (b55c31f0)
+
+ Updated TODO.
+
+
+M TODO
+
+2011-09-14 17:18:24 +0200 Stephan Bosch <stephan@rename-it.nl> (6ce2bc3a)
+
+ testsuite: fixed compiler warning.
+
+
+M src/testsuite/testsuite-script.c
+
+2011-09-14 17:17:15 +0200 Stephan Bosch <stephan@rename-it.nl> (991b5875)
+
+ body extension: fixed handling of :content message/rfc822.
+
+
+M src/lib-sieve/plugins/body/ext-body-common.c
+M tests/extensions/body/content.svtest
+
+2011-09-13 22:43:27 +0200 Stephan Bosch <stephan@rename-it.nl> (d9c2d870)
+
+ Added signature for changeset 0d071eaa6d5e
+
+
+M .hgsigs
+
+2011-09-13 22:42:18 +0200 Stephan Bosch <stephan@rename-it.nl> (4c68258d)
+
+ Added tag 0.2.4 for changeset 0d071eaa6d5e
+
+
+2011-09-13 22:42:06 +0200 Stephan Bosch <stephan@rename-it.nl> (ba82a8f1)
+
+ Released v0.2.4 for Dovecot v2.0.14.
+
+
+M NEWS
+M configure.in
+
+2011-09-11 11:56:07 +0200 Stephan Bosch <stephan@rename-it.nl> (ea8ee4e1)
+
+ Updated INSTALL documentation for new configuration options of the include
+ extension.
+
+
+M INSTALL
+A doc/include.txt
+R084 doc/rfc/draft-ietf-sieve-include-03.txt doc/rfc/draft-ietf-sieve-include-05.txt
+M doc/vacation.txt
+
+2011-09-11 11:39:07 +0200 Stephan Bosch <stephan@rename-it.nl> (dc31e865)
+
+ include extension: made nesting_depth and max_includes limits configurable.
+
+
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-limits.h
+M src/testsuite/testsuite-script.c
+M tests/extensions/include/errors.svtest
+A tests/extensions/include/errors/depth-limit.sieve
+A tests/extensions/include/errors/include-limit.sieve
+A tests/extensions/include/included/depth-limit-1.sieve
+A tests/extensions/include/included/depth-limit-2.sieve
+A tests/extensions/include/included/depth-limit-3.sieve
+
+2011-09-11 10:51:40 +0200 Stephan Bosch <stephan@rename-it.nl> (55f2956e)
+
+ include extension: implemented proper configuration handling Configuration
+ is now only read once at extension initialization.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/testsuite/testsuite.c
+R100 tests/extensions/include/errors/included/action-fileinto.sieve tests/extensions/include/included/action-fileinto.sieve
+R100 tests/extensions/include/errors/included/action-reject.sieve tests/extensions/include/included/action-reject.sieve
+R100 tests/extensions/include/execute/included/actions-fileinto1.sieve tests/extensions/include/included/actions-fileinto1.sieve
+R100 tests/extensions/include/execute/included/actions-fileinto2.sieve tests/extensions/include/included/actions-fileinto2.sieve
+R100 tests/extensions/include/execute/included/actions-fileinto3.sieve tests/extensions/include/included/actions-fileinto3.sieve
+R100 tests/extensions/include/errors/included/circular-one.sieve tests/extensions/include/included/circular-one.sieve
+R100 tests/extensions/include/errors/included/circular-three-2.sieve tests/extensions/include/included/circular-three-2.sieve
+R100 tests/extensions/include/errors/included/circular-three-3.sieve tests/extensions/include/included/circular-three-3.sieve
+R100 tests/extensions/include/errors/included/circular-three.sieve tests/extensions/include/included/circular-three.sieve
+R100 tests/extensions/include/errors/included/circular-two-2.sieve tests/extensions/include/included/circular-two-2.sieve
+R100 tests/extensions/include/errors/included/circular-two.sieve tests/extensions/include/included/circular-two.sieve
+
+2011-09-11 00:41:04 +0200 Stephan Bosch <stephan@rename-it.nl> (8ea852c3)
+
+ variables extension: fixed deinitialization problem (unfreed variable scope
+ data) newly found by Valgrind.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+
+2011-09-11 00:19:07 +0200 Stephan Bosch <stephan@rename-it.nl> (6dc92ae9)
+
+ variables extension: fixed segfault bug triggered when dumping binary
+ variable scopes.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2011-08-29 17:33:00 +0200 Stephan Bosch <stephan@rename-it.nl> (68c89690)
+
+ Updated NEWS and README for next release.
+
+
+M NEWS
+M README
+
+2011-08-29 17:01:44 +0200 Stephan Bosch <stephan@rename-it.nl> (e8723e76)
+
+ Updated TODO.
+
+
+M TODO
+
+2011-08-29 16:55:06 +0200 Stephan Bosch <stephan@rename-it.nl> (6b79318f)
+
+ sieve: fixed debug mode; no messages were logged in some situations.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-script.c
+
+2011-08-29 16:14:26 +0200 Stephan Bosch <stephan@rename-it.nl> (2157da61)
+
+ sievec: forgot to enable -D (debug) parameter.
+
+
+M src/sieve-tools/sievec.c
+
+2011-08-02 17:50:15 +0200 Stephan Bosch <stephan@rename-it.nl> (b9d4ea72)
+
+ lib-sieve: vacation extension: finally added support for using the original
+ recipient in vacation address check.
+
+
+M doc/vacation.txt
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-objects.c
+M tests/extensions/vacation/reply.svtest
+
+2011-08-02 16:36:06 +0200 Stephan Bosch <stephan@rename-it.nl> (123bdb04)
+
+ lib-sieve: forgot to check for NULL recipient in previous change.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2011-08-02 16:25:04 +0200 Stephan Bosch <stephan@rename-it.nl> (5ed91c57)
+
+ lib-sieve: added X-Sieve-Redirected-From header for people using SPF/SRS.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2011-07-05 20:32:28 +0200 Stephan Bosch <stephan@rename-it.nl> (3de551b5)
+
+ lib-sieve: include extension: forgot to check variable identifier syntax.
+
+
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M tests/extensions/include/rfc-ex2-default.sieve
+
+2011-07-02 23:58:01 +0200 Stephan Bosch <stephan@rename-it.nl> (a755afd5)
+
+ Merged concurrent changes.
+
+
+2011-07-02 22:58:22 +0200 Stephan Bosch <stephan@rename-it.nl> (b0338390)
+
+ Updated TODO.
+
+
+M TODO
+
+2011-07-02 12:42:33 +0200 Stephan Bosch <stephan@rename-it.nl> (4558b7d9)
+
+ Updated documentation.
+
+
+M NEWS
+M README
+
+2011-06-29 00:55:48 +0200 Stephan Bosch <stephan@rename-it.nl> (a454ba13)
+
+ lib-sieve: variables extension: fixed -Wunused-but-set-variable compiler
+ warning.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+
+2011-06-26 23:23:33 +0200 Stephan Bosch <stephan@rename-it.nl> (9ea19c87)
+
+ Added ihave RFC to repository.
+
+
+A doc/rfc/ihave.rfc5463.txt
+
+2011-06-26 23:07:33 +0200 Stephan Bosch <stephan@rename-it.nl> (3aa7648d)
+
+ lib-sieve: finished ihave extension.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/ihave/Makefile.am
+A src/lib-sieve/plugins/ihave/cmd-error.c
+M src/lib-sieve/plugins/ihave/ext-ihave-common.h
+M src/lib-sieve/plugins/ihave/ext-ihave.c
+M src/lib-sieve/plugins/ihave/tst-ihave.c
+A tests/extensions/ihave/errors.svtest
+A tests/extensions/ihave/errors/error.sieve
+A tests/extensions/ihave/restrictions.svtest
+
+2011-06-26 22:35:31 +0200 Stephan Bosch <stephan@rename-it.nl> (3c1c2d99)
+
+ Updated TODO list.
+
+
+M TODO
+
+2011-06-26 22:34:09 +0200 Stephan Bosch <stephan@rename-it.nl> (d4685130)
+
+ lib-sieve: implemented ihave extension.
+
+
+M Makefile.am
+M configure.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/ihave/Makefile.am
+A src/lib-sieve/plugins/ihave/ext-ihave-binary.c
+A src/lib-sieve/plugins/ihave/ext-ihave-binary.h
+A src/lib-sieve/plugins/ihave/ext-ihave-common.c
+A src/lib-sieve/plugins/ihave/ext-ihave-common.h
+A src/lib-sieve/plugins/ihave/ext-ihave.c
+A src/lib-sieve/plugins/ihave/tst-ihave.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+A tests/extensions/ihave/execute.svtest
+A tests/extensions/ihave/execute/ihave.sieve
+
+2011-06-26 17:07:53 +0200 Stephan Bosch <stephan@rename-it.nl> (a2e42ebd)
+
+ lib-sieve: optimized compilation of tests that yield constant results (i.e.
+ known at compile tme), such as true and false. If the result of a test is
+ known at compile time, it is optimized away. If an if-command depends on an
+ entirely constant test, it is optimized away as well, causing only the
+ 'true' sub-block to be compiled.
+
+
+M TODO
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/plugins/vnd.dovecot/debug/cmd-debug-log.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/lib-sieve/tst-truefalse.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-action.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+M tests/control-if.svtest
+M tests/test-allof.svtest
+M tests/test-anyof.svtest
+
+2011-06-22 22:17:28 +0200 Stephan Bosch <stephan@rename-it.nl> (249742c5)
+
+ Sieve tools: started using mail_namespaces_init_location instead of
+ mail_namespaces_init_empty.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite.c
+
+2011-06-22 19:56:29 +0200 Stephan Bosch <stephan@rename-it.nl> (939bf15e)
+
+ lib-sieve: made sure that flags and keywords are only checked when the
+ mailbox is actually opened.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2011-06-22 19:33:49 +0200 Stephan Bosch <stephan@rename-it.nl> (273cce20)
+
+ Finished testsuite item for the imap4flags extension.
+
+
+M tests/extensions/imap4flags/execute.svtest
+
+2011-06-21 17:18:58 +0200 Stephan Bosch <stephan@rename-it.nl> (4abd9c16)
+
+ Fixed a few minor textual problems in the manual pages.
+
+
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-filter.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+
+2011-06-06 16:59:39 +0200 Stephan Bosch <stephan@rename-it.nl> (59eb6248)
+
+ Made vnd.dovecot.debug extension available to the LDA plugin instead of only
+ the command line tools.
+
+
+M Makefile.am
+M configure.in
+M doc/man/sieve-test.1.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/vnd.dovecot/Makefile.am
+R085 src/sieve-tools/debug/Makefile.am src/lib-sieve/plugins/vnd.dovecot/debug/Makefile.am
+R063 src/sieve-tools/debug/cmd-debug-print.c src/lib-sieve/plugins/vnd.dovecot/debug/cmd-debug-log.c
+R051 src/sieve-tools/debug/ext-debug-common.h src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug-common.h
+A src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/sieve-tools/Makefile.am
+D src/sieve-tools/debug/ext-debug.c
+D src/sieve-tools/debug/sieve-ext-debug.h
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/testsuite-log.c
+A tests/extensions/vnd.dovecot/debug/execute.svtest
+
+2011-05-11 19:26:57 +0200 Stephan Bosch <stephan@rename-it.nl> (7f56af7a)
+
+ Sieve Storage: improved handling of unconfigured user home directory.
+
+
+M src/lib-sievestorage/sieve-storage.c
+M src/managesieve/managesieve-client.c
+
+2011-05-10 21:36:47 +0200 Stephan Bosch <stephan@rename-it.nl> (0964cb6c)
+
+ Imap4flags: previous change was inadequate.
+
+
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-validator.c
+
+2011-05-09 20:56:08 +0200 Stephan Bosch <stephan@rename-it.nl> (94aef858)
+
+ Imap4flags: prevent forcibly enabling imap4flags when imapflags is enabled.
+
+
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/vacation/ext-vacation-seconds.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+
+2011-04-14 22:45:40 +0200 Stephan Bosch <stephan@rename-it.nl> (021b7f00)
+
+ Added signature for changeset 3ab2a125e1e2
+
+
+M .hgsigs
+
+2011-04-14 22:44:05 +0200 Stephan Bosch <stephan@rename-it.nl> (cd48584b)
+
+ Added tag 0.2.3 for changeset 3ab2a125e1e2
+
+
+2011-04-14 22:43:50 +0200 Stephan Bosch <stephan@rename-it.nl> (1ef3f05a)
+
+ Released v0.2.3 for Dovecot v2.0.12.
+
+
+M configure.in
+
+2011-04-14 21:32:01 +0200 Stephan Bosch <stephan@rename-it.nl> (9dea325c)
+
+ Prepared NEWS file for next release.
+
+
+M NEWS
+
+2011-04-14 21:31:34 +0200 Stephan Bosch <stephan@rename-it.nl> (4eedbc27)
+
+ Small changes to the INSTALL file regarding configuration of vacation
+ extension.
+
+
+M INSTALL
+
+2011-04-14 21:27:22 +0200 Stephan Bosch <stephan@rename-it.nl> (e4eb532d)
+
+ Updated RFC for vacation-seconds extension.
+
+
+R053 doc/rfc/draft-ietf-sieve-vacation-seconds-03.txt doc/rfc/vacation-seconds.rfc6131.txt
+
+2011-04-14 21:26:42 +0200 Stephan Bosch <stephan@rename-it.nl> (43706eb0)
+
+ Restructured extension-specific install documentation.
+
+
+M doc/spamtest-virustest.txt
+M doc/vacation.txt
+
+2011-04-13 01:00:10 +0200 Stephan Bosch <stephan@rename-it.nl> (780eded2)
+
+ Managesieve-login: increased dump-capability time-out from 5 to 60 s.
+
+
+M src/managesieve-login/managesieve-login-settings-plugin.c
+
+2011-04-10 17:28:14 +0200 Stephan Bosch <stephan@rename-it.nl> (589fdabb)
+
+ managsieve-login: Reduced the max. number of allowed bad commands.
+
+
+M src/managesieve-login/client.c
+
+2011-03-22 22:25:11 +0100 Stephan Bosch <stephan@rename-it.nl> (2e939b67)
+
+ Sieve tools: avoid initializing mail store (namespaces) for sievec and
+ sieve-dump.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/testsuite.c
+
+2011-03-22 22:08:55 +0100 Stephan Bosch <stephan@rename-it.nl> (f433f945)
+
+ Fixed various compile warnings related to spurious semicolons and
+ inappropriate variable initialization.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/sieve-result.c
+M src/testsuite/cmd-test-message.c
+
+2011-03-05 14:48:20 +0100 Stephan Bosch <stephan@rename-it.nl> (d1b70d7b)
+
+ Updated copyright notices to include year 2011.
+
+
+M doc/man/pigeonhole.7.in
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-managesieve/managesieve-parser.h
+M src/lib-managesieve/managesieve-quote.c
+M src/lib-managesieve/managesieve-quote.h
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/cmp-i-ascii-casemap.c
+M src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/copy/sieve-ext-copy.h
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/date/ext-date.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify-limits.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/ext-environment-common.h
+M src/lib-sieve/plugins/environment/ext-environment.c
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-limits.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/notify/ext-notify-limits.h
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation-seconds.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/rfc2822.c
+M src/lib-sieve/rfc2822.h
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary-code.c
+M src/lib-sieve/sieve-binary-debug.c
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-plugins.c
+M src/lib-sieve/sieve-plugins.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-stringlist.c
+M src/lib-sieve/sieve-stringlist.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/lib-sieve/tst-truefalse.c
+M src/lib-sievestorage/sieve-storage-list.c
+M src/lib-sievestorage/sieve-storage-list.h
+M src/lib-sievestorage/sieve-storage-private.h
+M src/lib-sievestorage/sieve-storage-quota.c
+M src/lib-sievestorage/sieve-storage-quota.h
+M src/lib-sievestorage/sieve-storage-save.c
+M src/lib-sievestorage/sieve-storage-save.h
+M src/lib-sievestorage/sieve-storage-script.c
+M src/lib-sievestorage/sieve-storage-script.h
+M src/lib-sievestorage/sieve-storage.c
+M src/lib-sievestorage/sieve-storage.h
+M src/managesieve-login/client-authenticate.c
+M src/managesieve-login/client-authenticate.h
+M src/managesieve-login/client.c
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-login-settings-plugin.c
+M src/managesieve-login/managesieve-login-settings-plugin.h
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve-login/managesieve-login-settings.h
+M src/managesieve-login/managesieve-proxy.c
+M src/managesieve-login/managesieve-proxy.h
+M src/managesieve/cmd-capability.c
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-havespace.c
+M src/managesieve/cmd-listscripts.c
+M src/managesieve/cmd-logout.c
+M src/managesieve/cmd-noop.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/cmd-setactive.c
+M src/managesieve/main.c
+M src/managesieve/managesieve-capabilities.c
+M src/managesieve/managesieve-capabilities.h
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+M src/managesieve/managesieve-commands.c
+M src/managesieve/managesieve-commands.h
+M src/managesieve/managesieve-common.h
+M src/managesieve/managesieve-quota.c
+M src/managesieve/managesieve-quota.h
+M src/managesieve/managesieve-settings.c
+M src/managesieve/managesieve-settings.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.h
+M src/sieve-tools/debug/cmd-debug-print.c
+M src/sieve-tools/debug/ext-debug-common.h
+M src/sieve-tools/debug/ext-debug.c
+M src/sieve-tools/debug/sieve-ext-debug.h
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-arguments.c
+M src/testsuite/testsuite-arguments.h
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-binary.h
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-log.h
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-script.h
+M src/testsuite/testsuite-settings.c
+M src/testsuite/testsuite-settings.h
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/testsuite-substitutions.h
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-action.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2011-03-02 17:42:53 +0100 Stephan Bosch <stephan@rename-it.nl> (1d6239be)
+
+ Fixed segfault bug in extension configuration, triggered when unknown
+ extension is mentioned in sieve_extensions setting.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2011-02-23 22:59:40 +0100 Stephan Bosch <stephan@rename-it.nl> (508398e7)
+
+ Sieve-filter tool: forgot to enable -u option.
+
+
+M src/sieve-tools/sieve-filter.c
+
+2011-02-23 11:17:50 +0100 Stephan Bosch <stephan@rename-it.nl> (c51569ee)
+
+ Fixed some more minor problems in the man pages (patch by Pascal Volk).
+
+
+M doc/man/Makefile.am
+M doc/man/sieve-filter.1.in
+
+2011-02-23 01:26:55 +0100 Stephan Bosch <stephan@rename-it.nl> (3097e3e2)
+
+ Fixed some minor problems in the man pages (patch by Pascal Volk).
+
+
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-filter.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+
+2011-02-20 16:42:17 +0100 Stephan Bosch <stephan@rename-it.nl> (38fb3da0)
+
+ Vacation extension: added test for proper From: address when replying for
+ Cc'd e-mail.
+
+
+M tests/extensions/vacation/smtp.svtest
+
+2011-02-19 08:45:13 +0100 Stephan Bosch <stephan@rename-it.nl> (ac5245ff)
+
+ ManageSieve: fixed problems in previous change; utf-8 was actually denied
+ completely.
+
+
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-managesieve/managesieve-quote.c
+
+2011-02-18 14:03:28 +0100 Stephan Bosch <stephan@rename-it.nl> (2a321138)
+
+ ManageSieve: now using Dovecot API for UTF-8 validity checks.
+
+
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-managesieve/managesieve-parser.h
+M src/lib-managesieve/managesieve-quote.c
+
+2011-02-18 02:58:43 +0100 Stephan Bosch <stephan@rename-it.nl> (e3d57260)
+
+ Fixed potential segfault in extension registry.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2011-02-17 21:12:44 +0100 Stephan Bosch <stephan@rename-it.nl> (5d67c89d)
+
+ ManageSieve: fixed bug in UTF-8 checking of string values.
+
+
+M src/lib-managesieve/managesieve-parser.c
+
+2011-02-13 10:27:11 +0100 Stephan Bosch <stephan@rename-it.nl> (2cbeec33)
+
+ Sieve filter tool: finished basic functionality.
+
+
+M TODO
+M doc/man/sieve-filter.1.in
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+
+2011-02-11 09:24:12 +0100 Stephan Bosch <stephan@rename-it.nl> (015073d0)
+
+ Fixed bug in parsing of duration settings.
+
+
+M src/lib-sieve/sieve-settings.c
+
+2011-02-09 19:38:58 +0100 Stephan Bosch <stephan@rename-it.nl> (5bae97dc)
+
+ Testsuite: fixed prefix of -E option info log output.
+
+
+M src/testsuite/testsuite-log.c
+
+2011-02-09 19:32:28 +0100 Stephan Bosch <stephan@rename-it.nl> (6d3c929f)
+
+ Vacation extension: added tests for reply filtering test suite.
+
+
+M Makefile.am
+A tests/extensions/vacation/reply.svtest
+
+2011-02-09 19:31:36 +0100 Stephan Bosch <stephan@rename-it.nl> (674599b9)
+
+ Vacation extension: now inhibits replies to messages from sender listed in
+ :addresses.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2011-02-09 19:29:43 +0100 Stephan Bosch <stephan@rename-it.nl> (f9b1c10e)
+
+ Testsuite: added info log output to -E command line option.
+
+
+M src/testsuite/testsuite-log.c
+
+2011-01-26 00:51:55 +0100 Stephan Bosch <stephan@rename-it.nl> (bc3d93c5)
+
+ Sieve tools: prevent automatically creating mail storage.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+
+2011-01-25 02:44:29 +0100 Stephan Bosch <stephan@rename-it.nl> (db97d27a)
+
+ Vacation-seconds extension: added specification to doc/rfc.
+
+
+A doc/rfc/draft-ietf-sieve-vacation-seconds-03.txt
+
+2011-01-25 02:43:25 +0100 Stephan Bosch <stephan@rename-it.nl> (0d74a9e9)
+
+ Vacation extension: implemented the (draft) vacation-seconds extension.
+
+
+M INSTALL
+M doc/vacation.txt
+M src/lib-sieve/plugins/vacation/Makefile.am
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+A src/lib-sieve/plugins/vacation/ext-vacation-seconds.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M tests/extensions/vacation/execute.svtest
+A tests/extensions/vacation/execute/seconds.sieve
+
+2011-01-25 01:27:01 +0100 Stephan Bosch <stephan@rename-it.nl> (3817e2b0)
+
+ Vacation extension: added default period configuration setting and fixed a
+ limit bug.
+
+
+M doc/vacation.txt
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+
+2011-01-25 01:05:28 +0100 Stephan Bosch <stephan@rename-it.nl> (000ee266)
+
+ Vacation extension: added min/max period configuration settings and changed
+ the internal unit from days to seconds.
+
+
+M INSTALL
+M doc/Makefile.am
+A doc/vacation.txt
+M src/lib-sieve/plugins/vacation/Makefile.am
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+A src/lib-sieve/plugins/vacation/ext-vacation-common.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+
+2011-01-24 23:39:32 +0100 Stephan Bosch <stephan@rename-it.nl> (ccceee98)
+
+ Restructured settings parsing and added parsing support for duration
+ settings.
+
+
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+
+2011-01-23 13:44:13 +0100 Stephan Bosch <stephan@rename-it.nl> (e20025dc)
+
+ Copy extension: previous change was incomplete and broken.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+
+2011-01-23 13:40:33 +0100 Stephan Bosch <stephan@rename-it.nl> (e2e385f5)
+
+ Merged concurrent changes.
+
+
+2011-01-23 13:39:50 +0100 Stephan Bosch <stephan@rename-it.nl> (acf7285a)
+
+ Copy extension: added public interface for adding the :copy tag to new
+ commands.
+
+
+M src/lib-sieve/plugins/copy/Makefile.am
+M src/lib-sieve/plugins/copy/ext-copy.c
+A src/lib-sieve/plugins/copy/sieve-ext-copy.h
+
+2011-01-19 17:37:43 +0100 Stephan Bosch <stephan@rename-it.nl> (b67b1843)
+
+ Enotify: mailto: fixed inappropriate return type in URI parse function, also
+ fixing ARM compiler warning.
+
+
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+
+2011-01-18 21:46:08 +0100 Stephan Bosch <stephan@rename-it.nl> (f22c14f5)
+
+ Notify extension: fixed duplicate variable declaration.
+
+
+M src/lib-sieve/plugins/notify/cmd-notify.c
+
+2011-01-06 15:50:31 +0100 Stephan Bosch <stephan@rename-it.nl> (7f771cb4)
+
+ ManageSieve: removed TODO status of adding ANONYMOUS SASL support, since the
+ RFC specification no longer describes it.
+
+
+M README
+M TODO
+M src/managesieve-login/client-authenticate.c
+
+2011-01-04 12:51:58 +0100 Stephan Bosch <stephan@rename-it.nl> (86eb5660)
+
+ Vacation: fixed handling of sendmail errors.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2011-01-01 15:51:21 +0100 Stephan Bosch <stephan@rename-it.nl> (2153efc9)
+
+ Deprecated notify extension: reverted previous change as address is used for
+ the notification in stead of being actually parsed.
+
+
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+
+2011-01-01 15:21:44 +0100 Stephan Bosch <stephan@rename-it.nl> (adc6c8ce)
+
+ Removed header MIME-decoding for other instances where addresses need to be
+ parsed.
+
+
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2011-01-01 14:10:53 +0100 Stephan Bosch <stephan@rename-it.nl> (a2d09e04)
+
+ Address test: removed header MIME-decoding to prevent address parsing
+ problems.
+
+
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+M tests/test-address.svtest
+
+2010-12-07 00:05:50 +0100 Stephan Bosch <stephan@rename-it.nl> (d1b2051a)
+
+ Added signature for changeset df8b38da248c
+
+
+M .hgsigs
+
+2010-12-07 00:04:57 +0100 Stephan Bosch <stephan@rename-it.nl> (d70e7597)
+
+ Added tag 0.2.2 for changeset df8b38da248c
+
+
+2010-12-07 00:04:27 +0100 Stephan Bosch <stephan@rename-it.nl> (c70867fb)
+
+ Released v0.2.2 for Dovecot v2.0.8.
+
+
+M NEWS
+M configure.in
+
+2010-12-03 22:24:06 +0100 Stephan Bosch <stephan@rename-it.nl> (b17db543)
+
+ Prepared NEWS file for next release.
+
+
+M NEWS
+
+2010-12-01 00:46:31 +0100 Stephan Bosch <stephan@rename-it.nl> (35cdc868)
+
+ LDA Sieve plugin: started using Dovecot reject API.
+
+
+M TODO
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-types.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2010-12-01 00:34:47 +0100 Stephan Bosch <stephan@rename-it.nl> (2f20241f)
+
+ Fixed segfault caused by previous fix.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2010-11-30 22:49:57 +0100 Stephan Bosch <stephan@rename-it.nl> (e043367a)
+
+ LDA Sieve plugin: fixed memory leak at deinitialization (patch by Timo
+ Sirainen).
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2010-11-22 17:03:28 +0100 Stephan Bosch <stephan@rename-it.nl> (6282f9cc)
+
+ managesieve: Fixed giving any -parameters (analogoues to Dovecot fix).
+
+
+M src/managesieve/main.c
+
+2010-11-16 22:09:02 +0100 Stephan Bosch <stephan@rename-it.nl> (7d1c5a0a)
+
+ Services' default vsz_limit wasn't actually using default_vsz_limit but
+ rather 4 GB.
+
+
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve/managesieve-settings.c
+
+2010-11-16 22:08:10 +0100 Stephan Bosch <stephan@rename-it.nl> (1ffebb22)
+
+ "Running standalone?" check now uses a new DOVECOT_CHILD_PROCESS environment
+ rather than GENERATION. The GENERATION environment was already set in some
+ systems for Java.
+
+
+M src/managesieve/main.c
+
+2010-11-03 17:54:07 +0100 Stephan Bosch <stephan@rename-it.nl> (ad495903)
+
+ Avoids potential problems if auth process crashes and service_count > 1
+ (patch by Timo Sirainen).
+
+
+M src/managesieve/main.c
+
+2010-10-17 10:21:13 +0200 Stephan Bosch <stephan@rename-it.nl> (84d7b77c)
+
+ Sieve-filter: minor addition to the man page.
+
+
+M doc/man/sieve-filter.1.in
+
+2010-10-16 21:19:51 +0200 Stephan Bosch <stephan@rename-it.nl> (600afb87)
+
+ Sieve-filter: implemented basic filtering with source mailbox actions.
+
+
+M doc/man/sieve-filter.1.in
+M src/sieve-tools/sieve-filter.c
+
+2010-10-01 19:04:32 +0200 Stephan Bosch <stephan@rename-it.nl> (e56cdec7)
+
+ Sieve-filter: fixed tool compilation and further developed tool design.
+
+
+M TODO
+M doc/man/sieve-filter.1.in
+M src/sieve-tools/sieve-filter.c
+
+2010-10-01 19:03:08 +0200 Stephan Bosch <stephan@rename-it.nl> (af388430)
+
+ Sieve tools: fixed help text for sieve-test command and some minor
+ adjustments.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/sieve-tools/sieve-test.c
+
+2010-09-30 23:21:54 +0200 Stephan Bosch <stephan@rename-it.nl> (65f870bf)
+
+ Sieve-filter: updated man page.
+
+
+M doc/man/sieve-filter.1.in
+
+2010-09-30 21:11:34 +0200 Stephan Bosch <stephan@rename-it.nl> (d751082c)
+
+ Imap4flags: fixed segfault bug occuring in multiscript context.
+
+
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+
+2010-09-28 22:50:04 +0200 Stephan Bosch <stephan@rename-it.nl> (2d23339a)
+
+ Improved ManageSieve config example; 'sieve' is added to protocols setting
+ in 20-managesieve.conf now.
+
+
+M doc/example-config/conf.d/20-managesieve.conf
+
+2010-09-28 22:24:35 +0200 Stephan Bosch <stephan@rename-it.nl> (623f5a9b)
+
+ ManageSieve: added settings plugin version checking.
+
+
+M src/managesieve-login/managesieve-login-settings-plugin.c
+M src/managesieve/managesieve-settings.c
+
+2010-09-27 01:50:24 +0200 Stephan Bosch <stephan@rename-it.nl> (f69eeb68)
+
+ Added signature for changeset d768f911252d
+
+
+A .hgsigs
+
+2010-09-27 01:44:09 +0200 Stephan Bosch <stephan@rename-it.nl> (e545e840)
+
+ Added tag 0.2.1 for changeset d768f911252d
+
+
+2010-09-27 01:43:24 +0200 Stephan Bosch <stephan@rename-it.nl> (5d3a336f)
+
+ Released v0.2.1 for Dovecot v2.0.4.
+
+
+M NEWS
+M configure.in
+
+2010-09-27 00:19:45 +0200 Stephan Bosch <stephan@rename-it.nl> (7c2ccf0b)
+
+ LDA Sieve plugin: added _version symbol to enable Dovecot version checking.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2010-09-23 16:54:02 +0200 Stephan Bosch <stephan@rename-it.nl> (b339695c)
+
+ LDA Sieve plugin: updated wiki link in error message.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2010-09-23 16:46:40 +0200 Stephan Bosch <stephan@rename-it.nl> (9374a431)
+
+ LDA Sieve plugin: turned debug message into an error and added script path
+ information.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2010-09-17 23:12:05 +0200 Stephan Bosch <stephan@rename-it.nl> (36e3798d)
+
+ Incorporated distinction between original and final envelope recipient in
+ Sieve interpreter, as recently introduced in Dovecot.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-types.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-message.c
+
+2010-09-17 22:05:33 +0200 Stephan Bosch <stephan@rename-it.nl> (59568b9d)
+
+ Regex: added support for variable regex keys.
+
+
+M TODO
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M tests/compile/errors.svtest
+M tests/compile/errors/unsupported.sieve
+M tests/extensions/regex/basic.svtest
+M tests/extensions/regex/errors.svtest
+A tests/extensions/regex/errors/runtime.sieve
+
+2010-09-17 21:20:37 +0200 Stephan Bosch <stephan@rename-it.nl> (52b7dd1a)
+
+ Fixed comparator/match-type macro mixup.
+
+
+M src/lib-sieve/tst-header.c
+
+2010-09-13 02:48:50 +0200 Stephan Bosch <stephan@rename-it.nl> (7b49dde4)
+
+ Fixed unnecessary reporting of dummy extensions in ManageSieve SIEVE
+ capability.
+
+
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+
+2010-09-10 02:04:17 +0200 Stephan Bosch <stephan@rename-it.nl> (c1362376)
+
+ Added tag 0.2.0 for changeset 7bdabe6f9757
+
+
+2010-09-10 02:04:11 +0200 Stephan Bosch <stephan@rename-it.nl> (7202ebb9)
+
+ Released v0.2.0 for Dovecot v2.0.2.
+
+
+M NEWS
+M TODO
+M configure.in
+
+2010-09-10 00:33:03 +0200 Stephan Bosch <stephan@rename-it.nl> (c275ef53)
+
+ Updated the Compile section of the INSTALL file.
+
+
+M INSTALL
+
+2010-09-10 00:16:10 +0200 Stephan Bosch <stephan@rename-it.nl> (8a0316ba)
+
+ Fixed make distcheck to work.
+
+
+M configure.in
+M m4/dovecot.m4
+
+2010-09-09 23:59:56 +0200 Stephan Bosch <stephan@rename-it.nl> (f53adf75)
+
+ Removed --enable-header-install setting.
+
+
+M Makefile.am
+M configure.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/enotify/Makefile.am
+M src/lib-sieve/plugins/environment/Makefile.am
+M src/lib-sieve/plugins/variables/Makefile.am
+
+2010-09-09 09:24:40 +0200 Stephan Bosch <stephan@rename-it.nl> (6cc8c323)
+
+ Fixed series of AIX compiler warnings.
+
+
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/sieve-plugins.c
+
+2010-09-08 23:27:57 +0200 Stephan Bosch <stephan@rename-it.nl> (7be6741e)
+
+ Added a few missing NEWS items and fixed some formatting issues.
+
+
+M NEWS
+
+2010-09-08 20:58:01 +0200 Stephan Bosch <stephan@rename-it.nl> (c52eebe2)
+
+ Updated README documentation.
+
+
+M README
+
+2010-09-08 20:52:38 +0200 Stephan Bosch <stephan@rename-it.nl> (b7df21ba)
+
+ Updated INSTALL documentation.
+
+
+M INSTALL
+
+2010-09-08 20:04:56 +0200 Stephan Bosch <stephan@rename-it.nl> (4467bb97)
+
+ ManageSieve: fixed dump-capability problem occuring when using a custom
+ config file (patch by Timo Sirainen).
+
+
+M src/managesieve-login/managesieve-login-settings-plugin.c
+
+2010-09-06 18:36:25 +0200 Stephan Bosch <stephan@rename-it.nl> (f302ee17)
+
+ Sieve-dump: added support for producing per-block hexdump output.
+
+
+M doc/man/sieve-dump.1.in
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/sieve-tools/sieve-dump.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/testsuite.c
+
+2010-09-05 21:37:41 +0200 Stephan Bosch <stephan@rename-it.nl> (9772fd7f)
+
+ Added support for critical runtime errors.
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+
+2010-09-05 17:57:17 +0200 Stephan Bosch <stephan@rename-it.nl> (b3f447ee)
+
+ Error handling: don't log user message of critical error to system log.
+
+
+M src/lib-sieve/sieve-error.c
+
+2010-09-05 17:53:16 +0200 Stephan Bosch <stephan@rename-it.nl> (8fe5d7a2)
+
+ Sieve plugin: only refer to user log for compile error details when there is
+ actually a compile error.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2010-09-05 16:27:06 +0200 Stephan Bosch <stephan@rename-it.nl> (831fd560)
+
+ Final preparations for 0.2 release.
+
+
+M NEWS
+M TODO
+
+2010-09-05 15:11:13 +0200 Stephan Bosch <stephan@rename-it.nl> (c31f7561)
+
+ Sieve plugin: simplified system error handling.
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/plugins/lda-sieve/Makefile.am
+D src/plugins/lda-sieve/lda-sieve-log.c
+D src/plugins/lda-sieve/lda-sieve-log.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2010-09-05 14:24:19 +0200 Stephan Bosch <stephan@rename-it.nl> (87c1022c)
+
+ Simplified error handling; in particular the changes in the preceeding
+ commits.
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sievestorage/sieve-storage.c
+M src/plugins/lda-sieve/lda-sieve-log.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/testsuite/testsuite-log.c
+
+2010-09-04 14:53:35 +0200 Stephan Bosch <stephan@rename-it.nl> (ea639eaf)
+
+ Fixed runtime error logging not to report user-caused errors to the master
+ log.
+
+
+M TODO
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-validator.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2010-09-04 14:51:35 +0200 Stephan Bosch <stephan@rename-it.nl> (6eb224c4)
+
+ Made global system error handler state part of Sieve instance.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/tst-size.c
+M src/lib-sievestorage/sieve-storage.c
+M src/managesieve/cmd-putscript.c
+M src/plugins/lda-sieve/lda-sieve-log.c
+M src/plugins/lda-sieve/lda-sieve-log.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-mailstore.c
+
+2010-09-03 17:58:23 +0200 Stephan Bosch <stephan@rename-it.nl> (cc2c8e27)
+
+ Fixed default Sieve capability: extra extensions spamtest, spamtestplus and
+ virustest were also enabled by default.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2010-08-30 10:34:37 +0200 Stephan Bosch <stephan@rename-it.nl> (95154243)
+
+ Finished FIXME review.
+
+
+M TODO
+
+2010-08-30 10:30:47 +0200 Stephan Bosch <stephan@rename-it.nl> (25293c5a)
+
+ Fixed FIXME: fileinto folder name utf-8 validity is now checked at
+ compiletime or runtime.
+
+
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/sieve-actions.c
+
+2010-08-30 10:13:54 +0200 Stephan Bosch <stephan@rename-it.nl> (b75d2e74)
+
+ Made sure that store action logs both UTF-8 and mUTF-7 names when
+ applicable.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2010-08-30 09:20:44 +0200 Stephan Bosch <stephan@rename-it.nl> (4897d7b0)
+
+ Fixed FIXME: added runtime warning for erroneous :addresses item.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2010-08-30 03:15:57 +0200 Stephan Bosch <stephan@rename-it.nl> (d0d60d62)
+
+ Removed spurious source file.
+
+
+D src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2010-08-30 03:13:29 +0200 Stephan Bosch <stephan@rename-it.nl> (741f13eb)
+
+ Fixed FIXME: Date test now reports warning when invalid zone argument is
+ encountered at runtime.
+
+
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+
+2010-08-30 02:52:49 +0200 Stephan Bosch <stephan@rename-it.nl> (a629c533)
+
+ Fixed FIXME: Imap4flags extension now checks flag keyword syntax before the
+ message is stored.
+
+
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+
+2010-08-30 02:37:07 +0200 Stephan Bosch <stephan@rename-it.nl> (66f356ab)
+
+ Modified TODO item.
+
+
+M TODO
+M src/lib-sieve/ext-reject.c
+
+2010-08-30 02:33:26 +0200 Stephan Bosch <stephan@rename-it.nl> (d5880b7c)
+
+ Fixed FIXME: when redirect address is a variable, it is checked for validity
+ at runtime.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/sieve-address-parts.c
+M src/managesieve/cmd-putscript.c
+
+2010-08-30 02:18:54 +0200 Stephan Bosch <stephan@rename-it.nl> (dda5cd20)
+
+ Simplified runtime command script location querying.
+
+
+M TODO
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/sieve-tools/debug/cmd-debug-print.c
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-script.c
+
+2010-08-29 11:34:40 +0200 Stephan Bosch <stephan@rename-it.nl> (c84b56d1)
+
+ Testsuite: partly cleaned up test scripts (rest is post-v0.2).
+
+
+M Makefile.am
+M TODO
+D tests/address.svtest
+D tests/comparators/core.svtest
+A tests/comparators/i-ascii-casemap.svtest
+A tests/comparators/i-octet.svtest
+M tests/compile/errors.svtest
+M tests/compile/errors/match-type.sieve
+M tests/compile/recover.svtest
+M tests/compile/recover/commands-endblock.sieve
+M tests/compile/recover/commands-semicolon.sieve
+M tests/compile/recover/tests-endcomma.sieve
+M tests/compile/warnings.svtest
+M tests/compile/warnings/eof.sieve
+M tests/compile/warnings/invalid-headers.sieve
+A tests/control-if.svtest
+A tests/control-stop.svtest
+D tests/control-structures.svtest
+M tests/deprecated/imapflags/execute.svtest
+M tests/deprecated/notify/denotify.svtest
+M tests/execute/smtp.svtest
+D tests/exists.svtest
+M tests/extensions/encoded-character.svtest
+M tests/extensions/envelope.svtest
+M tests/extensions/imap4flags/basic.svtest
+M tests/extensions/imap4flags/flagstore.svtest
+M tests/extensions/imap4flags/flagstring.svtest
+M tests/extensions/imap4flags/multiscript.svtest
+M tests/extensions/imap4flags/multiscript/group-spam.sieve
+M tests/extensions/imap4flags/multiscript/sent-store.sieve
+M tests/extensions/include/included/rfc-ex1-always_allow.sieve
+M tests/extensions/include/included/rfc-ex1-mailing_lists.sieve
+M tests/extensions/regex/match-values.svtest
+M tests/extensions/relational/basic.svtest
+M tests/extensions/relational/comparators.svtest
+M tests/extensions/spamvirustest/virustest.svtest
+M tests/extensions/subaddress/basic.svtest
+M tests/extensions/subaddress/config.svtest
+M tests/extensions/vacation/execute/no-handle.sieve
+D tests/header.svtest
+M tests/match-types/contains.svtest
+M tests/multiscript/conflicts.svtest
+D tests/size.svtest
+A tests/test-address.svtest
+A tests/test-allof.svtest
+A tests/test-anyof.svtest
+A tests/test-exists.svtest
+A tests/test-header.svtest
+A tests/test-size.svtest
+M tests/testsuite.svtest
+
+2010-08-28 13:13:16 +0200 Stephan Bosch <stephan@rename-it.nl> (329f4c13)
+
+ Testsuite: made command syntax more uniform.
+
+
+M TODO
+M src/testsuite/Makefile.am
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-mailbox.c
+D src/testsuite/cmd-test-result-print.c
+D src/testsuite/cmd-test-result-reset.c
+A src/testsuite/cmd-test-result.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-common.h
+R076 src/testsuite/tst-test-result.c src/testsuite/tst-test-result-action.c
+M tests/deprecated/notify/execute.svtest
+M tests/execute/actions.svtest
+M tests/execute/errors.svtest
+M tests/execute/examples.svtest
+M tests/extensions/enotify/execute.svtest
+M tests/extensions/imap4flags/execute.svtest
+M tests/extensions/include/execute.svtest
+M tests/extensions/mailbox/execute.svtest
+M tests/extensions/reject/execute.svtest
+M tests/extensions/spamvirustest/spamtest.svtest
+M tests/extensions/spamvirustest/spamtestplus.svtest
+M tests/extensions/spamvirustest/virustest.svtest
+M tests/extensions/subaddress/config.svtest
+M tests/extensions/vacation/execute.svtest
+M tests/multiscript/basic.svtest
+M tests/multiscript/conflicts.svtest
+
+2010-08-27 22:33:52 +0200 Stephan Bosch <stephan@rename-it.nl> (0a7d1584)
+
+ doc/man/sievec.1.in: fixed roff error caused by unescaped '-' (patch by Mike
+ Abbott).
+
+
+M doc/man/sievec.1.in
+
+2010-08-27 22:25:19 +0200 Stephan Bosch <stephan@rename-it.nl> (3e05feb7)
+
+ ManageSieve: settings plugin, capability dump: argument array for execv was
+ too short by one element.
+
+
+M src/managesieve-login/managesieve-login-settings-plugin.c
+
+2010-08-27 22:22:11 +0200 Stephan Bosch <stephan@rename-it.nl> (c03182c9)
+
+ Forgot to add manpage preprocessor and includes to distribution.
+
+
+M doc/man/Makefile.am
+
+2010-08-26 00:35:19 +0200 Stephan Bosch <stephan@rename-it.nl> (38837035)
+
+ Removed spurious old stdio.h (top) includes; these cause compile issues on
+ specific systems.
+
+
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve.h
+M src/lib-sievestorage/sieve-storage-list.h
+
+2010-08-23 19:26:12 +0200 Stephan Bosch <stephan@rename-it.nl> (1cbc2470)
+
+ Fixed Sieve script name checking to properly handle length issues and added
+ 0x00ff as invalid character.
+
+
+M src/lib-sieve/sieve-script.c
+M src/managesieve/cmd-putscript.c
+
+2010-08-23 19:21:04 +0200 Stephan Bosch <stephan@rename-it.nl> (97d88d9c)
+
+ ManageSieve: fixed putscript error in previous commit.
+
+
+M src/managesieve/cmd-putscript.c
+
+2010-08-23 18:50:58 +0200 Stephan Bosch <stephan@rename-it.nl> (b71803b2)
+
+ Enforced ManageSieve protocol syntax better with some of the commands; some
+ commands still allowed spurious extra arguments.
+
+
+M TODO
+M src/managesieve/cmd-capability.c
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-havespace.c
+M src/managesieve/cmd-listscripts.c
+M src/managesieve/cmd-logout.c
+M src/managesieve/cmd-noop.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/cmd-setactive.c
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+
+2010-08-23 09:10:11 +0200 Stephan Bosch <stephan@rename-it.nl> (f1e6fa4b)
+
+ Cleaned up manpages and fixed various issues (patch by Pascal Volk). - No
+ longer track the generated pigeonhole.7 - Some makes don't like the 'handy'
+ notation that was used. - Deleted trailing spaces - Escaped some dashes -
+ Replaced some ' and " by \(aq and \(dq - Sorted manual pages in section 'See
+ also' (first list all man pages from the lowest section (1) alphabetical
+ sorted, then the next section …)
+
+
+M .hgignore
+M doc/man/Makefile.am
+D doc/man/pigeonhole.7
+M doc/man/pigeonhole.7.in
+M doc/man/sieve-dump.1.in
+M doc/man/sieve-test.1.in
+M doc/man/sievec.1.in
+
+2010-08-23 00:27:08 +0200 Stephan Bosch <stephan@rename-it.nl> (a8e800d9)
+
+ Update man pages to match style and content of Dovecot man pages.
+
+
+M .hgignore
+M TODO
+M doc/man/Makefile.am
+A doc/man/pigeonhole.7
+A doc/man/pigeonhole.7.in
+A doc/man/reporting-bugs.inc
+A doc/man/sed.sh
+D doc/man/sieve-dump.1
+A doc/man/sieve-dump.1.in
+R097 doc/man/sieve-filter.1 doc/man/sieve-filter.1.in
+D doc/man/sieve-test.1
+A doc/man/sieve-test.1.in
+D doc/man/sievec.1
+A doc/man/sievec.1.in
+
+2010-08-21 23:23:35 +0200 Stephan Bosch <stephan@rename-it.nl> (26d81be2)
+
+ Added manpage redirection for sieved.
+
+
+A doc/man/sieved.1
+
+2010-08-21 21:51:00 +0200 Stephan Bosch <stephan@rename-it.nl> (94482626)
+
+ Renamed sieved tool to sieve-dump.
+
+
+M .hgignore
+M NEWS
+M README
+M doc/man/Makefile.am
+R086 doc/man/sieved.1 doc/man/sieve-dump.1
+M doc/man/sieve-filter.1
+M doc/man/sieve-test.1
+M doc/man/sievec.1
+M src/sieve-tools/Makefile.am
+R090 src/sieve-tools/sieved.c src/sieve-tools/sieve-dump.c
+
+2010-08-19 18:04:22 +0200 Stephan Bosch <stephan@rename-it.nl> (7358244b)
+
+ Updated documentation for upcoming release.
+
+
+M INSTALL
+M NEWS
+M README
+
+2010-08-17 19:03:36 +0200 Stephan Bosch <stephan@rename-it.nl> (cf7807b2)
+
+ Added quota and limit configuration to config file examples.
+
+
+M doc/example-config/conf.d/20-managesieve.conf
+M doc/example-config/conf.d/90-sieve.conf
+
+2010-08-17 18:48:30 +0200 Stephan Bosch <stephan@rename-it.nl> (72d4847e)
+
+ Removed superfluous text from AUTHORS file.
+
+
+M AUTHORS
+
+2010-08-17 18:32:23 +0200 Stephan Bosch <stephan@rename-it.nl> (0e9baf99)
+
+ Moved finishing the ereject extension off the pre-v0.2.0 TODO list.
+
+
+M TODO
+
+2010-08-17 18:30:17 +0200 Stephan Bosch <stephan@rename-it.nl> (62c79e4b)
+
+ Updated documentation.
+
+
+M INSTALL
+M README
+
+2010-08-17 17:46:12 +0200 Stephan Bosch <stephan@rename-it.nl> (ad9b5110)
+
+ ManageSieve: changed default IMPLEMENTATION capability to 'Dovecot
+ Pigeonhole'.
+
+
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve/managesieve-settings.c
+
+2010-08-17 17:20:58 +0200 Stephan Bosch <stephan@rename-it.nl> (1bc1e36c)
+
+ Renamed 'Dovecot Sieve' to 'Pigeonhole' in source file copyright headers.
+
+
+M src/lib-managesieve/managesieve-parser.c
+M src/lib-managesieve/managesieve-parser.h
+M src/lib-managesieve/managesieve-quote.c
+M src/lib-managesieve/managesieve-quote.h
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/cmp-i-ascii-casemap.c
+M src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/date/ext-date.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify-limits.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/ext-environment-common.h
+M src/lib-sieve/plugins/environment/ext-environment.c
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-limits.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/notify/ext-notify-limits.h
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/rfc2822.c
+M src/lib-sieve/rfc2822.h
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary-code.c
+M src/lib-sieve/sieve-binary-debug.c
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-plugins.c
+M src/lib-sieve/sieve-plugins.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-stringlist.c
+M src/lib-sieve/sieve-stringlist.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/lib-sieve/tst-truefalse.c
+M src/lib-sievestorage/sieve-storage-list.c
+M src/lib-sievestorage/sieve-storage-list.h
+M src/lib-sievestorage/sieve-storage-private.h
+M src/lib-sievestorage/sieve-storage-quota.c
+M src/lib-sievestorage/sieve-storage-quota.h
+M src/lib-sievestorage/sieve-storage-save.c
+M src/lib-sievestorage/sieve-storage-save.h
+M src/lib-sievestorage/sieve-storage-script.c
+M src/lib-sievestorage/sieve-storage-script.h
+M src/lib-sievestorage/sieve-storage.c
+M src/lib-sievestorage/sieve-storage.h
+M src/managesieve-login/client-authenticate.c
+M src/managesieve-login/client-authenticate.h
+M src/managesieve-login/client.c
+M src/managesieve-login/client.h
+M src/managesieve-login/managesieve-login-settings-plugin.c
+M src/managesieve-login/managesieve-login-settings-plugin.h
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve-login/managesieve-login-settings.h
+M src/managesieve-login/managesieve-proxy.c
+M src/managesieve-login/managesieve-proxy.h
+M src/managesieve/cmd-capability.c
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-havespace.c
+M src/managesieve/cmd-listscripts.c
+M src/managesieve/cmd-logout.c
+M src/managesieve/cmd-noop.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/cmd-setactive.c
+M src/managesieve/main.c
+M src/managesieve/managesieve-capabilities.c
+M src/managesieve/managesieve-capabilities.h
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+M src/managesieve/managesieve-commands.c
+M src/managesieve/managesieve-commands.h
+M src/managesieve/managesieve-common.h
+M src/managesieve/managesieve-quota.c
+M src/managesieve/managesieve-quota.h
+M src/managesieve/managesieve-settings.c
+M src/managesieve/managesieve-settings.h
+M src/plugins/lda-sieve/lda-sieve-log.c
+M src/plugins/lda-sieve/lda-sieve-log.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.h
+M src/sieve-tools/debug/cmd-debug-print.c
+M src/sieve-tools/debug/ext-debug-common.h
+M src/sieve-tools/debug/ext-debug.c
+M src/sieve-tools/debug/sieve-ext-debug.h
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/sieve-tools/sieved.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result-print.c
+M src/testsuite/cmd-test-result-reset.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-arguments.c
+M src/testsuite/testsuite-arguments.h
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-binary.h
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-log.h
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-script.h
+M src/testsuite/testsuite-settings.c
+M src/testsuite/testsuite-settings.h
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/testsuite-substitutions.h
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-result.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2010-08-14 00:57:32 +0200 Stephan Bosch <stephan@rename-it.nl> (4d24bfe0)
+
+ Fixed source file header comments.
+
+
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-stringlist.c
+M src/lib-sieve/sieve-stringlist.h
+
+2010-08-14 00:42:24 +0200 Stephan Bosch <stephan@rename-it.nl> (dddd17ee)
+
+ Testsuite: added a few test for the regex extension.
+
+
+M tests/extensions/regex/basic.svtest
+
+2010-08-14 00:25:44 +0200 Stephan Bosch <stephan@rename-it.nl> (448b8065)
+
+ Fixed Valgrind error.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+
+2010-08-14 00:06:22 +0200 Stephan Bosch <stephan@rename-it.nl> (8f90c58c)
+
+ Improved runtime error handing.
+
+ - Changed operand read functions to prove exec status return codes in stead
+ of boolean.
+ - Restructured optional-operand, stringlist and string-match APIs to provide
+ execution status (error code) upon failure.
+ - Corruption errors are only produced when the binary is actually corrupt.
+ Normal failures should never cause a recompile attempt anymore.
+ - Simplified optional-operand API.
+ - Cleaned up test command implementations that use the string-match API.
+
+M TODO
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-stringlist.c
+M src/lib-sieve/sieve-stringlist.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+M src/managesieve/cmd-putscript.c
+M src/sieve-tools/debug/cmd-debug-print.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2010-08-12 16:28:02 +0200 Stephan Bosch <stephan@rename-it.nl> (4022e5af)
+
+ Produce a nicer error message when trying to load with non-lda/lmtp binary
+ (patch by Timo Sirainen).
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2010-08-12 14:43:04 +0200 Stephan Bosch <stephan@rename-it.nl> (a9dc6837)
+
+ Regex match: fixed segfault at deinitialization.
+
+
+M src/lib-sieve/plugins/regex/mcht-regex.c
+
+2010-08-12 14:41:46 +0200 Stephan Bosch <stephan@rename-it.nl> (471e91b2)
+
+ Updated TODO
+
+
+M TODO
+
+2010-08-12 00:56:33 +0200 Stephan Bosch <stephan@rename-it.nl> (4f8c4dbc)
+
+ Fixed compile on Solaris 10 with SunStudio 12.1 (patch by Willi Burmeister).
+
+
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-stringlist.h
+
+2010-08-11 18:20:41 +0200 Stephan Bosch <stephan@rename-it.nl> (6f0cf81a)
+
+ Improved and simplified file error handling
+
+ - Administrators now get properly notified about uncompiled global scripts
+ and the inability of the sieve plugin to store global binaries.
+ - Improved binary load/save error handling and fixed a few smal bugs.
+ - Simplified ManageSieve error handling.
+
+M TODO
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/sieve-binary-file.c
+M src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sievestorage/Makefile.am
+D src/lib-sievestorage/sieve-storage-error.h
+M src/lib-sievestorage/sieve-storage-list.c
+M src/lib-sievestorage/sieve-storage-private.h
+M src/lib-sievestorage/sieve-storage-quota.c
+M src/lib-sievestorage/sieve-storage-save.c
+M src/lib-sievestorage/sieve-storage-script.c
+M src/lib-sievestorage/sieve-storage-script.h
+M src/lib-sievestorage/sieve-storage.c
+M src/lib-sievestorage/sieve-storage.h
+M src/managesieve/cmd-deletescript.c
+M src/managesieve/cmd-getscript.c
+M src/managesieve/cmd-putscript.c
+M src/managesieve/cmd-renamescript.c
+M src/managesieve/cmd-setactive.c
+M src/managesieve/managesieve-client.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/sieve-tools/sieved.c
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite.c
+
+2010-08-11 18:10:46 +0200 Stephan Bosch <stephan@rename-it.nl> (36ef3b4d)
+
+ ManageSieve/Sieve storag: fixed error handling of PUTSCRIPT commmand; save
+ commit errors would not make the command fail.
+
+
+M src/lib-sievestorage/sieve-storage-save.c
+
+2010-08-11 17:25:48 +0200 Stephan Bosch <stephan@rename-it.nl> (56ef5958)
+
+ Fixed segfault occuring when loaded binary block turns out to be corrupt.
+
+
+M src/lib-sieve/sieve-interpreter.c
+
+2010-08-11 16:55:11 +0200 Stephan Bosch <stephan@rename-it.nl> (285f36d4)
+
+ Multiscript: fixed duplicate implicit keep caused by erroneous execution
+ state update.
+
+
+M src/lib-sieve/sieve.c
+
+2010-08-11 14:27:09 +0200 Stephan Bosch <stephan@rename-it.nl> (9bbcb23f)
+
+ Prevent assertion failure due to currupt binary string representation
+ (missing \0).
+
+
+M src/lib-sieve/sieve-binary-code.c
+
+2010-08-11 13:52:59 +0200 Stephan Bosch <stephan@rename-it.nl> (27dc72bd)
+
+ LDA Sieve plugin: fixed sieve_global_path setting; it was not recognized.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2010-08-08 11:21:04 +0200 Stephan Bosch <stephan@rename-it.nl> (9b0b57fa)
+
+ Fixed segfault in tools and testsuite occuring when no username can be
+ determined.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+
+2010-08-06 16:17:31 +0200 Stephan Bosch <stephan@rename-it.nl> (555a749a)
+
+ ManageSieve: fixed SASL negotiation; mechanisms that need a roundtrip were
+ broken.
+
+
+M src/managesieve-login/client-authenticate.c
+
+2010-08-04 18:19:59 +0200 Stephan Bosch <stephan@rename-it.nl> (9cb8afb7)
+
+ Fixed compiler warnings in tst-size.c
+
+
+M src/lib-sieve/tst-size.c
+
+2010-08-03 18:58:36 +0200 Stephan Bosch <stephan@rename-it.nl> (5551ad02)
+
+ Improved runtime trace debugging towards something more intuitively
+ readable.
+
+
+M TODO
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-stringlist.h
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-size.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result-print.c
+M src/testsuite/cmd-test-result-reset.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-script.h
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-result.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2010-08-03 18:30:14 +0200 Stephan Bosch <stephan@rename-it.nl> (41c3ef6a)
+
+ Imap4flags: fixed bug in setflag command; when parameter was a stringlist,
+ only the last item was actually set.
+
+
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M tests/extensions/imap4flags/basic.svtest
+
+2010-08-03 15:58:36 +0200 Stephan Bosch <stephan@rename-it.nl> (2faf5329)
+
+ Fixed bug in error handling of store action.
+
+
+M src/lib-sieve/sieve-actions.c
+M tests/execute/errors.svtest
+A tests/execute/errors/fileinto-invalid-name.sieve
+
+2010-08-03 12:29:46 +0200 Stephan Bosch <stephan@rename-it.nl> (2c57e513)
+
+ Testsuite: prevented warning messages from showing up by default.
+
+
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-log.h
+M src/testsuite/testsuite.c
+
+2010-08-03 03:10:22 +0200 Stephan Bosch <stephan@rename-it.nl> (00194238)
+
+ Testsuite: fixed segfault problem.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+
+2010-08-02 16:14:10 +0200 Stephan Bosch <stephan@rename-it.nl> (a5ceb7e0)
+
+ Testsuite: added missing test case for the size test.
+
+
+M Makefile.am
+A tests/size.svtest
+
+2010-08-02 15:19:05 +0200 Stephan Bosch <stephan@rename-it.nl> (1245cf0c)
+
+ Testsuite: minor cleanups.
+
+
+M src/testsuite/testsuite.c
+
+2010-08-02 15:18:51 +0200 Stephan Bosch <stephan@rename-it.nl> (fd849304)
+
+ Sieve tools: don't try to close stdout.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+
+2010-08-02 15:00:00 +0200 Stephan Bosch <stephan@rename-it.nl> (1753c207)
+
+ Sieve-test tool: accidentally disabled -d option.
+
+
+M src/sieve-tools/sieve-test.c
+
+2010-08-02 14:59:06 +0200 Stephan Bosch <stephan@rename-it.nl> (025065a9)
+
+ Improved byte code encoding implementation of integers and offsets.
+
+
+M src/lib-sieve/sieve-binary-code.c
+
+2010-07-30 19:03:30 +0200 Stephan Bosch <stephan@rename-it.nl> (b9be8e38)
+
+ Sieve binary: now using better defined integer types for byte-coded data
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/sieve-binary-code.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-interpreter.c
+M src/testsuite/cmd-test-fail.c
+
+2010-07-30 17:07:56 +0200 Stephan Bosch <stephan@rename-it.nl> (9e63fecd)
+
+ Updated TODO.
+
+
+M TODO
+
+2010-07-30 16:32:19 +0200 Stephan Bosch <stephan@rename-it.nl> (a7849cad)
+
+ Variables extension: fixed :length set modifier to recognize utf8 characters
+ in stead of octets.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M tests/extensions/variables/modifiers.svtest
+
+2010-07-30 14:53:14 +0200 Stephan Bosch <stephan@rename-it.nl> (169dd8d4)
+
+ Implemented generic string list interface and simplified matching API.
+
+
+M TODO
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+A src/lib-sieve/sieve-stringlist.c
+A src/lib-sieve/sieve-stringlist.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-log.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result.c
+M tests/extensions/envelope.svtest
+
+2010-07-30 09:16:13 +0200 Stephan Bosch <stephan@rename-it.nl> (67db254e)
+
+ Fixed sieve-test not to start in trace mode by default.
+
+
+M src/sieve-tools/sieve-test.c
+
+2010-07-29 11:53:26 +0200 Stephan Bosch <stephan@rename-it.nl> (a83e91bc)
+
+ Updated extension status information.
+
+
+M README
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/date/ext-date.c
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/environment/ext-environment.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/sieve-tools/debug/ext-debug.c
+M src/testsuite/ext-testsuite.c
+
+2010-07-28 15:01:26 +0200 Stephan Bosch <stephan@rename-it.nl> (d7f19d39)
+
+ ManageSieve: fixed deinitialization problem in dump-capability plugin.
+
+
+M src/managesieve-login/managesieve-login-settings-plugin.c
+
+2010-07-21 21:15:12 +0200 Stephan Bosch <stephan@rename-it.nl> (9f99c4ca)
+
+ ManageSieve: fixed dump-capability hang.
+
+
+M src/managesieve-login/managesieve-login-settings-plugin.c
+
+2010-07-21 17:43:16 +0200 Stephan Bosch <stephan@rename-it.nl> (a5f3a29c)
+
+ Further developed new runtime trace debugging; test suite is also now
+ included.
+
+
+M Makefile.am
+M doc/man/sieve-test.1
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/sieve-tools/sieve-test.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test.c
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-execute.c
+
+2010-07-20 13:29:46 +0200 Stephan Bosch <stephan@rename-it.nl> (23ac203c)
+
+ Makefile fix: rhel5 still has too old automake that doesn't define
+ $builddir.
+
+
+M src/lib-sieve/Makefile.am
+M src/sieve-tools/Makefile.am
+
+2010-07-17 19:57:25 +0200 Stephan Bosch <stephan@rename-it.nl> (a539090e)
+
+ First changes towards making `make distcheck' work.
+
+
+M Makefile.am
+M configure.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/body/Makefile.am
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile.am
+M src/lib-sieve/plugins/copy/Makefile.am
+M src/lib-sieve/plugins/date/Makefile.am
+M src/lib-sieve/plugins/enotify/Makefile.am
+M src/lib-sieve/plugins/enotify/mailto/Makefile.am
+M src/lib-sieve/plugins/environment/Makefile.am
+M src/lib-sieve/plugins/imap4flags/Makefile.am
+M src/lib-sieve/plugins/include/Makefile.am
+M src/lib-sieve/plugins/mailbox/Makefile.am
+M src/lib-sieve/plugins/notify/Makefile.am
+M src/lib-sieve/plugins/regex/Makefile.am
+M src/lib-sieve/plugins/relational/Makefile.am
+M src/lib-sieve/plugins/spamvirustest/Makefile.am
+M src/lib-sieve/plugins/subaddress/Makefile.am
+M src/lib-sieve/plugins/vacation/Makefile.am
+M src/lib-sieve/plugins/variables/Makefile.am
+M src/managesieve-login/Makefile.am
+M src/managesieve/Makefile.am
+M src/plugins/lda-sieve/Makefile.am
+M src/sieve-tools/Makefile.am
+M src/testsuite/Makefile.am
+
+2010-07-17 12:11:58 +0200 Stephan Bosch <stephan@rename-it.nl> (4dcd092f)
+
+ Improved runtime trace debugging output for core Sieve language.
+
+
+M TODO
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-runtime-trace.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/sieve-tools/sieve-test.c
+
+2010-07-16 21:31:46 +0200 Stephan Bosch <stephan@rename-it.nl> (d7b179a8)
+
+ Adjusted to Dovecot LDA API changes; implicitly fixing segfault (patch by
+ Timo Sirainen).
+
+
+M src/lib-sieve/sieve-actions.c
+
+2010-07-16 21:11:25 +0200 Stephan Bosch <stephan@rename-it.nl> (21a326f0)
+
+ Updated dovecot.m4.
+
+
+M m4/dovecot.m4
+
+2010-07-16 10:02:20 +0200 Stephan Bosch <stephan@rename-it.nl> (3806f628)
+
+ Removed unused code that caused compile failure due to Dovecot API change.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/managesieve/managesieve-capabilities.c
+
+2010-07-15 00:45:37 +0200 Stephan Bosch <stephan@rename-it.nl> (969dec8b)
+
+ Implemented simple runtime trace of string value matching.
+
+
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-match.c
+
+2010-07-14 23:55:21 +0200 Stephan Bosch <stephan@rename-it.nl> (7da1cc6e)
+
+ Adjusted string matching API tu use runtime environment.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-result.c
+
+2010-07-13 20:08:24 +0200 Stephan Bosch <stephan@rename-it.nl> (8582f2af)
+
+ Updated ManageSieve specification.
+
+
+R057 doc/rfc/draft-ietf-sieve-managesieve-09.txt doc/rfc/managesieve.rfc5804.txt
+
+2010-07-13 18:15:44 +0200 Stephan Bosch <stephan@rename-it.nl> (a86e0043)
+
+ Updated TODO list.
+
+
+M TODO
+
+2010-07-13 18:09:32 +0200 Stephan Bosch <stephan@rename-it.nl> (e7d75edc)
+
+ Testsuite: inappropriately removed initialization of dummy MAIL environment.
+
+
+M src/testsuite/testsuite.c
+
+2010-07-11 17:06:31 +0200 Stephan Bosch <stephan@rename-it.nl> (ed9c1bae)
+
+ Sieve tools: added support for extended trace debugging and updated man
+ pages.
+
+
+M doc/man/sieve-filter.1
+M doc/man/sieve-test.1
+M doc/man/sievec.1
+M doc/man/sieved.1
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-runtime-trace.h
+M src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-types.h
+M src/sieve-tools/sieve-test.c
+M src/testsuite/cmd-test.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite.c
+
+2010-07-11 12:40:00 +0200 Stephan Bosch <stephan@rename-it.nl> (68a275be)
+
+ Updated documentation: Sieve tools are now using Dovecot configuration by
+ default.
+
+
+M TODO
+M doc/man/sieve-filter.1
+M doc/man/sieve-test.1
+M doc/man/sievec.1
+M doc/man/sieved.1
+
+2010-07-10 18:53:40 +0200 Stephan Bosch <stephan@rename-it.nl> (3322ab5a)
+
+ Sieve-tools: use 'mail' as module name in stead of the name of the command.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+
+2010-07-10 18:06:28 +0200 Stephan Bosch <stephan@rename-it.nl> (421de7a5)
+
+ Sieve-tools: was using wrong mail_user variable for settings acquisition.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+
+2010-07-10 13:21:14 +0200 Stephan Bosch <stephan@rename-it.nl> (002cae7e)
+
+ Increased initial pool sieve for Sieve logfile and varexpand error handlers.
+
+
+M src/lib-sieve/sieve-error.c
+
+2010-07-10 13:14:53 +0200 Stephan Bosch <stephan@rename-it.nl> (4702320d)
+
+ Restructured and cleaned up the Sieve tools and the Sieve tool library.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/sieve-tools/sieved.c
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-settings.c
+M src/testsuite/testsuite-settings.h
+M src/testsuite/testsuite.c
+
+2010-07-08 00:47:26 +0200 Stephan Bosch <stephan@rename-it.nl> (ed89527b)
+
+ Testsuite: improved test for fileinto with non-existent mailbox.
+
+
+M tests/execute/errors.svtest
+
+2010-07-08 00:06:42 +0200 Stephan Bosch <stephan@rename-it.nl> (6b0c7726)
+
+ Fixed assertion failure in the keep/fileinto store actions and added
+ testsuite item.
+
+
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/sieve-actions.c
+M tests/execute/errors.svtest
+A tests/execute/errors/fileinto.sieve
+
+2010-07-05 17:18:23 +0200 Stephan Bosch <stephan@rename-it.nl> (b2be9010)
+
+ Fixed small discrepancy in example configuration.
+
+
+M doc/example-config/conf.d/90-sieve.conf
+
+2010-07-05 16:45:12 +0200 Stephan Bosch <stephan@rename-it.nl> (156f4a7c)
+
+ ManageSieve: fixed fd leak caused by DUMP_CAPABILITY execution.
+
+
+M src/managesieve/main.c
+
+2010-07-05 14:32:17 +0200 Stephan Bosch <stephan@rename-it.nl> (33e76f80)
+
+ Updated documentation.
+
+
+M INSTALL
+M doc/example-config/conf.d/20-managesieve.conf
+
+2010-07-04 01:22:40 +0200 Stephan Bosch <stephan@rename-it.nl> (89b9268f)
+
+ Sieve-tools: removed KEEP_CONFIG_OPEN service flag.
+
+
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/sieve-tools/sieved.c
+
+2010-07-04 00:22:09 +0200 Stephan Bosch <stephan@rename-it.nl> (98e994ca)
+
+ Fixed compiler warning caused by previous change.
+
+
+M src/managesieve/managesieve-capabilities.c
+
+2010-07-03 23:32:28 +0200 Stephan Bosch <stephan@rename-it.nl> (91f29b82)
+
+ Moved parsing of sieve_extensions setting to sieve engine initialization.
+
+
+M src/lib-sieve/sieve-extensions.c
+M src/managesieve/managesieve-capabilities.c
+M src/managesieve/managesieve-client.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2010-07-03 22:49:21 +0200 Stephan Bosch <stephan@rename-it.nl> (ca60b0da)
+
+ Fixed compiler warnings in previous change.
+
+
+M src/sieve-tools/sievec.c
+M src/sieve-tools/sieved.c
+
+2010-07-03 22:44:49 +0200 Stephan Bosch <stephan@rename-it.nl> (cc9d3eb3)
+
+ Sieve-Tools: fully use Dovecot service and settings API.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/sieve-script.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/sieve-tools/sieved.c
+M src/testsuite/testsuite.c
+
+2010-07-03 19:07:52 +0200 Stephan Bosch <stephan@rename-it.nl> (80dd4bc6)
+
+ Updated TODO list.
+
+
+M TODO
+
+2010-07-03 18:32:09 +0200 Stephan Bosch <stephan@rename-it.nl> (4f487241)
+
+ ManageSieve: reactivated reporting of NOTIFY capability.
+
+
+M src/managesieve-login/client.c
+M src/managesieve-login/managesieve-login-settings.c
+
+2010-07-03 18:07:30 +0200 Stephan Bosch <stephan@rename-it.nl> (88b1d0dc)
+
+ ManageSieve: removed service/managesieve-login from dynamically assinged
+ settings.
+
+
+M src/managesieve-login/managesieve-login-settings-plugin.c
+
+2010-07-03 17:37:49 +0200 Stephan Bosch <stephan@rename-it.nl> (fda83b69)
+
+ ManageSieve: added -k to dump capability invocation of managesieve binary.
+
+
+M src/managesieve-login/managesieve-login-settings-plugin.c
+
+2010-07-03 17:04:06 +0200 Stephan Bosch <stephan@rename-it.nl> (ca5e55cb)
+
+ ManageSieve: check for DUMP_CAPABILITY=1 before executing dump capability to
+ prevent infinite recursion.
+
+
+M src/managesieve-login/managesieve-login-settings-plugin.c
+
+2010-07-03 16:27:33 +0200 Stephan Bosch <stephan@rename-it.nl> (3451298d)
+
+ ManageSieve: forgot to include settings in doveconf plugin.
+
+
+M src/managesieve-login/Makefile.am
+M src/managesieve-login/managesieve-login-settings-plugin.c
+
+2010-07-03 15:09:57 +0200 Stephan Bosch <stephan@rename-it.nl> (7a383a98)
+
+ ManageSieve: doveconf went berserk with last change.
+
+
+M src/managesieve-login/managesieve-login-settings-plugin.c
+
+2010-07-03 14:21:38 +0200 Stephan Bosch <stephan@rename-it.nl> (03c8bfc7)
+
+ ManageSieve: enabled dynamic capability inference.
+
+
+M m4/dovecot.m4
+M src/managesieve-login/Makefile.am
+A src/managesieve-login/managesieve-login-settings-plugin.c
+A src/managesieve-login/managesieve-login-settings-plugin.h
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve-login/managesieve-login-settings.h
+
+2010-07-01 11:16:45 +0200 Stephan Bosch <stephan@rename-it.nl> (21b4e147)
+
+ managesieve: Added an assert to client_connected().
+
+
+M src/managesieve/main.c
+
+2010-06-28 14:35:07 +0200 Stephan Bosch <stephan@rename-it.nl> (19d0fd3f)
+
+ Updated TODO list.
+
+
+M TODO
+
+2010-06-26 00:51:33 +0200 Stephan Bosch <stephan@rename-it.nl> (f1659db4)
+
+ ManageSieve: forgot to change login unix socket name.
+
+
+M src/managesieve/managesieve-settings.c
+
+2010-06-26 00:27:34 +0200 Stephan Bosch <stephan@rename-it.nl> (8fc82ea2)
+
+ Use new LDA deliver save API (patch by Timo Sirainen).
+
+
+M src/lib-sieve/sieve-actions.c
+
+2010-06-26 00:05:02 +0200 Stephan Bosch <stephan@rename-it.nl> (b5fe7d25)
+
+ ManageSieve: small patch to service settings.
+
+
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve/managesieve-settings.c
+
+2010-06-24 17:04:41 +0200 Stephan Bosch <stephan@rename-it.nl> (93034e37)
+
+ ManageSieve: forgot to change protocol name to 'sieve' in login_binary
+ struct.
+
+
+M src/managesieve-login/client.c
+
+2010-06-19 17:36:18 +0200 Stephan Bosch <stephan@rename-it.nl> (b36c68bf)
+
+ Variables extension: added proper trace support.
+
+
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/sieve-runtime-trace.h
+
+2010-06-19 13:07:10 +0200 Stephan Bosch <stephan@rename-it.nl> (14e91a15)
+
+ Cleaned up mail storage-related code (modified patch by Timo Sirainen).
+
+
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-types.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite.c
+
+2010-06-19 11:32:00 +0200 Stephan Bosch <stephan@rename-it.nl> (744b97ab)
+
+ Updated documentation.
+
+
+M INSTALL
+M doc/example-config/conf.d/90-sieve.conf
+
+2010-06-19 11:00:37 +0200 Stephan Bosch <stephan@rename-it.nl> (008b424c)
+
+ Fixed error handling of failed mailbox creation (patch by Timo Sirainen).
+
+
+M src/lib-sieve/sieve-actions.c
+
+2010-06-19 10:57:23 +0200 Stephan Bosch <stephan@rename-it.nl> (fe8fbf1f)
+
+ Changed ManageSieve protocol name to 'sieve'.
+
+
+M doc/example-config/conf.d/20-managesieve.conf
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve/managesieve-settings.c
+
+2010-05-30 09:39:19 +0200 Stephan Bosch <stephan@rename-it.nl> (d853dbb0)
+
+ Forgot an active TODO item on the list.
+
+
+M TODO
+
+2010-05-30 09:37:28 +0200 Stephan Bosch <stephan@rename-it.nl> (d6df4c06)
+
+ Updated to changes in Dovecot service API.
+
+
+M src/managesieve/main.c
+
+2010-05-19 17:04:42 +0200 Stephan Bosch <stephan@rename-it.nl> (e0afdfc6)
+
+ Include extension: accidentally committed debug printf.
+
+
+M src/lib-sieve/plugins/include/ext-include-binary.c
+
+2010-05-19 17:00:44 +0200 Stephan Bosch <stephan@rename-it.nl> (d6babbda)
+
+ Explicitly set AC_CONFIG_AUX_DIR to prevent issues when compiling Pigeonhole
+ in a sub-directory of the Dovecot tree.
+
+
+M configure.in
+
+2010-05-16 18:12:56 +0200 Stephan Bosch <stephan@rename-it.nl> (d609cc7c)
+
+ Updated TODO.
+
+
+M TODO
+
+2010-05-16 14:43:43 +0200 Stephan Bosch <stephan@rename-it.nl> (c0c60be5)
+
+ Restructured and cleaned up trace debugging and optional operand fetching.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+A src/lib-sieve/sieve-runtime-trace.c
+A src/lib-sieve/sieve-runtime-trace.h
+A src/lib-sieve/sieve-runtime.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+M src/sieve-tools/debug/cmd-debug-print.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-result.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2010-05-14 22:57:06 +0200 Stephan Bosch <stephan@rename-it.nl> (60f2c55f)
+
+ Added debug mode to the Sieve engine.
+
+
+M doc/man/sieve-test.1
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/managesieve/managesieve-capabilities.c
+M src/managesieve/managesieve-client.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/sieve-tools/sieved.c
+M src/testsuite/testsuite.c
+
+2010-05-14 14:35:19 +0200 Stephan Bosch <stephan@rename-it.nl> (9ca03cee)
+
+ Testsuite: forgot to add -P plugin parameter to executable.
+
+
+M src/testsuite/testsuite.c
+
+2010-05-14 14:03:09 +0200 Stephan Bosch <stephan@rename-it.nl> (282701a9)
+
+ Updated TODO.
+
+
+M TODO
+
+2010-05-14 14:02:48 +0200 Stephan Bosch <stephan@rename-it.nl> (7e6c0d49)
+
+ Made action commands use new lineinfo facility.
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+
+2010-05-14 13:08:14 +0200 Stephan Bosch <stephan@rename-it.nl> (691db805)
+
+ Restructured binary implementation and added lineinfo debug blocks to the
+ binary.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+A src/lib-sieve/sieve-binary-code.c
+A src/lib-sieve/sieve-binary-debug.c
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+A src/lib-sieve/sieve-binary-file.c
+A src/lib-sieve/sieve-binary-private.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+M src/lib-sieve/tst-truefalse.c
+M src/sieve-tools/debug/cmd-debug-print.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-config.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result-print.c
+M src/testsuite/cmd-test-result-reset.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-result.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2010-05-14 12:34:59 +0200 Stephan Bosch <stephan@rename-it.nl> (278b251d)
+
+ Lexer: made sure source code positions are recorded at start of token.
+
+
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-parser.c
+
+2010-05-14 12:16:52 +0200 Stephan Bosch <stephan@rename-it.nl> (93c1be50)
+
+ Spamtest/Virustest extensions: forgot to call extension unload handler.
+
+
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+
+2010-05-14 11:25:25 +0200 Stephan Bosch <stephan@rename-it.nl> (8706f5b1)
+
+ Fixed potential deinitialization problem in interpreter.
+
+
+M src/lib-sieve/sieve-interpreter.c
+
+2010-05-14 11:23:55 +0200 Stephan Bosch <stephan@rename-it.nl> (a915ee9b)
+
+ Fixed potential memory leak in generator.
+
+
+M src/lib-sieve/sieve-generator.c
+
+2010-05-14 12:37:39 +0200 Stephan Bosch <stephan@rename-it.nl> (1169fe8a)
+
+ Updated TODO.
+
+
+M TODO
+
+2010-05-05 21:11:18 +0200 Stephan Bosch <stephan@rename-it.nl> (ba056452)
+
+ ManageSieve: disabled dynamic capability determination for now.
+
+
+M src/managesieve-login/managesieve-login-settings.c
+
+2010-05-05 20:21:50 +0200 Stephan Bosch <stephan@rename-it.nl> (b969c57e)
+
+ ManageSieve: dump_capability: simplified settings acquisition.
+
+
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve/managesieve-capabilities.c
+
+2010-05-05 19:39:26 +0200 Stephan Bosch <stephan@rename-it.nl> (137551e9)
+
+ ManageSieve: implemented user-independent capability dumping (untested).
+
+
+M src/managesieve/Makefile.am
+M src/managesieve/main.c
+A src/managesieve/managesieve-capabilities.c
+A src/managesieve/managesieve-capabilities.h
+M src/managesieve/managesieve-client.c
+
+2010-05-05 17:28:13 +0200 Stephan Bosch <stephan@rename-it.nl> (164c2465)
+
+ ManageSieve: don't use i_fatal() in doveconf plugin.
+
+
+M src/managesieve-login/managesieve-login-settings.c
+
+2010-05-05 16:56:12 +0200 Stephan Bosch <stephan@rename-it.nl> (fc08f6b6)
+
+ ManageSieve: fixed segfault bug in doveconf plugin and fixed compiler
+ warnings.
+
+
+M src/managesieve-login/managesieve-login-settings.c
+
+2010-05-05 16:04:31 +0200 Stephan Bosch <stephan@rename-it.nl> (28f2359f)
+
+ ManageSieve: implemented dynamic capability determination at login.
+
+
+M src/managesieve-login/Makefile.am
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve-login/managesieve-login-settings.h
+M src/managesieve/main.c
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+
+2010-05-05 15:43:54 +0200 Stephan Bosch <stephan@rename-it.nl> (f5df2f66)
+
+ ManageSieve: fixed compile error in previous change.
+
+
+M src/managesieve/managesieve-client.c
+
+2010-05-05 15:42:44 +0200 Stephan Bosch <stephan@rename-it.nl> (1403221c)
+
+ ManageSieve: forgot to initialize Sieve extensions.
+
+
+M src/managesieve/managesieve-client.c
+
+2010-05-03 20:02:55 +0200 Stephan Bosch <stephan@rename-it.nl> (eab3d162)
+
+ Made command line tools return proper exit status upon failure.
+
+
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/sieve-tools/sieved.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite.c
+
+2010-05-02 10:23:14 +0200 Stephan Bosch <stephan@rename-it.nl> (5fe046cf)
+
+ managesieve: updated to changes in Dovecot (IMAP/POP3).
+
+
+M src/managesieve/main.c
+M src/managesieve/managesieve-client.c
+M src/managesieve/managesieve-client.h
+M src/managesieve/managesieve-commands.c
+
+2010-05-02 09:30:37 +0200 Stephan Bosch <stephan@rename-it.nl> (1298095c)
+
+ sieve-storage: made auto-creation code match implementation of maildir
+ storage from Dovecot.
+
+
+M src/lib-sievestorage/sieve-storage-private.h
+M src/lib-sievestorage/sieve-storage.c
+
+2010-05-02 09:29:54 +0200 Stephan Bosch <stephan@rename-it.nl> (327f0c28)
+
+ managesieve: changed static IMAP error massage in main.c to ManageSieve
+ protocol.
+
+
+M src/managesieve/main.c
+
+2010-04-29 00:34:31 +0200 Stephan Bosch <stephan@rename-it.nl> (16e692f0)
+
+ Compiler warning fix.
+
+
+M src/managesieve/main.c
+
+2010-04-28 16:31:03 +0200 Stephan Bosch <stephan@rename-it.nl> (e5306691)
+
+ Changed result execution logging to use a var_expand_table created by liblda
+ to avoid code duplication (patch by Timo Sirainen).
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/sieve-result.c
+M src/managesieve/Makefile.am
+M src/sieve-tools/Makefile.am
+M src/testsuite/Makefile.am
+
+2010-04-28 16:26:14 +0200 Stephan Bosch <stephan@rename-it.nl> (7c8fc2b1)
+
+ Updated dovecot.m4.
+
+
+M m4/dovecot.m4
+
+2010-04-28 16:21:57 +0200 Stephan Bosch <stephan@rename-it.nl> (11b7e197)
+
+ Made var_expand_table argument of sieve_varexpand_ehandler_create const
+ (patch by Timo Sirainen).
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+
+2010-04-28 16:16:50 +0200 Stephan Bosch <stephan@rename-it.nl> (d0555478)
+
+ Fix CFLAGS and LIBS defines (patch by Timo Sirainen).
+
+
+M configure.in
+
+2010-04-20 01:16:18 +0200 Stephan Bosch <stephan@rename-it.nl> (3478bfb5)
+
+ Testsuite: avoid using existing e-mail addresses and domains in tests.
+
+
+M tests/address.svtest
+M tests/comparators/core.svtest
+M tests/compile/errors/address-part.sieve
+M tests/compile/errors/envelope.sieve
+M tests/compile/errors/match-type.sieve
+M tests/compile/errors/out-address.sieve
+M tests/compile/errors/unsupported.sieve
+M tests/compile/recover/commands-semicolon.sieve
+M tests/compile/redirect.sieve
+M tests/compile/warnings/invalid-headers.sieve
+M tests/control-structures.svtest
+M tests/deprecated/notify/basic.svtest
+M tests/deprecated/notify/denotify.svtest
+M tests/deprecated/notify/errors/options.sieve
+M tests/deprecated/notify/execute/duplicates.sieve
+M tests/deprecated/notify/mailto.svtest
+M tests/execute/actions.svtest
+M tests/execute/actions/fileinto.sieve
+M tests/execute/actions/redirect.sieve
+M tests/execute/mailstore.svtest
+M tests/execute/smtp.svtest
+M tests/exists.svtest
+M tests/extensions/body/basic.svtest
+M tests/extensions/body/match-values.svtest
+M tests/extensions/date/basic.svtest
+M tests/extensions/date/date-parts.svtest
+M tests/extensions/date/zones.svtest
+M tests/extensions/enotify/basic.svtest
+M tests/extensions/enotify/errors/from-mailto.sieve
+M tests/extensions/enotify/errors/options.sieve
+M tests/extensions/enotify/errors/uri-mailto.sieve
+M tests/extensions/enotify/errors/uri.sieve
+M tests/extensions/enotify/execute/duplicates.sieve
+M tests/extensions/enotify/mailto.svtest
+M tests/extensions/enotify/notify_method_capability.svtest
+M tests/extensions/enotify/valid_notify_method.svtest
+M tests/extensions/envelope.svtest
+M tests/extensions/include/execute.svtest
+M tests/extensions/include/included/rfc-ex1-mailing_lists.sieve
+M tests/extensions/mailbox/execute.svtest
+M tests/extensions/regex/basic.svtest
+M tests/extensions/regex/errors/compile.sieve
+M tests/extensions/regex/match-values.svtest
+M tests/extensions/reject/execute.svtest
+M tests/extensions/reject/execute/basic.sieve
+M tests/extensions/reject/smtp.svtest
+M tests/extensions/relational/basic.svtest
+M tests/extensions/spamvirustest/spamtest.svtest
+M tests/extensions/spamvirustest/spamtestplus.svtest
+M tests/extensions/spamvirustest/virustest.svtest
+M tests/extensions/subaddress/basic.svtest
+M tests/extensions/subaddress/config.svtest
+M tests/extensions/subaddress/rfc.svtest
+M tests/extensions/vacation/execute/action.sieve
+M tests/extensions/vacation/execute/no-handle.sieve
+M tests/extensions/vacation/message.svtest
+M tests/extensions/vacation/smtp.svtest
+M tests/extensions/vacation/utf-8.svtest
+M tests/extensions/variables/basic.svtest
+M tests/extensions/variables/match.svtest
+M tests/header.svtest
+M tests/match-types/contains.svtest
+M tests/match-types/is.svtest
+M tests/match-types/matches.svtest
+M tests/multiscript/basic.svtest
+M tests/multiscript/conflicts.svtest
+M tests/multiscript/notify.sieve
+M tests/testsuite.svtest
+
+2010-04-19 23:38:54 +0200 Stephan Bosch <stephan@rename-it.nl> (76f0f1f4)
+
+ Vacation extension: from address of reply is now by default equal to
+ whatever known recipient alias matched the headers of the message.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M tests/extensions/vacation/smtp.svtest
+
+2010-04-19 14:18:17 +0200 Stephan Bosch <stephan@rename-it.nl> (0b1d5db1)
+
+ Removed --install flag from ACLOCAL_AMFLAGS; RHEL uses automake 1.9 and
+ won't compile.
+
+
+M Makefile.am
+
+2010-04-14 23:38:44 +0200 Stephan Bosch <stephan@rename-it.nl> (1f8e87b4)
+
+ Added --with-docs configure option.
+
+
+M Makefile.am
+M configure.in
+M doc/Makefile.am
+
+2010-04-14 22:05:15 +0200 Stephan Bosch <stephan@rename-it.nl> (35729065)
+
+ Started using dovecot.m4 for linking against Dovecot (patch by Timo
+ Sirainen).
+
+
+M .hgignore
+M Makefile.am
+M configure.in
+A m4/dovecot.m4
+
+2010-04-14 21:48:01 +0200 Stephan Bosch <stephan@rename-it.nl> (2559a3c0)
+
+ Switched to cleaner way to create a raw storage.
+
+
+M src/lib-sieve-tool/mail-raw.c
+
+2010-04-14 21:45:54 +0200 Stephan Bosch <stephan@rename-it.nl> (2395912f)
+
+ ManageSieve: adjusted to Dovecot login API change.
+
+
+M src/managesieve-login/client.c
+
+2010-04-14 17:34:30 +0200 Stephan Bosch <stephan@rename-it.nl> (fdce3523)
+
+ Started using tar-ustar for release packaging to prevent crossing path
+ length limits.
+
+
+M configure.in
+
+2010-04-14 17:06:33 +0200 Stephan Bosch <stephan@rename-it.nl> (237d092b)
+
+ Assigned temporary version number to avoid confusion with releases for
+ Dovecot v1.2.
+
+
+M configure.in
+
+2010-04-14 16:47:05 +0200 Stephan Bosch <stephan@rename-it.nl> (d4031724)
+
+ Changed config file names to match Dovecot numeric config file names.
+
+
+R100 doc/example-config/conf.d/managesieve.conf doc/example-config/conf.d/20-managesieve.conf
+R100 doc/example-config/conf.d/sieve.conf doc/example-config/conf.d/90-sieve.conf
+M doc/example-config/conf.d/Makefile.am
+
+2010-04-08 09:13:54 +0200 Stephan Bosch <stephan@rename-it.nl> (ecab4fa1)
+
+ Mailbox extension: fixed memory leak in the mailboxexists test.
+
+
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+
+2010-04-01 09:41:37 +0200 Stephan Bosch <stephan@rename-it.nl> (408ec9fa)
+
+ ManageSieve: adjusted to changes in service API; added login failure
+ handler.
+
+
+M src/managesieve/main.c
+
+2010-03-28 18:16:21 +0200 Stephan Bosch <stephan@rename-it.nl> (f7ed659b)
+
+ Updated TODO list.
+
+
+M TODO
+
+2010-03-28 18:39:56 +0200 Stephan Bosch <stephan@rename-it.nl> (7928627d)
+
+ Spamtest and virustest: added documentation to the distribution.
+
+
+M doc/Makefile.am
+
+2010-03-28 18:21:55 +0200 Stephan Bosch <stephan@rename-it.nl> (ad9206ec)
+
+ Spamtest and virustest extensions: added documentation.
+
+
+M INSTALL
+A doc/spamtest-virustest.txt
+
+2010-03-14 17:13:49 +0100 Stephan Bosch <stephan@rename-it.nl> (6a9ad97d)
+
+ Spamtest and virustest extensions: changed setting names.
+
+
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M tests/extensions/spamvirustest/spamtest.svtest
+M tests/extensions/spamvirustest/spamtestplus.svtest
+
+2010-03-14 12:34:13 +0100 Stephan Bosch <stephan@rename-it.nl> (b98e08cc)
+
+ Spamtest and virustest extensions: now not available by default.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2010-03-14 12:19:51 +0100 Stephan Bosch <stephan@rename-it.nl> (9f020ec3)
+
+ Spamtest and virustest extensions: discarded whitespace at beginning of
+ regexp and added syntax testsuite tests.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+A tests/extensions/spamvirustest/errors.svtest
+A tests/extensions/spamvirustest/errors/syntax-errors.sieve
+M tests/extensions/spamvirustest/spamtest.svtest
+
+2010-03-27 19:11:09 +0100 Stephan Bosch <stephan@rename-it.nl> (fc22abee)
+
+ Changed ManageSieve client limit to match IMAP/POP3.
+
+
+M src/managesieve/managesieve-settings.c
+
+2010-03-08 18:48:54 +0100 Stephan Bosch <stephan@rename-it.nl> (beea3d8f)
+
+ Fixed memset argument mixup in enotify extension.
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+
+2010-02-28 21:50:04 +0100 Stephan Bosch <stephan@rename-it.nl> (e80633e4)
+
+ Fixed ManageSieve login crash at startup (patch by Timo Sirainen).
+
+
+M src/managesieve-login/client.c
+
+2010-02-13 12:48:32 +0100 Stephan Bosch <stephan@rename-it.nl> (140dca54)
+
+ ManageSieve: changed default login user to '' substitution.
+
+
+M src/managesieve-login/managesieve-login-settings.c
+
+2010-02-13 11:48:02 +0100 Stephan Bosch <stephan@rename-it.nl> (52750c58)
+
+ Adjusted to changes in Dovecot mailbox API.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/sieve-actions.c
+M src/sieve-tools/sieve-filter.c
+M src/testsuite/testsuite-mailstore.c
+
+2010-02-10 17:15:41 +0100 Stephan Bosch <stephan@rename-it.nl> (cb2c985d)
+
+ Adjusted to changes in dovecot-config (patch by Timo Sirainen).
+
+
+M configure.in
+M src/lib-sieve-tool/Makefile.am
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/enotify/mailto/Makefile.am
+M src/managesieve-login/Makefile.am
+M src/managesieve/Makefile.am
+M src/plugins/lda-sieve/Makefile.am
+M src/sieve-tools/Makefile.am
+M src/testsuite/Makefile.am
+
+2010-02-07 17:45:55 +0100 Stephan Bosch <stephan@rename-it.nl> (b02faa15)
+
+ Adjusted to change in Dovecot Storage API.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/sieve-actions.c
+M src/testsuite/testsuite-mailstore.c
+
+2010-01-31 17:06:24 +0100 Stephan Bosch <stephan@rename-it.nl> (c5b63ec5)
+
+ Let configure automatically infer path to installed Dovecot and don't rely
+ on installed libtool .la files anymore (patch by Timo Sirainen).
+
+
+M configure.in
+M src/managesieve-login/Makefile.am
+M src/managesieve/Makefile.am
+M src/sieve-tools/Makefile.am
+M src/testsuite/Makefile.am
+
+2010-01-31 16:12:46 +0100 Stephan Bosch <stephan@rename-it.nl> (c6805328)
+
+ Deprecated notify extension: fixed compiler warning.
+
+
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+
+2010-01-31 16:31:49 +0100 Stephan Bosch <stephan@rename-it.nl> (909e7e83)
+
+ Simplified package configuration with respect to linking against Dovecot
+ (patch by Timo Sirainen).
+
+
+M configure.in
+M src/lib-sieve/plugins/enotify/mailto/Makefile.am
+M src/sieve-tools/Makefile.am
+M src/testsuite/Makefile.am
+
+2010-01-31 12:37:46 +0100 Stephan Bosch <stephan@rename-it.nl> (7cb7df25)
+
+ Restructured and optimized lexical scanner.
+
+
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-parser.c
+
+2010-01-28 22:15:00 +0100 Stephan Bosch <stephan@rename-it.nl> (bb309113)
+
+ Fixed spelling of 'existent' in various testsuite scripts.
+
+
+M tests/exists.svtest
+M tests/extensions/body/basic.svtest
+M tests/extensions/environment/rfc.svtest
+M tests/extensions/include/errors/generic.sieve
+M tests/extensions/subaddress/basic.svtest
+M tests/header.svtest
+
+2010-01-28 22:09:07 +0100 Stephan Bosch <stephan@rename-it.nl> (29bbcb7b)
+
+ Fixed copy-paste error in previous change regarding inet_listener.
+
+
+M src/managesieve-login/managesieve-login-settings.c
+
+2010-01-28 11:00:41 +0100 Stephan Bosch <stephan@rename-it.nl> (c64b646f)
+
+ Added default inet_listener for managesieve-login.
+
+
+M doc/example-config/conf.d/managesieve.conf
+M src/managesieve-login/managesieve-login-settings.c
+
+2010-01-28 09:38:36 +0100 Stephan Bosch <stephan@rename-it.nl> (d10c177e)
+
+ Reverted ManageSieve protocol name back from 'sieve' to 'managesieve'.
+
+
+M INSTALL
+M doc/example-config/conf.d/managesieve.conf
+M src/managesieve-login/client.c
+M src/managesieve-login/managesieve-login-settings.c
+M src/managesieve/main.c
+M src/managesieve/managesieve-settings.c
+
+2010-01-27 19:59:34 +0100 Stephan Bosch <stephan@rename-it.nl> (701339a0)
+
+ Deprecated imapflags extension: added proper tests to the test suite.
+
+
+M Makefile.am
+R100 tests/extensions/imap4flags/errors.svtest tests/deprecated/imapflags/errors.svtest
+R100 tests/extensions/imap4flags/errors/imapflags.sieve tests/deprecated/imapflags/errors/imapflags.sieve
+A tests/deprecated/imapflags/execute.svtest
+A tests/deprecated/imapflags/execute/flags.sieve
+A tests/deprecated/imapflags/execute/mark.sieve
+D tests/extensions/imap4flags/execute/imapflags.sieve
+
+2010-01-27 19:02:12 +0100 Stephan Bosch <stephan@rename-it.nl> (7de56e84)
+
+ Deprecated imapflags extension: fixed implicit assignment of flags.
+
+
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+
+2010-01-28 09:20:28 +0100 Stephan Bosch <stephan@rename-it.nl> (86149cdf)
+
+ Updated TODO list.
+
+
+M TODO
+
+2010-01-25 21:03:46 +0100 Stephan Bosch <stephan@rename-it.nl> (c4f8cf92)
+
+ Omitted 'extern' in two declarations of global variables in header files,
+ causing compile failures on certain systems.
+
+
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+
+2010-01-25 18:42:30 +0100 Stephan Bosch <stephan@rename-it.nl> (600adae0)
+
+ Added spamtest and virustest extensions to the default build.
+
+
+M Makefile.am
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M src/lib-sieve/sieve-extensions.c
+
+2010-01-25 18:22:07 +0100 Stephan Bosch <stephan@rename-it.nl> (ee4e1271)
+
+ Spamtest and virustest extensions: finished configuration.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M tests/extensions/spamvirustest/spamtest.svtest
+A tests/extensions/spamvirustest/spamtestplus.svtest
+A tests/extensions/spamvirustest/virustest.svtest
+
+2010-01-25 10:02:36 +0100 Stephan Bosch <stephan@rename-it.nl> (47796d77)
+
+ Enotify extension: removed location from action log messages.
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+
+2010-01-25 01:57:54 +0100 Stephan Bosch <stephan@rename-it.nl> (b08dc028)
+
+ Fixed newly introduced compiler warning.
+
+
+M src/lib-sieve/sieve-settings.c
+
+2010-01-24 22:01:07 +0100 Stephan Bosch <stephan@rename-it.nl> (160ac4c0)
+
+ Added boolean settings parser.
+
+
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+
+2010-01-24 11:15:38 +0100 Stephan Bosch <stephan@rename-it.nl> (ba49af27)
+
+ Testsuite: added a few more tests for the i;ascii-numeric comparator (patch
+ by Julian Cowley).
+
+
+M tests/extensions/relational/comparators.svtest
+
+2010-01-23 00:37:21 +0100 Stephan Bosch <stephan@rename-it.nl> (766303db)
+
+ Fixed bugs in parser recovery and added corresponding tests in the test
+ suite.
+
+
+M Makefile.am
+M src/lib-sieve/sieve-parser.c
+A tests/compile/recover.svtest
+A tests/compile/recover/commands-endblock.sieve
+A tests/compile/recover/commands-semicolon.sieve
+A tests/compile/recover/tests-endcomma.sieve
+
+2010-01-22 15:28:07 +0100 Stephan Bosch <stephan@rename-it.nl> (e93a5fee)
+
+ Enotify extension: set default importance to normal as required.
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M tests/extensions/enotify/mailto.svtest
+
+2010-01-23 00:45:11 +0100 Stephan Bosch <stephan@rename-it.nl> (a0b5c2fc)
+
+ Fixed '-' in man pages.
+
+
+M doc/man/sieve-filter.1
+M doc/man/sieve-test.1
+M doc/man/sievec.1
+M doc/man/sieved.1
+
+2010-01-19 16:32:48 +0100 Stephan Bosch <stephan@rename-it.nl> (f94b9f6a)
+
+ Fixed small bug in the i;ascii-numeric comparator and added extensive
+ relational tests to the testsuite.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+A tests/extensions/relational/comparators.svtest
+
+2010-01-19 10:12:00 +0100 Stephan Bosch <stephan@rename-it.nl> (a1117a11)
+
+ Fixed spelling mistake in error messages.
+
+
+M src/lib-sieve/sieve-message.c
+
+2010-01-19 10:11:42 +0100 Stephan Bosch <stephan@rename-it.nl> (b55dc255)
+
+ Envelope paths with only a mailbox part are now allowed.
+
+
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address.c
+M tests/extensions/envelope.svtest
+
+2010-01-18 01:35:16 +0100 Stephan Bosch <stephan@rename-it.nl> (21e7f1e0)
+
+ Added TODO list item.
+
+
+M TODO
+
+2010-01-18 00:51:46 +0100 Stephan Bosch <stephan@rename-it.nl> (7d12af2a)
+
+ Fixed small bug in plugin support.
+
+
+M src/lib-sieve/sieve-plugins.c
+
+2010-01-15 22:56:52 +0100 Stephan Bosch <stephan@rename-it.nl> (11338868)
+
+ Slightly improved error messages during binary save.
+
+
+M src/lib-sieve/sieve-binary.c
+
+2010-01-15 18:36:43 +0100 Stephan Bosch <stephan@rename-it.nl> (b6f0a3a1)
+
+ Error handling: now only the topmost parent error handler will copy to the
+ master log.
+
+
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+
+2010-01-15 16:58:53 +0100 Stephan Bosch <stephan@rename-it.nl> (ce498a00)
+
+ Fixed compile problem in previous change.
+
+
+M src/lib-sieve/sieve-error.c
+
+2010-01-15 16:46:45 +0100 Stephan Bosch <stephan@rename-it.nl> (2b9f718c)
+
+ Made child error handlers inherit master_log status from parent.
+
+
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+
+2010-01-14 10:21:34 +0100 Stephan Bosch <stephan@rename-it.nl> (37aab05f)
+
+ Fixed bug in the logging of action results. The new varexpand error handler
+ was not properly tested.
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-result.c
+
+2010-01-13 21:07:26 +0100 Stephan Bosch <stephan@rename-it.nl> (d369700c)
+
+ Merged Sieve and ManageSieve for Dovecot v2.0 into one Pigeonhole package.
+
+
+M .hgignore
+M AUTHORS
+M INSTALL
+M Makefile.am
+M NEWS
+M README
+M TODO
+M configure.in
+M doc/example-config/conf.d/Makefile.am
+A doc/example-config/conf.d/managesieve.conf
+M doc/man/sieve-filter.1
+M doc/man/sieve-test.1
+M doc/man/sievec.1
+M doc/man/sieved.1
+A doc/rfc/draft-ietf-sieve-managesieve-09.txt
+D dsieve-config.h.in
+A pigeonhole-config.h.in
+M src/Makefile.am
+A src/lib-managesieve/Makefile.am
+A src/lib-managesieve/managesieve-parser.c
+A src/lib-managesieve/managesieve-parser.h
+A src/lib-managesieve/managesieve-quote.c
+A src/lib-managesieve/managesieve-quote.h
+M src/lib-sieve-tool/Makefile.am
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-plugins.c
+A src/lib-sievestorage/Makefile.am
+A src/lib-sievestorage/sieve-storage-error.h
+A src/lib-sievestorage/sieve-storage-list.c
+A src/lib-sievestorage/sieve-storage-list.h
+A src/lib-sievestorage/sieve-storage-private.h
+A src/lib-sievestorage/sieve-storage-quota.c
+A src/lib-sievestorage/sieve-storage-quota.h
+A src/lib-sievestorage/sieve-storage-save.c
+A src/lib-sievestorage/sieve-storage-save.h
+A src/lib-sievestorage/sieve-storage-script.c
+A src/lib-sievestorage/sieve-storage-script.h
+A src/lib-sievestorage/sieve-storage.c
+A src/lib-sievestorage/sieve-storage.h
+A src/managesieve-login/Makefile.am
+A src/managesieve-login/client-authenticate.c
+A src/managesieve-login/client-authenticate.h
+A src/managesieve-login/client.c
+A src/managesieve-login/client.h
+A src/managesieve-login/managesieve-login-settings.c
+A src/managesieve-login/managesieve-login-settings.h
+A src/managesieve-login/managesieve-proxy.c
+A src/managesieve-login/managesieve-proxy.h
+A src/managesieve/Makefile.am
+A src/managesieve/cmd-capability.c
+A src/managesieve/cmd-deletescript.c
+A src/managesieve/cmd-getscript.c
+A src/managesieve/cmd-havespace.c
+A src/managesieve/cmd-listscripts.c
+A src/managesieve/cmd-logout.c
+A src/managesieve/cmd-noop.c
+A src/managesieve/cmd-putscript.c
+A src/managesieve/cmd-renamescript.c
+A src/managesieve/cmd-setactive.c
+A src/managesieve/main.c
+A src/managesieve/managesieve-client.c
+A src/managesieve/managesieve-client.h
+A src/managesieve/managesieve-commands.c
+A src/managesieve/managesieve-commands.h
+A src/managesieve/managesieve-common.h
+A src/managesieve/managesieve-quota.c
+A src/managesieve/managesieve-quota.h
+A src/managesieve/managesieve-settings.c
+A src/managesieve/managesieve-settings.h
+M src/sieve-tools/Makefile.am
+M src/testsuite/Makefile.am
+M tests/extensions/environment/basic.svtest
+
+2010-01-13 09:16:04 +0100 Stephan Bosch <stephan@rename-it.nl> (0649733b)
+
+ Fixed off-by-one bug in extension reloading.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2010-01-13 08:57:10 +0100 Stephan Bosch <stephan@rename-it.nl> (d08c5d27)
+
+ Improved extension unloading.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2010-01-13 01:16:20 +0100 Stephan Bosch <stephan@rename-it.nl> (81942d5b)
+
+ Fixed segfault bug caused by previous change, occuring when a plugin is
+ unloaded.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2010-01-13 09:02:53 +0100 Stephan Bosch <stephan@rename-it.nl> (ba8fb890)
+
+ Improved various aspects of the plugin-related extension API.
+
+
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-plugins.c
+M src/lib-sieve/sieve.c
+
+2010-01-12 16:55:12 +0100 Stephan Bosch <stephan@rename-it.nl> (fd7746d6)
+
+ Forgot to add dsieve-config.h to installed headers.
+
+
+M Makefile.am
+
+2010-01-12 11:47:18 +0100 Stephan Bosch <stephan@rename-it.nl> (43e1519c)
+
+ Variables extension: removed public dependency on ext-variables-limits.h.
+
+
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2010-01-11 19:03:37 +0100 Stephan Bosch <stephan@rename-it.nl> (e756f4c5)
+
+ Fixed a few memleaks caused by previous changes in error handling.
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/sieve-result.c
+
+2010-01-10 03:00:42 +0100 Stephan Bosch <stephan@rename-it.nl> (0ed8aab4)
+
+ Enotify extension: mailto method: fixed small uri validation glitch.
+
+
+M src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+
+2010-01-10 02:39:19 +0100 Stephan Bosch <stephan@rename-it.nl> (3c42f48c)
+
+ Enotify extension: cleaned up notify method API (part is in previous
+ change).
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+
+2010-01-12 00:23:08 +0100 Stephan Bosch <stephan@rename-it.nl> (d2ef2e6d)
+
+ Reworked error handler implementation and cleaned up enotify extension
+ implementation.
+
+
+M configure.in
+M src/lib-sieve/plugins/enotify/Makefile.am
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+A src/lib-sieve/plugins/enotify/mailto/Makefile.am
+A src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+A src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
+A src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2010-01-08 12:18:20 +0100 Stephan Bosch <stephan@rename-it.nl> (f32da22a)
+
+ Vacation extension: subject is now only MIME-encoded when it contains 8bit
+ characters.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M tests/extensions/vacation/utf-8.svtest
+
+2010-01-08 01:27:00 +0100 Stephan Bosch <stephan@rename-it.nl> (fa3e26d0)
+
+ Fixed compile problems on systems with older autotools installed.
+
+
+M configure.in
+
+2010-01-07 23:57:16 +0100 Stephan Bosch <stephan@rename-it.nl> (ea83a088)
+
+ Sieve-filter: made tool compile with Dovecot v2.0 (not working).
+
+
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+
+2010-01-07 23:04:23 +0100 Stephan Bosch <stephan@rename-it.nl> (0b46c130)
+
+ Plugin support: added -P parameter to all sieve tools and enabled dict
+ support.
+
+
+M configure.in
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/plugins/lda-sieve/Makefile.am
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/sieve-tools/sieved.c
+M src/testsuite/testsuite.c
+
+2010-01-07 22:26:29 +0100 Stephan Bosch <stephan@rename-it.nl> (0127ed29)
+
+ Plugin support: fixed unloading problem.
+
+
+M src/lib-sieve/sieve.c
+
+2010-01-07 02:56:11 +0100 Stephan Bosch <stephan@rename-it.nl> (f7a3ced7)
+
+ Variables extension: finished namespaces support.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2010-01-03 23:25:25 +0100 Stephan Bosch <stephan@rename-it.nl> (d1c9ee43)
+
+ Spamtest extension: added yesno-type header matching tests to the testsuite.
+
+
+M tests/extensions/spamvirustest/spamtest.svtest
+
+2010-01-03 23:22:25 +0100 Stephan Bosch <stephan@rename-it.nl> (4583ec5f)
+
+ Spamtest extension: fixed small bug in yesno-type spam header matching.
+
+
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+
+2010-01-03 23:08:21 +0100 Stephan Bosch <stephan@rename-it.nl> (bbf50be8)
+
+ Testsuite: fixed panic occuring when unsetting an unknown configuration
+ setting.
+
+
+M src/testsuite/testsuite-settings.c
+
+2010-01-03 22:29:04 +0100 Stephan Bosch <stephan@rename-it.nl> (0cb3a96d)
+
+ Spamtest extension: added tests for strlen values to the testsuite.
+
+
+M tests/extensions/spamvirustest/spamtest.svtest
+
+2010-01-03 22:28:33 +0100 Stephan Bosch <stephan@rename-it.nl> (d0f9c920)
+
+ Spamtest extension: fixed bugs in extension unloading and in strlen value
+ extraction.
+
+
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+
+2010-01-03 22:24:33 +0100 Stephan Bosch <stephan@rename-it.nl> (ae507162)
+
+ Testsuite: added support for removed settings.
+
+
+M src/testsuite/cmd-test-config.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-settings.c
+M src/testsuite/testsuite-settings.h
+
+2010-01-03 21:41:45 +0100 Stephan Bosch <stephan@rename-it.nl> (7b36cdba)
+
+ Spamtest extension: added various value tests to the testsuite.
+
+
+M tests/extensions/spamvirustest/spamtest.svtest
+
+2010-01-03 21:41:21 +0100 Stephan Bosch <stephan@rename-it.nl> (446ee0cb)
+
+ Spamtest extension: fixed result when over the maximum score.
+
+
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+
+2010-01-03 19:26:23 +0100 Stephan Bosch <stephan@rename-it.nl> (46c23635)
+
+ Spamtest extension: further developed configuration loading and testing.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
+A tests/extensions/spamvirustest/spamtest.svtest
+
+2010-01-03 17:09:01 +0100 Stephan Bosch <stephan@rename-it.nl> (a9078e5b)
+
+ Testsuite: enabled warnings in testsuite error handler.
+
+
+M src/testsuite/testsuite-log.c
+
+2010-01-07 22:22:08 +0100 Stephan Bosch <stephan@rename-it.nl> (f6930c08)
+
+ Testsuite: added command line parameter for copying errors to stderr.
+
+
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-log.h
+M src/testsuite/testsuite.c
+
+2010-01-03 13:33:45 +0100 Stephan Bosch <stephan@rename-it.nl> (648cb538)
+
+ Testsuite: added support for changing and testing an extension's
+ configuration.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/testsuite/Makefile.am
+A src/testsuite/cmd-test-config.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-common.h
+A tests/extensions/subaddress/config.svtest
+
+2010-01-02 19:06:03 +0100 Stephan Bosch <stephan@rename-it.nl> (13bca4d5)
+
+ Adjusted tag parameter validation API.
+
+
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/testsuite/cmd-test-message.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-result.c
+
+2010-01-02 16:16:24 +0100 Stephan Bosch <stephan@rename-it.nl> (14a3169a)
+
+ Restructured handling of Dovecot includes in makefiles.
+
+
+M configure.in
+M src/lib-sieve-tool/Makefile.am
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/body/Makefile.am
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile.am
+M src/lib-sieve/plugins/copy/Makefile.am
+M src/lib-sieve/plugins/date/Makefile.am
+M src/lib-sieve/plugins/enotify/Makefile.am
+M src/lib-sieve/plugins/environment/Makefile.am
+M src/lib-sieve/plugins/imap4flags/Makefile.am
+M src/lib-sieve/plugins/include/Makefile.am
+M src/lib-sieve/plugins/mailbox/Makefile.am
+M src/lib-sieve/plugins/notify/Makefile.am
+M src/lib-sieve/plugins/regex/Makefile.am
+M src/lib-sieve/plugins/relational/Makefile.am
+M src/lib-sieve/plugins/spamvirustest/Makefile.am
+M src/lib-sieve/plugins/subaddress/Makefile.am
+M src/lib-sieve/plugins/vacation/Makefile.am
+M src/lib-sieve/plugins/variables/Makefile.am
+M src/plugins/lda-sieve/Makefile.am
+M src/sieve-tools/Makefile.am
+M src/sieve-tools/debug/Makefile.am
+M src/testsuite/Makefile.am
+
+2010-01-02 13:56:11 +0100 Stephan Bosch <stephan@rename-it.nl> (2e1a06c2)
+
+ Forgot to update two makefiles.
+
+
+M src/lib-sieve/plugins/imap4flags/Makefile.am
+M src/sieve-tools/debug/Makefile.am
+
+2010-01-02 13:50:52 +0100 Stephan Bosch <stephan@rename-it.nl> (d3c2735b)
+
+ Set default dovecot directory to ../dovecot-2.0
+
+
+M configure.in
+
+2010-01-02 13:39:38 +0100 Stephan Bosch <stephan@rename-it.nl> (f07845fc)
+
+ Added support for fully compiling against installed Dovecot libraries.
+
+
+M Makefile.am
+M configure.in
+M src/Makefile.am
+M src/lib-sieve-tool/Makefile.am
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/body/Makefile.am
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile.am
+M src/lib-sieve/plugins/copy/Makefile.am
+M src/lib-sieve/plugins/date/Makefile.am
+M src/lib-sieve/plugins/enotify/Makefile.am
+M src/lib-sieve/plugins/environment/Makefile.am
+M src/lib-sieve/plugins/include/Makefile.am
+M src/lib-sieve/plugins/mailbox/Makefile.am
+M src/lib-sieve/plugins/notify/Makefile.am
+M src/lib-sieve/plugins/regex/Makefile.am
+M src/lib-sieve/plugins/relational/Makefile.am
+M src/lib-sieve/plugins/spamvirustest/Makefile.am
+M src/lib-sieve/plugins/subaddress/Makefile.am
+M src/lib-sieve/plugins/vacation/Makefile.am
+M src/lib-sieve/plugins/variables/Makefile.am
+M src/plugins/lda-sieve/Makefile.am
+M src/sieve-tools/Makefile.am
+M src/testsuite/Makefile.am
+
+2010-01-02 02:56:45 +0100 Stephan Bosch <stephan@rename-it.nl> (5309cd46)
+
+ Updated all copyright messages to the new year.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/cmp-i-ascii-casemap.c
+M src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/date/ext-date.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify-limits.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/ext-environment-common.h
+M src/lib-sieve/plugins/environment/ext-environment.c
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-limits.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/notify/ext-notify-limits.h
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
+M src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+M src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+M src/lib-sieve/plugins/variables/ext-variables-namespaces.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/rfc2822.c
+M src/lib-sieve/rfc2822.h
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-plugins.c
+M src/lib-sieve/sieve-plugins.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve-smtp.c
+M src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/lib-sieve/tst-truefalse.c
+M src/plugins/lda-sieve/lda-sieve-log.c
+M src/plugins/lda-sieve/lda-sieve-log.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.h
+M src/sieve-tools/debug/cmd-debug-print.c
+M src/sieve-tools/debug/ext-debug-common.h
+M src/sieve-tools/debug/ext-debug.c
+M src/sieve-tools/debug/sieve-ext-debug.h
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/sieve-tools/sieved.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result-print.c
+M src/testsuite/cmd-test-result-reset.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-arguments.c
+M src/testsuite/testsuite-arguments.h
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-binary.h
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-log.h
+M src/testsuite/testsuite-mailstore.c
+M src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-script.h
+M src/testsuite/testsuite-settings.c
+M src/testsuite/testsuite-settings.h
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/testsuite-substitutions.h
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-result.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2010-01-01 14:22:13 +0100 Stephan Bosch <stephan@rename-it.nl> (75647f79)
+
+ Plugin support: removed ability to have duplicate plugins in different
+ directories.
+
+
+M src/lib-sieve/sieve-plugins.c
+
+2009-12-31 20:02:40 +0100 Stephan Bosch <stephan@rename-it.nl> (04ac8bb0)
+
+ Fixed yet another small textual error in the README file.
+
+
+M README
+
+2009-12-31 19:57:09 +0100 Stephan Bosch <stephan@rename-it.nl> (6cc56d70)
+
+ Fixed small textual error in the README file.
+
+
+M README
+
+2009-12-31 19:47:01 +0100 Stephan Bosch <stephan@rename-it.nl> (02ea6992)
+
+ Further developed support for Sieve engine plugins.
+
+
+M src/lib-sieve/sieve-plugins.c
+
+2009-12-31 18:10:46 +0100 Stephan Bosch <stephan@rename-it.nl> (65920901)
+
+ Further developed support for Sieve engine plugins.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/sieve-common.h
+A src/lib-sieve/sieve-plugins.c
+A src/lib-sieve/sieve-plugins.h
+M src/lib-sieve/sieve.c
+
+2009-12-31 18:42:36 +0100 Stephan Bosch <stephan@rename-it.nl> (8c92c80e)
+
+ dded preliminary support for plugins.
+
+
+M configure.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/sieve.c
+
+2009-12-31 04:40:09 +0100 Stephan Bosch <stephan@rename-it.nl> (31e40815)
+
+ Enotify extension: adjusted notify method registration API.
+
+
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+
+2009-12-30 04:44:27 +0100 Stephan Bosch <stephan@rename-it.nl> (b05726fc)
+
+ Imap4flags extension: added tests to verify removeflag behavior.
+
+
+M tests/extensions/imap4flags/basic.svtest
+
+2009-12-30 04:43:02 +0100 Stephan Bosch <stephan@rename-it.nl> (dbcfa2e7)
+
+ Imap4flags extension: fixed bug in removeflag: removing a single flag failed
+ due to off-by-one error.
+
+
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+
+2009-12-30 04:40:04 +0100 Stephan Bosch <stephan@rename-it.nl> (59cf3adf)
+
+ Imap4flags extension: added tests for flag string management.
+
+
+M Makefile.am
+A tests/extensions/imap4flags/flagstring.svtest
+
+2009-12-31 18:16:03 +0100 Stephan Bosch <stephan@rename-it.nl> (cc4f65c4)
+
+ Updated README file.
+
+
+M README
+
+2009-12-30 00:16:30 +0100 Stephan Bosch <stephan@rename-it.nl> (2a541e80)
+
+ Built basic implementation of the spamtest, spamtestplus and virustest
+ extensions (unfinished).
+
+
+M TODO
+M configure.in
+A doc/rfc/spamvirustest.rfc5235.txt
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/spamvirustest/Makefile.am
+A src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
+A src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
+A src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
+A src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+
+2009-12-29 23:49:27 +0100 Stephan Bosch <stephan@rename-it.nl> (e9e6a82c)
+
+ Improved EACCES error messages for stat() and lstat() syscalls.
+
+
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-12-29 23:24:15 +0100 Stephan Bosch <stephan@rename-it.nl> (9c8a25f0)
+
+ Renamed sieve_callbacks to sieve_environment and restructured settings API.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/testsuite/testsuite.c
+
+2009-12-29 23:14:28 +0100 Stephan Bosch <stephan@rename-it.nl> (641e1c06)
+
+ Deprecated notify extension: implemented denotify command.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+A tests/deprecated/notify/denotify.svtest
+
+2009-12-26 20:39:53 +0100 Stephan Bosch <stephan@rename-it.nl> (99b455a0)
+
+ Moved size limit enforcement to script compilation (lexer) in stead of
+ during opening the stream.
+
+
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+
+2009-12-25 15:30:51 +0100 Stephan Bosch <stephan@rename-it.nl> (23147756)
+
+ LDA Sieve plugin: log messages now include the lda session ID; forgot to set
+ master error handler.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-12-25 14:38:27 +0100 Stephan Bosch <stephan@rename-it.nl> (cf5516e0)
+
+ Previous commit was broken.
+
+
+M src/plugins/lda-sieve/Makefile.am
+M src/plugins/lda-sieve/lda-sieve-log.c
+
+2009-12-25 14:11:38 +0100 Stephan Bosch <stephan@rename-it.nl> (e72e053d)
+
+ Added LDA session ID to log messages produced by the Sieve plugin.
+
+
+A src/plugins/lda-sieve/lda-sieve-log.c
+A src/plugins/lda-sieve/lda-sieve-log.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-12-25 10:38:30 +0100 Stephan Bosch <stephan@rename-it.nl> (4f877644)
+
+ Fixed compiler warning.
+
+
+M src/lib-sieve/sieve-script.c
+
+2009-12-23 15:12:37 +0100 Stephan Bosch <stephan@rename-it.nl> (76dfa64d)
+
+ Include extension: global command may now appear anywhere in a script.
+
+
+M TODO
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M tests/extensions/include/errors.svtest
+M tests/extensions/include/errors/variables.sieve
+M tests/extensions/include/variables.svtest
+
+2009-12-23 14:17:53 +0100 Stephan Bosch <stephan@rename-it.nl> (ca5912f2)
+
+ Vacation extension: fixed typo in runtime log message (patch by Julian
+ Cowley).
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2009-12-23 14:12:59 +0100 Stephan Bosch <stephan@rename-it.nl> (d0aefe8a)
+
+ Testsuite: added tests for new features of the include extension.
+
+
+M tests/extensions/include/errors.svtest
+A tests/extensions/include/errors/global-namespace.sieve
+A tests/extensions/include/errors/scriptname.sieve
+M tests/extensions/include/included/variables-included1.sieve
+M tests/extensions/include/included/variables-included2.sieve
+
+2009-12-23 12:28:03 +0100 Stephan Bosch <stephan@rename-it.nl> (e86e039c)
+
+ Updated specification of include extension to latest version.
+
+
+R068 doc/rfc/draft-ietf-sieve-include-01.txt doc/rfc/draft-ietf-sieve-include-03.txt
+
+2009-12-23 12:27:38 +0100 Stephan Bosch <stephan@rename-it.nl> (5523de35)
+
+ Include extension: implemented global variables namespace.
+
+
+M TODO
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+
+2009-12-23 12:26:04 +0100 Stephan Bosch <stephan@rename-it.nl> (1670193a)
+
+ Variables extension: added basic namespace support.
+
+
+M TODO
+M src/lib-sieve/plugins/variables/Makefile.am
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+A src/lib-sieve/plugins/variables/ext-variables-namespaces.c
+A src/lib-sieve/plugins/variables/ext-variables-namespaces.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2009-12-22 11:21:34 +0100 Stephan Bosch <stephan@rename-it.nl> (4ebf931a)
+
+ Variables extension: improved source code comment.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+
+2009-12-24 11:03:14 +0100 Stephan Bosch <stephan@rename-it.nl> (7726ed36)
+
+ Added configurable script size limit.
+
+
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+
+2009-12-20 10:25:08 +0100 Stephan Bosch <stephan@rename-it.nl> (12a317ad)
+
+ Implemented script name checking using the requirements specified in the
+ ManageSieve draft.
+
+
+M TODO
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+
+2009-12-17 11:17:18 +0100 Stephan Bosch <stephan@rename-it.nl> (d61ff631)
+
+ Another Dovecot lib-storage API change (patch by Timo Sirainen).
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/sieve-actions.c
+M src/sieve-tools/sieve-filter.c
+M src/testsuite/testsuite-mailstore.c
+
+2009-12-13 21:16:10 +0100 Stephan Bosch <stephan@rename-it.nl> (1d3a73aa)
+
+ Adjusted to changes in Dovecot buffer API (patch by Pascal Volk).
+
+
+M src/lib-sieve/sieve-binary.c
+
+2009-11-19 21:22:56 +0100 Stephan Bosch <stephan@rename-it.nl> (545ba98e)
+
+ Made homedir aquisition a callback.
+
+
+M TODO
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve-types.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/testsuite/testsuite.c
+
+2009-11-19 18:03:19 +0100 Stephan Bosch <stephan@rename-it.nl> (924f83b7)
+
+ A warning is now produced when parsing invalid integer settings.
+
+
+M src/lib-sieve/sieve-settings.c
+
+2009-11-19 18:13:41 +0100 Stephan Bosch <stephan@rename-it.nl> (a2ae237a)
+
+ Made limits on the number of redirects and the number of actions in general
+ configurable.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/sieve-common.h
+D src/lib-sieve/sieve-limits.c
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-result.c
+A src/lib-sieve/sieve-settings.c
+A src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve.c
+
+2009-11-18 23:27:12 +0100 Stephan Bosch <stephan@rename-it.nl> (90d420e1)
+
+ Fixed homedir expansion bug in the include extension.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2009-11-17 14:46:04 +0100 Stephan Bosch <stephan@rename-it.nl> (191c465d)
+
+ Made sure that scripts are only recompiled when the script file - or the
+ symlink pointing to it - is strictly newer.
+
+
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+
+2009-11-16 00:34:13 +0100 Stephan Bosch <stephan@rename-it.nl> (45a3462d)
+
+ Fixed comment errors in date extension.
+
+
+M src/lib-sieve/plugins/date/tst-date.c
+
+2009-11-11 18:51:13 +0100 Stephan Bosch <stephan@rename-it.nl> (fd46aec5)
+
+ LDA Sieve plugin: small cosmetic changes in the sources.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-11-11 17:38:29 +0100 Stephan Bosch <stephan@rename-it.nl> (66d90e53)
+
+ Subaddress extension: now uses Dovecot's recipient_delimiter setting in
+ stead of its own sieve_subaddress_sep setting.
+
+
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+
+2009-11-08 23:35:48 +0100 Stephan Bosch <stephan@rename-it.nl> (aeca3e5b)
+
+ (Hopefully) fixed home expansion in LDA Sieve plugin.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-11-08 23:35:16 +0100 Stephan Bosch <stephan@rename-it.nl> (ea1e83d8)
+
+ Fixed dovecot doc dir.
+
+
+M configure.in
+
+2009-11-08 22:43:01 +0100 Stephan Bosch <stephan@rename-it.nl> (35bc88d6)
+
+ Forgot to add sieve_debug after porting logging change from v1.2.
+
+
+M src/lib-sieve/sieve-error.c
+
+2009-11-08 21:43:28 +0100 Stephan Bosch <stephan@rename-it.nl> (b49c5731)
+
+ Fixed install location of example config.
+
+
+M configure.in
+M doc/example-config/conf.d/Makefile.am
+
+2009-11-08 21:23:55 +0100 Stephan Bosch <stephan@rename-it.nl> (1e1b251b)
+
+ Made LDA Sieve plugin recognize the deliver_log_format setting.
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-types.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-11-08 21:03:30 +0100 Stephan Bosch <stephan@rename-it.nl> (fb5b443c)
+
+ Added i_debug support.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-11-08 19:50:46 +0100 Stephan Bosch <stephan@rename-it.nl> (3535f14e)
+
+ Fixed a bug in configure.in.
+
+
+M configure.in
+
+2009-11-08 18:49:37 +0100 Stephan Bosch <stephan@rename-it.nl> (67957b91)
+
+ Corrected install directories for headers and libraries.
+
+
+M configure.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/enotify/Makefile.am
+M src/lib-sieve/plugins/environment/Makefile.am
+M src/lib-sieve/plugins/variables/Makefile.am
+M src/sieve-tools/Makefile.am
+
+2009-11-08 16:02:59 +0100 Stephan Bosch <stephan@rename-it.nl> (cf4cfd97)
+
+ Made Sieve library a shared library.
+
+
+M configure.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/enotify/Makefile.am
+M src/lib-sieve/plugins/environment/Makefile.am
+M src/lib-sieve/plugins/variables/Makefile.am
+M src/plugins/lda-sieve/Makefile.am
+M src/sieve-tools/Makefile.am
+M src/testsuite/Makefile.am
+
+2009-10-31 22:36:41 +0100 Stephan Bosch <stephan@rename-it.nl> (4ef0c80a)
+
+ Fixed bug in result printing (untroduced in large rework).
+
+
+M src/lib-sieve/sieve-result.c
+
+2009-10-31 22:36:14 +0100 Stephan Bosch <stephan@rename-it.nl> (c72834e9)
+
+ Fixed bug in the extensions configuration (untroduced in large rework).
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2009-11-05 16:42:28 +0100 Stephan Bosch <stephan@rename-it.nl> (a9a234f3)
+
+ Fixed logging of mailbox names. It logged the converted mUTF7 version in
+ stead of the original UTF8.
+
+
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+
+2009-10-31 01:01:58 +0100 Stephan Bosch <stephan@rename-it.nl> (1b257ba4)
+
+ Fixed minor memory leak in the multiscript support.
+
+
+M src/lib-sieve/sieve.c
+
+2009-11-05 16:13:37 +0100 Stephan Bosch <stephan@rename-it.nl> (7d0e3eb1)
+
+ Adjusted to changes in Dovecot v2.0's LDA duplicate checking API.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-types.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+
+2009-11-05 15:47:24 +0100 Stephan Bosch <stephan@rename-it.nl> (852f7bf1)
+
+ Fixed v2.0-specific settings-related bugs remaining in the port from v1.2.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/testsuite/Makefile.am
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-settings.c
+M src/testsuite/testsuite-settings.h
+M src/testsuite/testsuite.c
+
+2009-11-05 15:46:48 +0100 Stephan Bosch <stephan@rename-it.nl> (e455b1d6)
+
+ Adjusted to API changes in Dovecot v2.0.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-mailstore.c
+
+2009-11-05 15:29:42 +0100 Stephan Bosch <stephan@rename-it.nl> (3368ba14)
+
+ Merged concurrent changes.
+
+
+2009-11-05 15:29:20 +0100 Stephan Bosch <stephan@rename-it.nl> (0bbc0790)
+
+ Properly implemented settings retrieval API.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/sieve-common.h
+D src/lib-sieve/sieve-settings.c
+D src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sievec.c
+M src/testsuite/Makefile.am
+M src/testsuite/testsuite.c
+
+2009-11-05 15:28:26 +0100 Stephan Bosch <stephan@rename-it.nl> (e8d9d151)
+
+ Fixed compiler warning in imap4flags extension.
+
+
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+
+2009-11-02 01:01:08 +0100 Stephan Bosch <stephan@rename-it.nl> (65583101)
+
+ Major rework of extension handling, making sure that no global state is
+ maintained.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/cmp-i-ascii-casemap.c
+M src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/Makefile.am
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/date/ext-date.c
+M src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/ext-environment-common.h
+M src/lib-sieve/plugins/environment/ext-environment.c
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/notify/ext-notify.c
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/lib-sieve/tst-truefalse.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/debug/cmd-debug-print.c
+M src/sieve-tools/debug/ext-debug-common.h
+M src/sieve-tools/debug/ext-debug.c
+M src/sieve-tools/debug/sieve-ext-debug.h
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/sieve-tools/sieved.c
+M src/testsuite/cmd-test-binary.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-mailbox.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/cmd-test-result-print.c
+M src/testsuite/cmd-test-result-reset.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-arguments.c
+M src/testsuite/testsuite-arguments.h
+M src/testsuite/testsuite-binary.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/testsuite-substitutions.h
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-multiscript.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-result.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+M tests/compile/errors/typos.sieve
+M tests/extensions/environment/basic.svtest
+M tests/extensions/imap4flags/multiscript.svtest
+
+2009-10-28 12:23:05 +0100 Stephan Bosch <stephan@rename-it.nl> (b3bb899f)
+
+ Message headers produced from user-supplied data are now RFC2047-encoded if
+ necessary for outgoing messages.
+
+
+M TODO
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/rfc2822.c
+M src/lib-sieve/rfc2822.h
+A tests/extensions/vacation/utf-8.svtest
+
+2009-10-23 00:17:34 +0200 Stephan Bosch <stephan@rename-it.nl> (6a2dbda5)
+
+ Adjusted to changes in the Dovecot service API.
+
+
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite.c
+
+2009-10-22 23:12:04 +0200 Stephan Bosch <stephan@rename-it.nl> (7eba6db1)
+
+ Set Dovecot version to v2.0 in configure.in.
+
+
+M configure.in
+
+2009-10-22 23:11:25 +0200 Stephan Bosch <stephan@rename-it.nl> (212a4172)
+
+ Added example configuration.
+
+
+M Makefile.am
+M configure.in
+A doc/Makefile.am
+A doc/example-config/Makefile.am
+A doc/example-config/conf.d/Makefile.am
+A doc/example-config/conf.d/sieve.conf
+A doc/man/Makefile.am
+
+2009-10-21 22:39:31 +0200 Stephan Bosch <stephan@rename-it.nl> (5a7a227e)
+
+ Moved Sieve plugin installation from modules/lda to modules.
+
+
+M src/plugins/lda-sieve/Makefile.am
+
+2009-10-20 22:54:11 +0200 Stephan Bosch <stephan@rename-it.nl> (f2a167f7)
+
+ Notify (deprecated): added support for the $text$ substitution.
+
+
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M tests/deprecated/notify/mailto.svtest
+
+2009-10-20 20:25:49 +0200 Stephan Bosch <stephan@rename-it.nl> (58b43b15)
+
+ Fixed indentation problems in obsolete notify extension.
+
+
+M src/lib-sieve/plugins/notify/cmd-notify.c
+
+2009-10-21 12:52:53 +0200 Stephan Bosch <stephan@rename-it.nl> (f2d1d0a6)
+
+ Adjusted to master service changes in the Dovecot API.
+
+
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite.c
+
+2009-10-21 11:52:52 +0200 Stephan Bosch <stephan@rename-it.nl> (8410ec51)
+
+ Adjusted to changes in Dovecot Master Service API.
+
+
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite.c
+
+2009-10-19 11:58:11 +0200 Stephan Bosch <stephan@rename-it.nl> (a781e577)
+
+ Finished new settings handling, including debugging support.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/sieve-settings.c
+M src/lib-sieve/sieve-settings.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/sieve-tools/sieved.c
+M src/testsuite/Makefile.am
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-script.c
+A src/testsuite/testsuite-settings.c
+A src/testsuite/testsuite-settings.h
+M src/testsuite/testsuite.c
+
+2009-10-18 23:22:51 +0200 Stephan Bosch <stephan@rename-it.nl> (273f6b4c)
+
+ Implemented Sieve settings handling (debug not working yet).
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+A src/lib-sieve/sieve-settings.c
+A src/lib-sieve/sieve-settings.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite.c
+
+2009-10-18 18:17:42 +0200 Stephan Bosch <stephan@rename-it.nl> (ec74124a)
+
+ Cleaned up TODO file.
+
+
+M TODO
+
+2009-10-18 16:44:23 +0200 Stephan Bosch <stephan@rename-it.nl> (58fb9103)
+
+ Testsuite: added multiscript flag tests for the imap4flags extension.
+
+
+M src/testsuite/cmd-test-message.c
+M src/testsuite/testsuite-script.c
+M tests/extensions/imap4flags/multiscript.svtest
+A tests/extensions/imap4flags/multiscript/fileinto.sieve
+A tests/extensions/imap4flags/multiscript/setflag.sieve
+
+2009-10-17 23:05:03 +0200 Stephan Bosch <stephan@rename-it.nl> (9cd8ef59)
+
+ Test suite: added multiscript support and added some new tests with the new
+ feature.
+
+
+M Makefile.am
+M TODO
+M src/testsuite/Makefile.am
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-script.h
+A src/testsuite/tst-test-multiscript.c
+A tests/extensions/imap4flags/multiscript.svtest
+A tests/extensions/imap4flags/multiscript/group-spam.sieve
+A tests/extensions/imap4flags/multiscript/sent-store.sieve
+A tests/extensions/imap4flags/multiscript/spam.sieve
+
+2009-10-17 19:40:18 +0200 Stephan Bosch <stephan@rename-it.nl> (793f4f7a)
+
+ Updated TODO.
+
+
+M TODO
+
+2009-10-17 16:35:32 +0200 Stephan Bosch <stephan@rename-it.nl> (c2d28f3a)
+
+ Updated TODO.
+
+
+M TODO
+
+2009-10-17 16:15:22 +0200 Stephan Bosch <stephan@rename-it.nl> (851d9d64)
+
+ Fixed race condition occuring when multiple instances are saving the same
+ binary (patch by Timo Sirainen).
+
+
+M src/lib-sieve/sieve-binary.c
+
+2009-10-11 15:51:54 +0200 Stephan Bosch <stephan@rename-it.nl> (17f472f2)
+
+ Test suite: added tests for not yet working body extension features.
+
+
+M tests/extensions/body/content.svtest
+
+2009-10-11 15:51:52 +0200 Stephan Bosch <stephan@rename-it.nl> (cf2d54d5)
+
+ Body extension: minor code cleanups.
+
+
+M src/lib-sieve/plugins/body/ext-body-common.c
+
+2009-10-11 12:20:38 +0200 Stephan Bosch <stephan@rename-it.nl> (43ebae99)
+
+ Body extension: fixed minor comment error.
+
+
+M src/lib-sieve/plugins/body/ext-body-common.c
+
+2009-10-11 12:08:02 +0200 Stephan Bosch <stephan@rename-it.nl> (45d8d199)
+
+ Test suite: restructured tests for body extension.
+
+
+M tests/extensions/body/basic.svtest
+M tests/extensions/body/content.svtest
+
+2009-10-11 12:07:45 +0200 Stephan Bosch <stephan@rename-it.nl> (9520455c)
+
+ Body extension: made parsing of content-type header more robust.
+
+
+M src/lib-sieve/plugins/body/ext-body-common.c
+
+2009-10-11 10:46:06 +0200 Stephan Bosch <stephan@rename-it.nl> (ecf0634c)
+
+ Test suite: added tests for basic use of :content with body test.
+
+
+M Makefile.am
+A tests/extensions/body/content.svtest
+
+2009-10-10 11:16:08 +0200 Stephan Bosch <stephan@rename-it.nl> (08255724)
+
+ Added TODO item.
+
+
+M TODO
+
+2009-10-10 11:14:58 +0200 Stephan Bosch <stephan@rename-it.nl> (c4b07aac)
+
+ Body extension: implemented proper handling of the :raw transform.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/tst-body.c
+M tests/extensions/body/basic.svtest
+A tests/extensions/body/raw.svtest
+
+2009-10-04 23:18:16 +0200 Stephan Bosch <stephan@rename-it.nl> (7c77a9bd)
+
+ Made compiler more lenient towars missing CRLF at the end of the script in a
+ hash comment.
+
+
+M Makefile.am
+M src/lib-sieve/sieve-lexer.c
+A tests/compile/warnings.svtest
+A tests/compile/warnings/eof.sieve
+
+2009-09-02 23:17:50 +0200 Stephan Bosch <stephan@rename-it.nl> (8d6882e2)
+
+ Body extension: don't give SKIP_BODY_BLOCK flag to message parser, we want
+ the body! (patch by Timo Sirainen).
+
+
+M src/lib-sieve/plugins/body/ext-body-common.c
+
+2009-09-02 23:38:57 +0200 Stephan Bosch <stephan@rename-it.nl> (726146c1)
+
+ Added TODO item.
+
+
+M TODO
+
+2009-09-02 23:10:59 +0200 Stephan Bosch <stephan@rename-it.nl> (53221b6d)
+
+ Fixed handling of implicit side effects for multiscript execution.
+
+
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2009-09-02 21:57:48 +0200 Stephan Bosch <stephan@rename-it.nl> (c861ba46)
+
+ Fixed bug in multiscript support; subsequent keep actions were not always
+ merged correctly.
+
+
+M src/lib-sieve/sieve-result.c
+
+2009-09-02 20:48:53 +0200 Stephan Bosch <stephan@rename-it.nl> (646b649e)
+
+ Fixed segfault bug in the sieve-test tool.
+
+
+M src/sieve-tools/sieve-test.c
+
+2009-09-02 20:36:19 +0200 Stephan Bosch <stephan@rename-it.nl> (30b8858d)
+
+ Fixed segfault bug triggered by merging side effects in duplicate actions.
+
+
+M src/lib-sieve/sieve-result.c
+
+2009-10-13 20:34:41 +0200 Stephan Bosch <stephan@rename-it.nl> (9a91c518)
+
+ Sieve plugin: don't try stat the user's personal script if it is not
+ specified (NULL).
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-10-13 20:32:25 +0200 Stephan Bosch <stephan@rename-it.nl> (8c91dc7d)
+
+ Mailbox extension: mailboxexists source file had wrong name; it is a test
+ and not a command.
+
+
+M src/lib-sieve/plugins/mailbox/Makefile.am
+R100 src/lib-sieve/plugins/mailbox/cmd-mailboxexists.c src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
+
+2009-08-21 16:30:49 +0200 Stephan Bosch <stephan@rename-it.nl> (33d248f6)
+
+ Enotify: removed spurious extern declaration of notify_extension.
+
+
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+
+2009-08-21 16:24:07 +0200 Stephan Bosch <stephan@rename-it.nl> (34076558)
+
+ Notify (deprecated): removed spurious source file.
+
+
+D src/lib-sieve/plugins/notify/ext-enotify.c
+
+2009-08-21 01:29:32 +0200 Stephan Bosch <stephan@rename-it.nl> (11e752a0)
+
+ Fixed compile warnings in test suite.
+
+
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-script.c
+
+2009-08-16 01:34:37 +0200 Stephan Bosch <stephan@rename-it.nl> (495c8fe7)
+
+ Updated TODO.
+
+
+M TODO
+
+2009-08-16 01:34:09 +0200 Stephan Bosch <stephan@rename-it.nl> (ebefaf9f)
+
+ Testsuite: added action execution test for the include extension with stored
+ binaries.
+
+
+M Makefile.am
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite.c
+A tests/extensions/include/execute.svtest
+A tests/extensions/include/execute/actions-fileinto.sieve
+A tests/extensions/include/execute/included/actions-fileinto1.sieve
+A tests/extensions/include/execute/included/actions-fileinto2.sieve
+A tests/extensions/include/execute/included/actions-fileinto3.sieve
+
+2009-08-16 01:33:32 +0200 Stephan Bosch <stephan@rename-it.nl> (5a6f9c5b)
+
+ Made sure script can be compared to NULL.
+
+
+M src/lib-sieve/sieve-script.c
+
+2009-08-16 00:59:56 +0200 Stephan Bosch <stephan@rename-it.nl> (5e20f16e)
+
+ Fixed bug in error reporting when binary-related script object is not set.
+
+
+M src/lib-sieve/sieve-error.c
+
+2009-08-16 01:00:41 +0200 Stephan Bosch <stephan@rename-it.nl> (21697375)
+
+ Testsuite: added support for testing binaries stored on disk.
+
+
+M Makefile.am
+M src/testsuite/Makefile.am
+A src/testsuite/cmd-test-binary.c
+M src/testsuite/ext-testsuite.c
+A src/testsuite/testsuite-binary.c
+A src/testsuite/testsuite-binary.h
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-script.h
+R056 tests/compile/examples.svtest tests/execute/examples.svtest
+
+2009-08-15 19:55:58 +0200 Stephan Bosch <stephan@rename-it.nl> (bf2b918d)
+
+ Updated TODO list.
+
+
+M TODO
+
+2009-10-13 20:22:40 +0200 Stephan Bosch <stephan@rename-it.nl> (a60edb07)
+
+ Updated documentation.
+
+
+M README
+
+2009-08-15 19:54:56 +0200 Stephan Bosch <stephan@rename-it.nl> (76be3c64)
+
+ Testsuite: added tests for the new date extension.
+
+
+M Makefile.am
+A tests/extensions/date/basic.svtest
+A tests/extensions/date/date-parts.svtest
+A tests/extensions/date/zones.svtest
+
+2009-08-15 19:54:34 +0200 Stephan Bosch <stephan@rename-it.nl> (2cbfffad)
+
+ Date extension: now included in default compile.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+M src/lib-sieve/plugins/date/ext-date.c
+M src/lib-sieve/sieve-extensions.c
+
+2009-08-15 19:36:02 +0200 Stephan Bosch <stephan@rename-it.nl> (4aec8d11)
+
+ Date extension: accidentally committed debug printf.
+
+
+M src/lib-sieve/plugins/date/tst-date.c
+
+2009-08-15 19:30:33 +0200 Stephan Bosch <stephan@rename-it.nl> (afd82d40)
+
+ Date extension: fixed problems in time zone handling.
+
+
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/tst-date.c
+
+2009-08-15 19:29:39 +0200 Stephan Bosch <stephan@rename-it.nl> (eee29780)
+
+ Testsuite: added some debug code.\n
+
+
+M src/testsuite/testsuite-message.c
+
+2009-08-15 16:55:29 +0200 Stephan Bosch <stephan@rename-it.nl> (bbe06f29)
+
+ Date extension: fixed bug in julian date calculation.
+
+
+M src/lib-sieve/plugins/date/ext-date-common.c
+
+2009-08-15 16:40:28 +0200 Stephan Bosch <stephan@rename-it.nl> (b3b6c0e4)
+
+ Date extension: fixed a few bugs related to date part extraction.
+
+
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/tst-date.c
+
+2009-08-15 14:43:28 +0200 Stephan Bosch <stephan@rename-it.nl> (418bd097)
+
+ Date extension: fixed errorhandling of gmtime() call.
+
+
+M src/lib-sieve/plugins/date/tst-date.c
+
+2009-08-15 14:34:21 +0200 Stephan Bosch <stephan@rename-it.nl> (2a84d7ca)
+
+ Date extension: completed implementation.
+
+
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/tst-date.c
+
+2009-08-15 14:13:03 +0200 Stephan Bosch <stephan@rename-it.nl> (d88c5f03)
+
+ Date extension: all simple integer date parts are fixed-length strings.
+
+
+M src/lib-sieve/plugins/date/ext-date-common.c
+
+2009-08-15 14:09:23 +0200 Stephan Bosch <stephan@rename-it.nl> (1f89a586)
+
+ Date extension: implemented time zone handling.
+
+
+M src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/date/tst-date.c
+
+2009-08-15 13:37:24 +0200 Stephan Bosch <stephan@rename-it.nl> (b6d41c88)
+
+ Date extension: implemented iso8601 date part.
+
+
+M src/lib-sieve/plugins/date/ext-date-common.c
+
+2009-08-15 13:17:59 +0200 Stephan Bosch <stephan@rename-it.nl> (89db87d7)
+
+ Date extension: implemented a few more date parts.
+
+
+M src/lib-sieve/plugins/date/ext-date-common.c
+
+2009-10-13 20:10:57 +0200 Stephan Bosch <stephan@rename-it.nl> (47f917af)
+
+ Adjusted to changes in smtp_client API in Dovecot.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-08-12 23:20:43 +0200 Stephan Bosch <stephan@rename-it.nl> (15296322)
+
+ Fixed segfault occuring when message was stored. Namespace was not properly
+ initialized.
+
+
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-mailstore.c
+
+2009-08-10 09:55:36 +0200 Stephan Bosch <stephan@rename-it.nl> (103ea620)
+
+ Fixed distribution of unfinished features.
+
+
+M Makefile.am
+
+2009-08-09 18:47:13 +0200 Stephan Bosch <stephan@rename-it.nl> (3765cf1c)
+
+ Date extension: built infrastructure for date part testing.
+
+
+M src/lib-sieve/plugins/date/Makefile.am
+A src/lib-sieve/plugins/date/ext-date-common.c
+M src/lib-sieve/plugins/date/ext-date-common.h
+M src/lib-sieve/plugins/date/ext-date.c
+M src/lib-sieve/plugins/date/tst-date.c
+
+2009-08-07 21:50:32 +0200 Stephan Bosch <stephan@rename-it.nl> (43271274)
+
+ Sieve-filter: created man-page a design for the command line options.
+
+
+M Makefile.am
+A doc/man/sieve-filter.1
+
+2009-08-07 17:42:48 +0200 Stephan Bosch <stephan@rename-it.nl> (2e57e896)
+
+ Include: compare execution result to SIEVE_EXEC_OK and not to zero.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2009-08-07 17:24:28 +0200 Stephan Bosch <stephan@rename-it.nl> (0ca5d58b)
+
+ Include: fixed return type of execution function.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+
+2009-08-07 17:10:30 +0200 Stephan Bosch <stephan@rename-it.nl> (6c9046de)
+
+ Fixed erroneous comment in binary implementation.
+
+
+M src/lib-sieve/plugins/include/ext-include-binary.c
+
+2009-08-06 21:46:10 +0200 Stephan Bosch <stephan@rename-it.nl> (951ed92e)
+
+ Fixed typo in TODO file.
+
+
+M TODO
+
+2009-08-05 23:40:35 +0200 Stephan Bosch <stephan@rename-it.nl> (7097f58c)
+
+ Updated TODO.
+
+
+M TODO
+
+2009-08-05 23:38:20 +0200 Stephan Bosch <stephan@rename-it.nl> (f0166f99)
+
+ Built skeleton implementation for the date extension (RFC 5260).
+
+
+M configure.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/date/Makefile.am
+A src/lib-sieve/plugins/date/ext-date-common.h
+A src/lib-sieve/plugins/date/ext-date.c
+A src/lib-sieve/plugins/date/tst-date.c
+M src/lib-sieve/sieve-extensions.c
+
+2009-08-05 23:28:21 +0200 Stephan Bosch <stephan@rename-it.nl> (0a245504)
+
+ Body: fixed erroneous return code for invalid optional operand.
+
+
+M src/lib-sieve/plugins/body/tst-body.c
+
+2009-08-05 13:18:08 +0200 Stephan Bosch <stephan@rename-it.nl> (51cf7daa)
+
+ Be explicit about signedness of data in binary code representation. Some
+ architectures, like ARM, differ in this respect.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-interpreter.c
+
+2009-08-05 12:47:27 +0200 Stephan Bosch <stephan@rename-it.nl> (68f65845)
+
+ Side-effect argumennt registrations were not using the SIEVE_OPT_SIDE_EFFECT
+ constant.
+
+
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-code.h
+
+2009-08-05 09:07:14 +0200 Stephan Bosch <stephan@rename-it.nl> (cd4d36c3)
+
+ Removed direct stdint.h includes to prevent portability issues.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-common.h
+
+2009-08-04 22:18:53 +0200 Stephan Bosch <stephan@rename-it.nl> (d317639a)
+
+ Reprioritized and reformatted TODO file.
+
+
+M TODO
+
+2009-08-04 19:35:11 +0200 Stephan Bosch <stephan@rename-it.nl> (729452a5)
+
+ Fixed segfault bug in the handling of script open failures.
+
+
+M src/lib-sieve/sieve.c
+
+2009-08-04 19:34:18 +0200 Stephan Bosch <stephan@rename-it.nl> (4d9f374d)
+
+ Include: further adjusted log and user messages.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2009-08-11 18:13:18 +0200 Stephan Bosch <stephan@rename-it.nl> (88ff726c)
+
+ Mailbox extension: ported mailboxexists test to Dovecot v2.0.
+
+
+M src/lib-sieve/plugins/mailbox/cmd-mailboxexists.c
+
+2009-08-04 18:53:50 +0200 Stephan Bosch <stephan@rename-it.nl> (0c230819)
+
+ LDA-Sieve plugin: fixed copy-paste mixup between sieve_after and
+ sieve_before. If only a sieve_after script was active, nothing would have
+ been executed. Patch by Mike Abbott.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-08-04 18:45:02 +0200 Stephan Bosch <stephan@rename-it.nl> (22c1bca7)
+
+ Include: fixed bug in /home/stephan substitution in sieve_dir path.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2009-08-04 17:46:30 +0200 Stephan Bosch <stephan@rename-it.nl> (3f844674)
+
+ Include: improved error messages for include failures.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+
+2009-08-04 17:13:50 +0200 Stephan Bosch <stephan@rename-it.nl> (2fcf65a7)
+
+ Include: removed variables-related FIXME and substituted a permanent error
+ message.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+
+2009-08-03 17:48:11 +0200 Stephan Bosch <stephan@rename-it.nl> (d636abe1)
+
+ Forgot to add header in Makefile.am for testsuite.
+
+
+M src/testsuite/Makefile.am
+
+2009-08-03 16:43:55 +0200 Stephan Bosch <stephan@rename-it.nl> (9512ce58)
+
+ Fixed automake bug in new maibox extension sources.
+
+
+M src/lib-sieve/plugins/mailbox/Makefile.am
+
+2009-08-02 16:34:35 +0200 Stephan Bosch <stephan@rename-it.nl> (b07bf640)
+
+ Testsuite: made valgrind report all allocated blocks that remain at program
+ end.
+
+
+M Makefile.am
+
+2009-08-02 16:03:13 +0200 Stephan Bosch <stephan@rename-it.nl> (7d7ce23e)
+
+ Testsuite: properly deallocated test name string buffer upon close.
+
+
+M src/testsuite/testsuite-common.c
+
+2009-08-02 15:41:08 +0200 Stephan Bosch <stephan@rename-it.nl> (3bf779b0)
+
+ Fixed memory leak in matching code caused by earlier fix.
+
+
+M src/lib-sieve/sieve-match.c
+
+2009-08-02 15:26:33 +0200 Stephan Bosch <stephan@rename-it.nl> (a611b483)
+
+ Made proper API for loading a binary directly.
+
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/sieve-tools/sieved.c
+
+2009-08-02 14:40:46 +0200 Stephan Bosch <stephan@rename-it.nl> (2c2926aa)
+
+ Testsuite: added an important test for the imap4flags extension.
+
+
+M tests/extensions/imap4flags/flagstore.svtest
+
+2009-08-02 11:00:24 +0200 Stephan Bosch <stephan@rename-it.nl> (d03211b9)
+
+ Imap4flags: added flag storage tests using mailbox loopback.
+
+
+M Makefile.am
+M TODO
+A tests/extensions/imap4flags/flagstore.svtest
+
+2009-08-02 10:42:58 +0200 Stephan Bosch <stephan@rename-it.nl> (e78f1905)
+
+ Imap4flags: now reads initial flags and keywords from supplied mail. Upon
+ delivery this is empty, which still matches the specification.
+
+
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M tests/extensions/imap4flags/basic.svtest
+
+2009-08-02 10:40:12 +0200 Stephan Bosch <stephan@rename-it.nl> (a61fb923)
+
+ Added access methods for message data en script environment to result
+ object.
+
+
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2009-08-02 00:58:47 +0200 Stephan Bosch <stephan@rename-it.nl> (055ade7b)
+
+ Testsuite: added support for testing delivered messages by looping these
+ back as the evaluated message. Added tests for the fileinto command.
+
+
+M Makefile.am
+M TODO
+M src/testsuite/cmd-test-message.c
+M src/testsuite/testsuite-mailstore.c
+A tests/execute/mailstore.svtest
+M tests/extensions/mailbox/execute.svtest
+
+2009-08-11 18:00:47 +0200 Stephan Bosch <stephan@rename-it.nl> (092ac281)
+
+ Updated README.
+
+
+M README
+
+2009-08-01 22:40:21 +0200 Stephan Bosch <stephan@rename-it.nl> (45e64f2c)
+
+ Updated TODO and added a FIXME to the mailbox extension (no ACL support yet,
+ but required by RFC).
+
+
+M TODO
+M src/lib-sieve/plugins/mailbox/cmd-mailboxexists.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+
+2009-08-01 22:33:37 +0200 Stephan Bosch <stephan@rename-it.nl> (322597a8)
+
+ Testsuite: added tests for the mailbox extension.
+
+
+M Makefile.am
+A tests/extensions/mailbox/execute.svtest
+
+2009-08-01 22:28:50 +0200 Stephan Bosch <stephan@rename-it.nl> (742c8bf0)
+
+ Mailbox extension: finished implementation.
+
+
+M src/lib-sieve/plugins/mailbox/cmd-mailboxexists.c
+M src/lib-sieve/plugins/mailbox/ext-mailbox.c
+
+2009-08-01 19:37:24 +0200 Stephan Bosch <stephan@rename-it.nl> (dd677db8)
+
+ Small code cleanup in the lexer code.
+
+
+M src/lib-sieve/sieve-lexer.c
+
+2009-08-01 13:33:35 +0200 Stephan Bosch <stephan@rename-it.nl> (a594d8f1)
+
+ Updated man pages.
+
+
+M doc/man/sieve-test.1
+M doc/man/sievec.1
+M doc/man/sieved.1
+
+2009-07-31 17:35:51 +0200 Stephan Bosch <stephan@rename-it.nl> (f99a83f1)
+
+ Fixed bug in the derivation of the binary path from the script path. A bare
+ filename would yield a path relative to root.
+
+
+M src/lib-sieve/sieve-script.c
+
+2009-08-11 17:56:48 +0200 Stephan Bosch <stephan@rename-it.nl> (fc41bc1a)
+
+ Testsuite: added support for testing mailbox operations.
+
+
+M src/testsuite/Makefile.am
+A src/testsuite/cmd-test-mailbox.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-common.h
+A src/testsuite/testsuite-mailstore.c
+A src/testsuite/testsuite-mailstore.h
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite.c
+M tests/execute/actions.svtest
+M tests/extensions/imap4flags/execute.svtest
+
+2009-08-11 17:56:02 +0200 Stephan Bosch <stephan@rename-it.nl> (456fd6e0)
+
+ Fixed indent problems.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/sieve-tools/sieve-test.c
+
+2009-07-31 00:13:03 +0200 Stephan Bosch <stephan@rename-it.nl> (4b749557)
+
+ Use foreign automake option so it doesn't complain about missing ChangeLog.
+
+
+M autogen.sh
+M configure.in
+
+2009-07-30 01:15:00 +0200 Stephan Bosch <stephan@rename-it.nl> (033a28eb)
+
+ Regex: documented source code a little better.
+
+
+M src/lib-sieve/plugins/regex/mcht-regex.c
+
+2009-07-30 01:00:14 +0200 Stephan Bosch <stephan@rename-it.nl> (7c2116f7)
+
+ Made sieve_match_context use a proper pool in stead of the datastack.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-result.c
+
+2009-07-29 02:24:34 +0200 Stephan Bosch <stephan@rename-it.nl> (c72624bc)
+
+ Added TODO item.
+
+
+M TODO
+
+2009-07-29 01:56:09 +0200 Stephan Bosch <stephan@rename-it.nl> (36963417)
+
+ Include: fixed assertion fail caused by missing initialization (bug surfaces
+ only for stored binaries).
+
+
+M src/lib-sieve/plugins/include/ext-include.c
+
+2009-07-29 01:04:09 +0200 Stephan Bosch <stephan@rename-it.nl> (1d8fb774)
+
+ Include: include error message for failed :global include.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2009-07-27 17:51:13 +0200 Stephan Bosch <stephan@rename-it.nl> (b24b7269)
+
+ Sieve-filter: removed unnecessary MAILBOX_TRANSACTION_FLAG_REFRESH flag for
+ mailbox_transaction_begin().
+
+
+M src/sieve-tools/sieve-filter.c
+
+2009-07-27 00:28:31 +0200 Stephan Bosch <stephan@rename-it.nl> (89ec2c30)
+
+ Reprioritized TODO.
+
+
+M TODO
+
+2009-08-07 23:57:52 +0200 Stephan Bosch <stephan@rename-it.nl> (71197d41)
+
+ Fixed compile warnings introduced by porting from v1.2.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+
+2009-08-07 23:50:27 +0200 Stephan Bosch <stephan@rename-it.nl> (dd70d665)
+
+ Mailbox extension: implemented the :create tagged argument for the fileinto
+ command.
+
+
+M src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+
+2009-08-07 23:23:33 +0200 Stephan Bosch <stephan@rename-it.nl> (2b6dacc5)
+
+ Fixed compile error introduced by porting from v1.2.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2009-08-07 23:21:07 +0200 Stephan Bosch <stephan@rename-it.nl> (99cf7d64)
+
+ Sieve-filter: added support for setting flags on message in the source
+ folder.
+
+
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+
+2009-07-26 14:23:02 +0200 Stephan Bosch <stephan@rename-it.nl> (e1f2abc0)
+
+ Sieve-filter: corrected and optimized mail filter loop.
+
+
+M src/sieve-tools/sieve-filter.c
+
+2009-08-07 23:19:51 +0200 Stephan Bosch <stephan@rename-it.nl> (f002157d)
+
+ Fixed broken wiki reference in error message.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-07-26 02:37:58 +0200 Stephan Bosch <stephan@rename-it.nl> (81a4e22d)
+
+ Implemented skeleton of the mailbox extension.
+
+
+M configure.in
+M src/lib-sieve/Makefile.am
+A src/lib-sieve/plugins/mailbox/Makefile.am
+A src/lib-sieve/plugins/mailbox/cmd-mailboxexists.c
+A src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
+A src/lib-sieve/plugins/mailbox/ext-mailbox.c
+A src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
+M src/lib-sieve/sieve-extensions.c
+
+2009-07-26 02:37:46 +0200 Stephan Bosch <stephan@rename-it.nl> (f83b6345)
+
+ Notify (deprecated): fixed compiler warnings.
+
+
+M src/lib-sieve/plugins/Makefile.am
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+
+2009-07-25 22:44:49 +0200 Stephan Bosch <stephan@rename-it.nl> (a8af380a)
+
+ Sieve-filter: implemented alternative discard actions.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-types.h
+M src/sieve-tools/sieve-filter.c
+
+2009-07-25 20:12:18 +0200 Stephan Bosch <stephan@rename-it.nl> (a8c1aca0)
+
+ Sieve-filter: implemented expunging filtered messages in the source folder
+ (move).
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-types.h
+M src/sieve-tools/sieve-filter.c
+
+2009-07-25 01:42:50 +0200 Stephan Bosch <stephan@rename-it.nl> (a584bec0)
+
+ Added means to get keep status from sieve execution through main Sieve
+ library API.
+
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+
+2009-07-25 00:39:35 +0200 Stephan Bosch <stephan@rename-it.nl> (565eb918)
+
+ Minor changes to the sieve-filter tool.
+
+
+M src/sieve-tools/sieve-filter.c
+
+2009-08-07 23:17:00 +0200 Stephan Bosch <stephan@rename-it.nl> (b5f343d8)
+
+ Restructured store action implementation to properly handle an attempt to
+ store (keep) a message in the folder it originates from.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+
+2009-08-07 23:11:14 +0200 Stephan Bosch <stephan@rename-it.nl> (ace3f5a4)
+
+ Notify (deprecated): implemented skeleton of the denotify command.
+
+
+M src/lib-sieve/plugins/notify/Makefile.am
+M src/lib-sieve/plugins/notify/cmd-denotify.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+A src/lib-sieve/plugins/notify/ext-notify-common.c
+M src/lib-sieve/plugins/notify/ext-notify-common.h
+M src/lib-sieve/plugins/notify/ext-notify.c
+
+2009-07-24 12:36:17 +0200 Stephan Bosch <stephan@rename-it.nl> (aebf3eee)
+
+ Fallback to INBOX when storing into a namespace prefix used wrong storage.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2009-07-24 04:19:44 +0200 Stephan Bosch <stephan@rename-it.nl> (580a1330)
+
+ Separated source and destination mail store for sieve-filter tool.
+
+
+M src/sieve-tools/sieve-filter.c
+
+2009-08-07 23:07:35 +0200 Stephan Bosch <stephan@rename-it.nl> (1ee0aea6)
+
+ Showed wrong folder name upon INBOX fallback.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2009-08-07 23:05:25 +0200 Stephan Bosch <stephan@rename-it.nl> (633c5a18)
+
+ Fixed some code indent problems.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2009-08-07 23:04:06 +0200 Stephan Bosch <stephan@rename-it.nl> (12b28e57)
+
+ Made attempt to store in a namespace prefix fall back into INBOX.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2009-08-07 23:01:03 +0200 Stephan Bosch <stephan@rename-it.nl> (e4c6a900)
+
+ Fixed logging of folder namespace prefix in store action.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2009-07-22 00:51:36 +0200 Stephan Bosch <stephan@rename-it.nl> (59c13056)
+
+ Fixed potential segfault argument parameter validation.
+
+
+M src/lib-sieve/sieve-validator.c
+
+2009-07-21 13:09:06 +0200 Stephan Bosch <stephan@rename-it.nl> (4ad98f80)
+
+ Testsuite: added tests on the envelope of outgoing messages produced by
+ redirect, enotify:mailto, reject and vacation.
+
+
+M Makefile.am
+M src/testsuite/testsuite.c
+A tests/execute/smtp.svtest
+M tests/extensions/enotify/mailto.svtest
+A tests/extensions/reject/smtp.svtest
+A tests/extensions/vacation/smtp.svtest
+
+2009-08-07 22:48:19 +0200 Stephan Bosch <stephan@rename-it.nl> (66cddf8e)
+
+ Major rework of envelope address handling: a normalized version of the
+ envelope addresses is maintained in the message context and message context
+ is now also available during action execution.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite.c
+
+2009-08-07 22:36:04 +0200 Stephan Bosch <stephan@rename-it.nl> (085cad82)
+
+ Fixed segfault bug: made sure return_path is never used without checking for
+ NULL first.
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/notify/cmd-notify.c
+M src/lib-sieve/sieve-address.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-smtp.c
+
+2009-08-07 22:33:35 +0200 Stephan Bosch <stephan@rename-it.nl> (72d3a452)
+
+ Removed the sieve-filter tool from the default build. Need to specify
+ --with-unfinished-features to get this tool built.
+
+
+M src/sieve-tools/Makefile.am
+
+2009-07-19 23:18:34 +0200 Stephan Bosch <stephan@rename-it.nl> (d88b39dc)
+
+ Added compilation support for ereject extension. It is unfinished right now
+ and performs exactly the same action as reject.
+
+
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/sieve-extensions.c
+
+2009-07-19 23:17:46 +0200 Stephan Bosch <stephan@rename-it.nl> (d1763395)
+
+ Fixed bugs in the autoconf structure regarding enabling/disabling unfinished
+ features.
+
+
+M configure.in
+M dsieve-config.h.in
+
+2009-07-19 21:57:13 +0200 Stephan Bosch <stephan@rename-it.nl> (1d3c285b)
+
+ Downloaded RFC for reject and ereject extensions.
+
+
+D doc/rfc/draft-ietf-sieve-refuse-reject-07.txt
+A doc/rfc/reject-ereject.rfc5429.txt
+
+2009-07-19 16:59:47 +0200 Stephan Bosch <stephan@rename-it.nl> (18d4325f)
+
+ Improved file manipulation error messages regarding EACCES error.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-script.c
+
+2009-07-18 11:35:46 +0200 Stephan Bosch <stephan@rename-it.nl> (4ce148eb)
+
+ Testsuite: added tests for envelope/address test behavior with non-existant
+ subaddress :detail part.
+
+
+M tests/extensions/subaddress/basic.svtest
+
+2009-07-18 11:34:52 +0200 Stephan Bosch <stephan@rename-it.nl> (5542d373)
+
+ Envelope: fixed bug in application of address parts; failure to obtain the
+ part would cause inappropriate match success (bug reported by Ron Lee)
+
+
+M src/lib-sieve/ext-envelope.c
+
+2009-07-18 11:14:18 +0200 Stephan Bosch <stephan@rename-it.nl> (aeaec526)
+
+ Added additional headers to the list of allowed headers for the address
+ test.
+
+
+M src/lib-sieve/tst-address.c
+
+2009-07-17 21:52:13 +0200 Stephan Bosch <stephan@rename-it.nl> (2310bf8d)
+
+ Notify (deprecated): added FIXME notice with missing compatibility features.
+
+
+M src/lib-sieve/plugins/notify/ext-notify.c
+
+2009-07-17 21:46:00 +0200 Stephan Bosch <stephan@rename-it.nl> (fb59caa7)
+
+ Testsuite: added tests for deprecated notify extension.
+
+
+M Makefile.am
+A tests/deprecated/notify/basic.svtest
+A tests/deprecated/notify/errors.svtest
+A tests/deprecated/notify/errors/options.sieve
+A tests/deprecated/notify/execute.svtest
+A tests/deprecated/notify/execute/duplicates.sieve
+A tests/deprecated/notify/mailto.svtest
+
+2009-07-19 17:20:17 +0200 Stephan Bosch <stephan@rename-it.nl> (3451d5e6)
+
+ Notify (deprecated): fixed compile error due to inappropriate use of SMTP
+ API.
+
+
+M src/lib-sieve/plugins/notify/cmd-notify.c
+
+2009-07-19 17:19:25 +0200 Stephan Bosch <stephan@rename-it.nl> (cb2dddc6)
+
+ Testsuite: added support for specifying the available extensions at the
+ commandline.
+
+
+M src/testsuite/testsuite.c
+
+2009-07-17 21:38:40 +0200 Stephan Bosch <stephan@rename-it.nl> (23a5f9c8)
+
+ Testsuite: Notify: added test with empty :from argument for notify command.
+
+
+M tests/extensions/enotify/errors.svtest
+M tests/extensions/enotify/errors/from-mailto.sieve
+
+2009-07-17 21:37:23 +0200 Stephan Bosch <stephan@rename-it.nl> (96090a84)
+
+ Notify (deprecated): fixed segfault bug in the :options argument validation.
+
+
+M src/lib-sieve/plugins/notify/cmd-notify.c
+
+2009-07-17 21:01:03 +0200 Stephan Bosch <stephan@rename-it.nl> (7bf26c2a)
+
+ Notify (deprecated): added runtime check for recipient limit.
+
+
+M src/lib-sieve/plugins/notify/cmd-notify.c
+
+2009-07-17 20:47:22 +0200 Stephan Bosch <stephan@rename-it.nl> (e6586cb7)
+
+ Notify (deprecated): added runtime check for duplicate recipients.
+
+
+M src/lib-sieve/plugins/notify/cmd-notify.c
+
+2009-07-17 20:32:39 +0200 Stephan Bosch <stephan@rename-it.nl> (445934a2)
+
+ Notify (deprecated): added support for substitutions in the notification
+ message.
+
+
+M src/lib-sieve/plugins/notify/cmd-notify.c
+
+2009-07-17 03:28:04 +0200 Stephan Bosch <stephan@rename-it.nl> (f5268a9c)
+
+ Made deprecated notify extension implementation compatible with cmusieve,
+ except for the denotify command.
+
+
+M configure.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+M src/lib-sieve/plugins/enotify/Makefile.am
+D src/lib-sieve/plugins/enotify/ext-notify.c
+A src/lib-sieve/plugins/notify/Makefile.am
+A src/lib-sieve/plugins/notify/cmd-denotify.c
+A src/lib-sieve/plugins/notify/cmd-notify.c
+A src/lib-sieve/plugins/notify/ext-enotify.c
+A src/lib-sieve/plugins/notify/ext-notify-common.h
+A src/lib-sieve/plugins/notify/ext-notify-limits.h
+A src/lib-sieve/plugins/notify/ext-notify.c
+
+2009-07-08 19:37:24 +0200 Stephan Bosch <stephan@rename-it.nl> (dd412acb)
+
+ Added partial support for the depricated notify extension.
+
+
+M src/lib-sieve/plugins/enotify/Makefile.am
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+A src/lib-sieve/plugins/enotify/ext-notify.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-extensions.c
+
+2009-07-17 03:14:45 +0200 Stephan Bosch <stephan@rename-it.nl> (1c8106f0)
+
+ Fixed validator extension validation. It validated the first non-require
+ command before validating the extensions, which produced useless error
+ messages.
+
+
+M src/lib-sieve/sieve-validator.c
+
+2009-07-17 01:04:19 +0200 Stephan Bosch <stephan@rename-it.nl> (a11b7ade)
+
+ Made discard action log a message to avoid confusion about disappearing
+ messages.
+
+
+M src/lib-sieve/cmd-discard.c
+
+2009-07-15 19:36:17 +0200 Stephan Bosch <stephan@rename-it.nl> (e7a1f2e1)
+
+ Inappropriately ignored return value from fwrite in outgoing message
+ construction.
+
+
+M src/lib-sieve/rfc2822.c
+M src/lib-sieve/rfc2822.h
+
+2009-07-14 23:08:09 +0200 Stephan Bosch <stephan@rename-it.nl> (8c55bae5)
+
+ Adjusted to Dovecot mail API changes.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2009-07-08 17:08:23 +0200 Stephan Bosch <stephan@rename-it.nl> (646cd2c1)
+
+ Apparently, deprecated is spelled with an 'e'.
+
+
+M src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/sieve-extensions.c
+
+2009-07-06 15:05:25 +0200 Stephan Bosch <stephan@rename-it.nl> (9621cd92)
+
+ Fixed AIX compile problem provisionally.
+
+
+M src/lib-sieve/sieve-ast.c
+
+2009-07-05 09:45:48 +0200 Stephan Bosch <stephan@rename-it.nl> (31b9138b)
+
+ Updated TODO.
+
+
+M TODO
+
+2009-07-05 10:12:52 +0200 Stephan Bosch <stephan@rename-it.nl> (125bacfe)
+
+ Added item to .hgignore.
+
+
+M .hgignore
+
+2009-07-05 10:11:13 +0200 Stephan Bosch <stephan@rename-it.nl> (7ec4862e)
+
+ Improved consistency of sieve tool documentation.
+
+
+M doc/man/sieve-test.1
+M doc/man/sievec.1
+M doc/man/sieved.1
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/sieve-tools/sieved.c
+
+2009-07-04 14:08:39 +0200 Stephan Bosch <stephan@rename-it.nl> (591ba090)
+
+ Enhanced extensions configuration, allowing to specify the enabled
+ extensions relatively to the default.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2009-07-04 11:26:01 +0200 Stephan Bosch <stephan@rename-it.nl> (242ee570)
+
+ Sieve plugin: forgot to initialize script execution status.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-07-05 10:05:32 +0200 Stephan Bosch <stephan@rename-it.nl> (532f630e)
+
+ Sieve plugin: fixed logging for execution of default main script (went to
+ STDERR).
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-06-28 15:57:09 +0200 Stephan Bosch <stephan@rename-it.nl> (e7905807)
+
+ Added support for CRLF line breaks in strbuf error handler (ManageSieve
+ fix).
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+
+2009-06-21 13:35:00 +0200 Stephan Bosch <stephan@rename-it.nl> (05cfe989)
+
+ Adjusted to mailbox API changes in Dovecot.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve/sieve-actions.c
+
+2009-06-01 10:20:14 +0200 Stephan Bosch <stephan@rename-it.nl> (7d664b76)
+
+ Body: fixed potential problems wil NUL characters in body parts.
+
+
+M src/lib-sieve/plugins/body/ext-body-common.c
+
+2009-06-01 10:00:07 +0200 Stephan Bosch <stephan@rename-it.nl> (16372f50)
+
+ Body: fixed assert failure caused by ugly code and a change in dovecot.
+
+
+M src/lib-sieve/plugins/body/ext-body-common.c
+
+2009-05-29 23:50:53 +0200 Stephan Bosch <stephan@rename-it.nl> (6d5c81d5)
+
+ Body: fixed part of the assert fail problems (Dovecot change).
+
+
+M src/lib-sieve/plugins/body/ext-body-common.c
+
+2009-05-29 23:49:30 +0200 Stephan Bosch <stephan@rename-it.nl> (8d04eab3)
+
+ Adjusted to changes in Dovecot regarding opening a raw stream.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/sieve-tools/sieve-test.c
+
+2009-05-24 18:48:44 +0200 Stephan Bosch <stephan@rename-it.nl> (e701fa64)
+
+ Started using v2.0 settings interface to get plugin settings.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-05-23 13:11:17 +0200 Stephan Bosch <stephan@rename-it.nl> (e5648819)
+
+ Migrated Dovecot Sieve to Dovecot v2.0.
+
+
+M .hgignore
+M src/lib-sieve-tool/Makefile.am
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+A src/lib-sieve/sieve-smtp.c
+A src/lib-sieve/sieve-smtp.h
+M src/lib-sieve/sieve-types.h
+M src/plugins/lda-sieve/Makefile.am
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/Makefile.am
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/sieve-tools/sieved.c
+M src/testsuite/Makefile.am
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite.c
+
+2009-05-18 08:54:26 +0200 Stephan Bosch <stephan@rename-it.nl> (f639cbb5)
+
+ Fixed compiler warning.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2009-05-17 20:05:44 +0200 Stephan Bosch <stephan@rename-it.nl> (fe48395e)
+
+ Made default of sieve_dir setting match the ManageSieve implementation.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2009-05-17 19:54:10 +0200 Stephan Bosch <stephan@rename-it.nl> (72aa0c23)
+
+ Fixed indent problems.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2009-04-18 19:54:33 +0200 Stephan Bosch <stephan@rename-it.nl> (798f2181)
+
+ Released v0.1.5 for Dovecot v1.2.rc3.
+
+
+M NEWS
+M configure.in
+
+2009-04-18 10:15:24 +0200 Stephan Bosch <stephan@rename-it.nl> (55414588)
+
+ Increased binary version number.
+
+
+M src/lib-sieve/sieve-binary.c
+
+2009-04-18 10:10:21 +0200 Stephan Bosch <stephan@rename-it.nl> (d76b84ac)
+
+ Improved error message for unknown Sieve extension to account for core
+ commands included as an extension.
+
+
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M tests/compile/errors.svtest
+M tests/compile/errors/require.sieve
+
+2009-04-14 18:54:17 +0200 Stephan Bosch <stephan@rename-it.nl> (35608790)
+
+ Fixed bug in the Sieve plugin's return value that caused omission of
+ delivery when no Sieve scripts are present. Bug spotted by Matthijs
+ Kooijman.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-04-13 23:18:11 +0200 Stephan Bosch <stephan@rename-it.nl> (abe5e27a)
+
+ Environment: fixed compiler warning.
+
+
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+
+2009-04-13 21:31:39 +0200 Stephan Bosch <stephan@rename-it.nl> (27dc5d4c)
+
+ Updated NEWS file for upcoming v1.2 release.
+
+
+M NEWS
+
+2009-04-13 21:30:00 +0200 Stephan Bosch <stephan@rename-it.nl> (b6ee35f9)
+
+ Testsuite: forgot to add new testcase file.
+
+
+A tests/extensions/environment/rfc.svtest
+
+2009-04-12 15:01:45 +0200 Stephan Bosch <stephan@rename-it.nl> (27317986)
+
+ Environment: fixed segfault and fixed some rfc deviations.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/tst-environment.c
+
+2009-04-12 14:10:40 +0200 Stephan Bosch <stephan@rename-it.nl> (a87632e2)
+
+ Environment: activated host environment item.
+
+
+M src/lib-sieve/plugins/environment/ext-environment-common.c
+M src/lib-sieve/plugins/environment/sieve-ext-environment.h
+M src/testsuite/testsuite.c
+M tests/extensions/environment/basic.svtest
+
+2009-04-12 12:09:18 +0200 Stephan Bosch <stephan@rename-it.nl> (dfc1ce09)
+
+ Implemented core support for the environment extension.
+
+
+M Makefile.am
+M TODO
+M configure.in
+A doc/rfc/environment.rfc5183.txt
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/environment/Makefile.am
+A src/lib-sieve/plugins/environment/ext-environment-common.c
+A src/lib-sieve/plugins/environment/ext-environment-common.h
+A src/lib-sieve/plugins/environment/ext-environment.c
+A src/lib-sieve/plugins/environment/sieve-ext-environment.h
+A src/lib-sieve/plugins/environment/tst-environment.c
+M src/lib-sieve/sieve-extensions.c
+A tests/extensions/environment/basic.svtest
+
+2009-04-11 00:10:37 +0200 Stephan Bosch <stephan@rename-it.nl> (a8380918)
+
+ Include: added various tests to the testsuite.
+
+
+M Makefile.am
+A tests/extensions/include/included-global/rfc-ex1-spam_tests.sieve
+A tests/extensions/include/included/rfc-ex1-always_allow.sieve
+A tests/extensions/include/included/rfc-ex1-mailing_lists.sieve
+A tests/extensions/include/included/rfc-ex1-spam_tests.sieve
+A tests/extensions/include/included/rfc-ex2-spam_filter_script.sieve
+A tests/extensions/include/included/twice-1.sieve
+A tests/extensions/include/included/twice-2.sieve
+A tests/extensions/include/rfc-ex1-default.sieve
+A tests/extensions/include/rfc-ex2-default.sieve
+A tests/extensions/include/rfc.svtest
+A tests/extensions/include/twice.svtest
+
+2009-04-11 00:10:00 +0200 Stephan Bosch <stephan@rename-it.nl> (89baff27)
+
+ Include: fixed bug in binary save of global variable scope.
+
+
+M src/lib-sieve/plugins/include/ext-include-variables.c
+
+2009-04-10 23:30:15 +0200 Stephan Bosch <stephan@rename-it.nl> (538adede)
+
+ Include: implemented :once modifier for the include command.
+
+
+M Makefile.am
+M README
+M TODO
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+M tests/extensions/include/included/once-2.sieve
+A tests/extensions/include/included/once-3.sieve
+A tests/extensions/include/included/once-4.sieve
+M tests/extensions/include/once.svtest
+
+2009-04-10 23:15:51 +0200 Stephan Bosch <stephan@rename-it.nl> (d8d0f6f6)
+
+ Testsuite: fixed minor result passing problem in test code generation.
+
+
+M src/testsuite/cmd-test.c
+
+2009-04-10 20:27:18 +0200 Stephan Bosch <stephan@rename-it.nl> (f91b1ee6)
+
+ Include: improved runtime script handling.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2009-04-10 19:30:01 +0200 Stephan Bosch <stephan@rename-it.nl> (fa900dea)
+
+ Include: added runtime check for circular include.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2009-04-10 19:19:46 +0200 Stephan Bosch <stephan@rename-it.nl> (59192a4e)
+
+ Fixed a few small indent problems.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2009-04-10 19:16:07 +0200 Stephan Bosch <stephan@rename-it.nl> (47ce4d8c)
+
+ Include: added skeleton :once modifier.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/sieve-binary-dumper.c
+A tests/extensions/include/included/once-1.sieve
+A tests/extensions/include/included/once-2.sieve
+A tests/extensions/include/once.svtest
+
+2009-04-10 19:11:54 +0200 Stephan Bosch <stephan@rename-it.nl> (0c984f4c)
+
+ Include: fixed bug in sub-sub include.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2009-04-10 19:10:25 +0200 Stephan Bosch <stephan@rename-it.nl> (768bc087)
+
+ Fixed warnings in revised plugin code.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-04-10 17:39:10 +0200 Stephan Bosch <stephan@rename-it.nl> (0b247829)
+
+ Minor update to the sieve-test manpage
+
+
+M doc/man/sieve-test.1
+
+2009-04-10 15:29:01 +0200 Stephan Bosch <stephan@rename-it.nl> (f7de6816)
+
+ Include: updated implementation status.
+
+
+M README
+M src/lib-sieve/plugins/include/ext-include.c
+
+2009-04-10 15:26:01 +0200 Stephan Bosch <stephan@rename-it.nl> (e8eb2131)
+
+ Replaced include specification with latest draft.
+
+
+D doc/rfc/draft-daboo-sieve-include-05.txt
+A doc/rfc/draft-ietf-sieve-include-01.txt
+
+2009-04-10 15:24:48 +0200 Stephan Bosch <stephan@rename-it.nl> (528faeeb)
+
+ Include: replaced import/export commands with global command as specified in
+ latest draft. Import/export are now DEPRICATED.
+
+
+M src/lib-sieve/plugins/include/Makefile.am
+R067 src/lib-sieve/plugins/include/cmd-import.c src/lib-sieve/plugins/include/cmd-global.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+M tests/extensions/include/errors.svtest
+D tests/extensions/include/errors/import-runtime.sieve
+M tests/extensions/include/errors/variables-inactive.sieve
+M tests/extensions/include/errors/variables.sieve
+M tests/extensions/include/included/variables-included1.sieve
+M tests/extensions/include/included/variables-included2.sieve
+M tests/extensions/include/included/variables-included3.sieve
+M tests/extensions/include/variables.svtest
+
+2009-04-10 14:13:35 +0200 Stephan Bosch <stephan@rename-it.nl> (bece6db9)
+
+ Definitively fixed handling group specifications in mailbox lists of address
+ headers.
+
+
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/sieve-address-parts.c
+M tests/address.svtest
+M tests/extensions/subaddress/basic.svtest
+
+2009-04-10 02:37:34 +0200 Stephan Bosch <stephan@rename-it.nl> (1a998318)
+
+ Fixed minor typo in sieve-test man page.
+
+
+M doc/man/sieve-test.1
+
+2009-04-10 01:27:22 +0200 Stephan Bosch <stephan@rename-it.nl> (50a63dd8)
+
+ Updated TODO.
+
+
+M TODO
+
+2009-04-10 00:56:15 +0200 Stephan Bosch <stephan@rename-it.nl> (e6379fcc)
+
+ Major rework of the multiscript support for better error handling.
+
+
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+
+2009-04-09 01:14:42 +0200 Stephan Bosch <stephan@rename-it.nl> (a7d63599)
+
+ Improved plugin debug message.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-04-08 18:56:40 +0200 Stephan Bosch <stephan@rename-it.nl> (c61d3920)
+
+ Fixed problem of unexecuted before/after global scripts when user script is
+ missing.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-04-07 00:05:55 +0200 Stephan Bosch <stephan@rename-it.nl> (72d99bb2)
+
+ Adjusted to signal handler API changes in Dovecot.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+
+2009-04-06 00:40:03 +0200 Stephan Bosch <stephan@rename-it.nl> (4a46ebdb)
+
+ Fixed segfault bug caused by undisclosed-recipients:; when fed to the
+ subaddress extension.
+
+
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/sieve-address-parts.c
+
+2009-03-21 15:56:27 +0100 Stephan Bosch <stephan@rename-it.nl> (77282a29)
+
+ Added tag 0.1.4 for changeset b7eb19f14fa7
+
+
+2009-03-21 15:56:15 +0100 Stephan Bosch <stephan@rename-it.nl> (1dd42d50)
+
+ Released v0.1.4 for Dovecot v1.2.beta3.
+
+
+M NEWS
+M configure.in
+
+2009-03-20 20:00:38 +0100 Stephan Bosch <stephan@rename-it.nl> (f8e708b6)
+
+ Documented vnd.dovecot.debug in the sieve-test man page.
+
+
+M doc/man/sieve-test.1
+
+2009-03-20 19:47:38 +0100 Stephan Bosch <stephan@rename-it.nl> (67e76294)
+
+ Updated NEWS file.
+
+
+M NEWS
+
+2009-03-20 19:30:37 +0100 Stephan Bosch <stephan@rename-it.nl> (3d4541e6)
+
+ Improved error handling and added debug extension to all applicable Sieve
+ tools.
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/sieve-tools/sieve-filter.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/sieve-tools/sieved.c
+
+2009-03-14 19:21:21 +0100 Stephan Bosch <stephan@rename-it.nl> (3f6045df)
+
+ Created replaceable error handler for system errors.
+
+
+M NEWS
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+
+2009-03-14 18:15:39 +0100 Stephan Bosch <stephan@rename-it.nl> (720ef3aa)
+
+ Added Dovecot-specific debug extension to the sieve-test tool.
+
+
+M TODO
+M configure.in
+M src/sieve-tools/Makefile.am
+A src/sieve-tools/debug/Makefile.am
+A src/sieve-tools/debug/cmd-debug-print.c
+A src/sieve-tools/debug/ext-debug-common.h
+A src/sieve-tools/debug/ext-debug.c
+A src/sieve-tools/debug/sieve-ext-debug.h
+M src/sieve-tools/sieve-test.c
+
+2009-03-14 17:07:27 +0100 Stephan Bosch <stephan@rename-it.nl> (b9cd2210)
+
+ Sieve-filter: implemented basic filtering.
+
+
+M TODO
+M src/sieve-tools/sieve-filter.c
+
+2009-03-05 20:39:56 +0100 Stephan Bosch <stephan@rename-it.nl> (8ed87679)
+
+ Removed unnecessary linker flags that break Solaris compilation.
+
+
+M src/sieve-tools/Makefile.am
+M src/testsuite/Makefile.am
+
+2009-02-24 13:56:46 +0100 Stephan Bosch <stephan@rename-it.nl> (d8696f98)
+
+ Fixed MAC OSX compile problems: forgot extern modifier at various places.
+
+
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+
+2009-02-23 22:06:58 +0100 Stephan Bosch <stephan@rename-it.nl> (27eff17b)
+
+ Fixed issue with opening relative paths as a mail file.
+
+
+M src/lib-sieve-tool/mail-raw.c
+
+2009-02-23 18:41:34 +0100 Stephan Bosch <stephan@rename-it.nl> (77844c3f)
+
+ Fixed tmp file name for raw storage used for sieve tools.
+
+
+M src/lib-sieve-tool/mail-raw.c
+
+2009-02-19 19:35:32 +0100 Stephan Bosch <stephan@rename-it.nl> (8a946c8a)
+
+ Updated TODO.
+
+
+M TODO
+
+2009-02-19 19:31:32 +0100 Stephan Bosch <stephan@rename-it.nl> (8a09768f)
+
+ Removed inappropriate ACAP rfc for i;ascii-numeric comparator and
+ substituted rfc4790 in stead.
+
+
+A doc/rfc/collation.rfc4790.txt
+D doc/rfc/i-ascii-numeric.rfc2244.txt
+
+2009-02-15 14:10:55 +0100 Stephan Bosch <stephan@rename-it.nl> (32456894)
+
+ Sieve-filter: developed listing messages in a folder a little further.
+
+
+M src/sieve-tools/sieve-filter.c
+
+2009-02-15 13:17:52 +0100 Stephan Bosch <stephan@rename-it.nl> (280b3158)
+
+ Started work on sieve-filter tool.
+
+
+M .hgignore
+M src/sieve-tools/Makefile.am
+A src/sieve-tools/sieve-filter.c
+
+2009-02-14 10:10:56 +0100 Stephan Bosch <stephan@rename-it.nl> (31e29a26)
+
+ Testsuite: added a few final important tests for the enotify extension.
+
+
+M TODO
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-validator.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M tests/extensions/enotify/mailto.svtest
+
+2009-02-13 00:19:43 +0100 Stephan Bosch <stephan@rename-it.nl> (a877a6b5)
+
+ Added tag 0.1.3 for changeset 8bdff47ab3f0
+
+
+2009-02-13 00:19:36 +0100 Stephan Bosch <stephan@rename-it.nl> (d6e7b70f)
+
+ Released v0.1.3 for Dovecot v1.2.beta1.
+
+
+M configure.in
+
+2009-02-12 22:19:39 +0100 Stephan Bosch <stephan@rename-it.nl> (d3afdf0c)
+
+ Added items to the TODO list.
+
+
+M TODO
+
+2009-02-12 22:02:27 +0100 Stephan Bosch <stephan@rename-it.nl> (54155f42)
+
+ Minor changes to the sievec man page.
+
+
+M doc/man/sievec.1
+
+2009-02-12 21:07:58 +0100 Stephan Bosch <stephan@rename-it.nl> (49fd5448)
+
+ Saved binary now has at most the same permissions as the script file itself.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+
+2009-02-12 01:14:52 +0100 Stephan Bosch <stephan@rename-it.nl> (882e35b3)
+
+ Fixed bug the code generation of extensions.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-extensions.c
+
+2009-02-12 01:14:14 +0100 Stephan Bosch <stephan@rename-it.nl> (8da93e37)
+
+ Added -x parameter to sieved tool.
+
+
+M doc/man/sieved.1
+M src/sieve-tools/sieved.c
+
+2009-02-11 23:22:34 +0100 Stephan Bosch <stephan@rename-it.nl> (f42e9d1b)
+
+ Fixed small bug in the extension validation.
+
+
+M src/lib-sieve/sieve-validator.c
+
+2009-02-11 22:39:48 +0100 Stephan Bosch <stephan@rename-it.nl> (79ea9888)
+
+ Imapflags: marked as depricated and disabled by default.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2009-02-11 22:35:59 +0100 Stephan Bosch <stephan@rename-it.nl> (9b109792)
+
+ Properly implemented verification of loaded extensions after last require
+ command is validated.
+
+
+M src/lib-sieve/sieve-validator.c
+
+2009-02-11 22:35:24 +0100 Stephan Bosch <stephan@rename-it.nl> (7455ba6b)
+
+ Testsuite: added small test for ?* match values.
+
+
+M tests/extensions/variables/match.svtest
+
+2009-02-11 22:10:14 +0100 Stephan Bosch <stephan@rename-it.nl> (f915a0c9)
+
+ Updated NEWS file for next release.
+
+
+M NEWS
+
+2009-02-08 18:21:26 +0100 Stephan Bosch <stephan@rename-it.nl> (1fa1740c)
+
+ Testsuite: added message tests for the vacation extension.
+
+
+M Makefile.am
+A tests/extensions/vacation/message.svtest
+D tests/extensions/vacation/references.svtest
+
+2009-02-08 18:06:46 +0100 Stephan Bosch <stephan@rename-it.nl> (2aad47e4)
+
+ Testsuite: added support for resetting the result.
+
+
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/testsuite/Makefile.am
+A src/testsuite/cmd-test-result-reset.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+M src/testsuite/tst-test-script-run.c
+M tests/extensions/enotify/mailto.svtest
+
+2009-02-08 00:32:47 +0100 Stephan Bosch <stephan@rename-it.nl> (8488591c)
+
+ Testsuite: added tests for enotify with multiple recipients.
+
+
+M tests/extensions/enotify/mailto.svtest
+
+2009-02-08 00:10:26 +0100 Stephan Bosch <stephan@rename-it.nl> (a6a59602)
+
+ Testsuite: added support for looping back outgoing SMTP messages back into
+ the test.
+
+
+M Makefile.am
+M TODO
+M src/lib-sieve/plugins/include/cmd-import.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/tst-size.c
+M src/testsuite/Makefile.am
+A src/testsuite/cmd-test-message.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-message.c
+M src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-smtp.c
+M src/testsuite/testsuite-smtp.h
+M src/testsuite/tst-test-result-execute.c
+A tests/extensions/enotify/mailto.svtest
+
+2009-02-07 18:26:50 +0100 Stephan Bosch <stephan@rename-it.nl> (3f573f87)
+
+ Defined very basic function for address comparison.
+
+
+M TODO
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+
+2009-02-07 00:44:59 +0100 Stephan Bosch <stephan@rename-it.nl> (acb82aab)
+
+ Adjusted store action to API changes in Dovecot.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2009-02-06 18:28:47 +0100 Stephan Bosch <stephan@rename-it.nl> (31bc8a9f)
+
+ Vacation: made addresses comparison case-insensitive.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-address.c
+M tests/extensions/vacation/execute/action.sieve
+
+2009-02-05 00:24:29 +0100 Stephan Bosch <stephan@rename-it.nl> (741b295b)
+
+ Updated documentation.
+
+
+M README
+
+2009-02-05 00:21:29 +0100 Stephan Bosch <stephan@rename-it.nl> (214d41be)
+
+ Imap4flags: fixed dumping of \flagged flag in flags side effect.
+
+
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M tests/extensions/imap4flags/execute/imapflags.sieve
+
+2009-02-05 00:17:28 +0100 Stephan Bosch <stephan@rename-it.nl> (87c64daf)
+
+ Imap4flags: added support for obsolete imapflags extension for backwards
+ compatibility with CMUSieve.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/imap4flags/Makefile.am
+A src/lib-sieve/plugins/imap4flags/ext-imapflags.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-validator.c
+M src/testsuite/testsuite.c
+A tests/extensions/imap4flags/errors.svtest
+A tests/extensions/imap4flags/errors/imapflags.sieve
+A tests/extensions/imap4flags/execute/imapflags.sieve
+
+2009-02-04 22:43:33 +0100 Stephan Bosch <stephan@rename-it.nl> (a4176570)
+
+ Validator: added support for checking loaded extensions.
+
+
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+
+2009-02-04 22:13:48 +0100 Stephan Bosch <stephan@rename-it.nl> (06949d2b)
+
+ Added facilities for requiring extensions and making extensions mutually
+ exclusive.
+
+
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+
+2009-02-04 21:32:17 +0100 Stephan Bosch <stephan@rename-it.nl> (542e9489)
+
+ Imap4flags: gave testsuite directory proper name.
+
+
+M Makefile.am
+R100 tests/extensions/imapflags/basic.svtest tests/extensions/imap4flags/basic.svtest
+R100 tests/extensions/imapflags/execute.svtest tests/extensions/imap4flags/execute.svtest
+R100 tests/extensions/imapflags/execute/flags-side-effect.sieve tests/extensions/imap4flags/execute/flags-side-effect.sieve
+R100 tests/extensions/imapflags/hasflag.svtest tests/extensions/imap4flags/hasflag.svtest
+
+2009-02-04 20:24:43 +0100 Stephan Bosch <stephan@rename-it.nl> (0e048ed6)
+
+ Imap4flags: properly named extension objects.
+
+
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+M src/lib-sieve/sieve-extensions.c
+
+2009-02-04 20:18:13 +0100 Stephan Bosch <stephan@rename-it.nl> (aa8eb737)
+
+ Imap4flags: properly named functions.
+
+
+M src/lib-sieve/plugins/imap4flags/cmd-flag.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+M src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+M src/lib-sieve/plugins/imap4flags/tag-flags.c
+M src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+
+2009-02-04 19:59:56 +0100 Stephan Bosch <stephan@rename-it.nl> (c051208b)
+
+ Imap4flags: properly named extension directory and source files.
+
+
+M configure.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+R066 src/lib-sieve/plugins/imapflags/Makefile.am src/lib-sieve/plugins/imap4flags/Makefile.am
+R099 src/lib-sieve/plugins/imapflags/cmd-flag.c src/lib-sieve/plugins/imap4flags/cmd-flag.c
+R099 src/lib-sieve/plugins/imapflags/ext-imapflags-common.c src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
+R097 src/lib-sieve/plugins/imapflags/ext-imapflags-common.h src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
+R098 src/lib-sieve/plugins/imapflags/ext-imapflags.c src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+R099 src/lib-sieve/plugins/imapflags/tag-flags.c src/lib-sieve/plugins/imap4flags/tag-flags.c
+R099 src/lib-sieve/plugins/imapflags/tst-hasflag.c src/lib-sieve/plugins/imap4flags/tst-hasflag.c
+
+2009-02-03 21:06:34 +0100 Stephan Bosch <stephan@rename-it.nl> (bd16e831)
+
+ Fixed README: now mentions the naming differences of the imap4flags and
+ enotify extensions compared to the old CMU Sieve plugin.
+
+
+M README
+
+2009-02-02 11:03:07 +0100 Stephan Bosch <stephan@rename-it.nl> (e54e3922)
+
+ Fixed compile warning caused by missing include.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2009-02-01 19:49:03 +0100 Stephan Bosch <stephan@rename-it.nl> (448d8db5)
+
+ Installed RFC documents for notify extension and corresponding mailto
+ method.
+
+
+D doc/rfc/draft-ietf-sieve-notify-12.txt
+R051 doc/rfc/draft-ietf-sieve-notify-mailto-10.txt doc/rfc/notify-mailto.rfc5436.txt
+A doc/rfc/notify.rfc5435.txt
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2009-02-01 14:06:47 +0100 Stephan Bosch <stephan@rename-it.nl> (97c1dc8d)
+
+ Cleaned up :matches match-type code.
+
+
+M src/lib-sieve/mcht-matches.c
+M tests/match-types/matches.svtest
+
+2009-02-01 13:30:11 +0100 Stephan Bosch <stephan@rename-it.nl> (8d4f5015)
+
+ Fixed bug in the :matches match type.
+
+
+M src/lib-sieve/mcht-matches.c
+M tests/match-types/matches.svtest
+
+2009-01-27 17:19:22 +0100 Stephan Bosch <stephan@rename-it.nl> (ab6177dd)
+
+ Added important TODO item.
+
+
+M TODO
+
+2009-01-27 10:54:31 +0100 Stephan Bosch <stephan@rename-it.nl> (826c4ef8)
+
+ Changed SMTP message generation back to CRLF, because the Sieve engine uses
+ CRLF internally.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/rfc2822.c
+
+2009-01-27 00:32:20 +0100 Stephan Bosch <stephan@rename-it.nl> (8e33424b)
+
+ Fixed use of data stack by binary dumping code.
+
+
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code.c
+
+2009-01-27 00:31:57 +0100 Stephan Bosch <stephan@rename-it.nl> (37ed7849)
+
+ Regex: fixed segfault bug occuring when regex is freed.
+
+
+M src/lib-sieve/plugins/regex/mcht-regex.c
+
+2009-01-27 00:31:05 +0100 Stephan Bosch <stephan@rename-it.nl> (6b604fd1)
+
+ Testsuite: fixed warning.
+
+
+M src/testsuite/tst-test-script-compile.c
+
+2009-01-27 00:30:43 +0100 Stephan Bosch <stephan@rename-it.nl> (286d42d4)
+
+ Increased various initial pool sizes.
+
+
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-validator.c
+
+2009-01-26 23:21:36 +0100 Stephan Bosch <stephan@rename-it.nl> (d4bc6cce)
+
+ Increased initial size of binary's lazy_file pool.
+
+
+M src/lib-sieve/sieve-binary.c
+
+2009-01-26 22:58:30 +0100 Stephan Bosch <stephan@rename-it.nl> (cc9ea513)
+
+ Fixed error in the SMTP message composition that caused mixing of CRLF and
+ LF in redirected messages.
+
+
+M src/lib-sieve/rfc2822.c
+
+2009-01-22 23:17:06 +0100 Stephan Bosch <stephan@rename-it.nl> (751e4095)
+
+ Updated NEWS file.
+
+
+M NEWS
+
+2009-01-22 23:16:30 +0100 Stephan Bosch <stephan@rename-it.nl> (dbadda3a)
+
+ Updated NEWS file.
+
+
+M NEWS
+
+2009-01-22 22:02:30 +0100 Stephan Bosch <stephan@rename-it.nl> (7527d467)
+
+ Updated README file.
+
+
+M README
+
+2009-01-22 21:55:27 +0100 Stephan Bosch <stephan@rename-it.nl> (8687fe89)
+
+ Prepared NEWS file for next release.
+
+
+M NEWS
+
+2009-01-22 20:43:52 +0100 Stephan Bosch <stephan@rename-it.nl> (6d2522d0)
+
+ Updated documentation.
+
+
+M INSTALL
+
+2009-01-22 00:20:10 +0100 Stephan Bosch <stephan@rename-it.nl> (cf33f358)
+
+ Testsuite: added simple tests for the match values produced by the :regex
+ match.
+
+
+M Makefile.am
+A tests/extensions/regex/match-values.svtest
+
+2009-01-22 00:19:41 +0100 Stephan Bosch <stephan@rename-it.nl> (8fa2ee03)
+
+ Regex: fixed bug in the match value indexes.
+
+
+M src/lib-sieve/plugins/regex/mcht-regex.c
+
+2009-01-18 17:52:40 +0100 Stephan Bosch <stephan@rename-it.nl> (2919e2d0)
+
+ Added multiscript draft to the doc/rfc directory.
+
+
+A doc/rfc/draft-degener-sieve-multiscript-00.txt
+
+2009-01-18 17:32:15 +0100 Stephan Bosch <stephan@rename-it.nl> (bfbd7d01)
+
+ Testsuite: added storage of outgoing SMTP messages.
+
+
+M src/testsuite/Makefile.am
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-message.c
+A src/testsuite/testsuite-smtp.c
+A src/testsuite/testsuite-smtp.h
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-script-run.c
+
+2009-01-18 14:07:46 +0100 Stephan Bosch <stephan@rename-it.nl> (fc011a3e)
+
+ Testsuite: exported message handling to separate module.
+
+
+M src/testsuite/Makefile.am
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+A src/testsuite/testsuite-message.c
+A src/testsuite/testsuite-message.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite.c
+
+2009-01-16 19:56:15 +0100 Stephan Bosch <stephan@rename-it.nl> (b4e7dc74)
+
+ Enotify: cleaned up method API.
+
+
+M TODO
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2009-01-16 19:20:22 +0100 Stephan Bosch <stephan@rename-it.nl> (2f8711f9)
+
+ Testsuite: improved testsuite with respect to testing of setflag, addflag
+ and removeflag commands.
+
+
+M tests/extensions/imapflags/basic.svtest
+M tests/extensions/imapflags/hasflag.svtest
+
+2009-01-16 19:19:46 +0100 Stephan Bosch <stephan@rename-it.nl> (b9ba12b3)
+
+ Imap4flags: merged setflag, addflag and removeflag implementations.
+
+
+M TODO
+M src/lib-sieve/plugins/imapflags/Makefile.am
+D src/lib-sieve/plugins/imapflags/cmd-addflag.c
+A src/lib-sieve/plugins/imapflags/cmd-flag.c
+D src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+D src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+
+2009-01-16 18:32:12 +0100 Stephan Bosch <stephan@rename-it.nl> (3eb9eaed)
+
+ Added sieve_subaddress_sep setting.
+
+
+M INSTALL
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+
+2009-01-11 12:14:38 +0100 Stephan Bosch <stephan@rename-it.nl> (e46dea37)
+
+ Fixed bug in the outgoing mail address verification.
+
+
+M src/lib-sieve/sieve-address.c
+M tests/compile/errors.svtest
+M tests/compile/errors/out-address.sieve
+
+2009-01-11 11:56:13 +0100 Stephan Bosch <stephan@rename-it.nl> (7dab1255)
+
+ Enotify/Mailto: prevented single recipient from receiving multiple
+ notifications on the same message.
+
+
+M TODO
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M tests/extensions/enotify/execute.svtest
+M tests/extensions/enotify/execute/duplicates.sieve
+
+2009-01-11 11:53:13 +0100 Stephan Bosch <stephan@rename-it.nl> (5ef4fda9)
+
+ Testsuite: fixed segfault bugs in the error handling.
+
+
+M src/testsuite/testsuite.c
+
+2009-01-10 23:57:03 +0100 Stephan Bosch <stephan@rename-it.nl> (8c07be8e)
+
+ Small project status update to the README.
+
+
+M README
+
+2009-01-10 23:50:24 +0100 Stephan Bosch <stephan@rename-it.nl> (3f157f00)
+
+ Enotify: added API for detecting and killing duplicate notification
+ recipients.
+
+
+M TODO
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M tests/extensions/enotify/execute.svtest
+A tests/extensions/enotify/execute/duplicates.sieve
+
+2009-01-10 23:19:48 +0100 Stephan Bosch <stephan@rename-it.nl> (935133cc)
+
+ Multiscript: implemented sorting of script files in script directories for
+ Sieve plugin.
+
+
+M TODO
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-01-10 23:07:59 +0100 Stephan Bosch <stephan@rename-it.nl> (702921e7)
+
+ Updated documentation.
+
+
+M INSTALL
+M README
+M TODO
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-01-10 22:22:17 +0100 Stephan Bosch <stephan@rename-it.nl> (d60ea1a8)
+
+ Reprioritized TODO.
+
+
+M TODO
+
+2009-01-10 21:54:06 +0100 Stephan Bosch <stephan@rename-it.nl> (a48cf926)
+
+ Got array_get_pool() integrated into Dovecot.
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2009-01-10 21:14:50 +0100 Stephan Bosch <stephan@rename-it.nl> (ac14b30e)
+
+ Updated documentation.
+
+
+M README
+M TODO
+
+2009-01-10 20:37:42 +0100 Stephan Bosch <stephan@rename-it.nl> (d5c70708)
+
+ Fixed segfault in lda sieve plugin.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2009-01-10 19:28:28 +0100 Stephan Bosch <stephan@rename-it.nl> (b54aac45)
+
+ Enotify/Mailto: fixed bug in the generation of the SMTP envelope sender.
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2009-01-10 19:18:13 +0100 Stephan Bosch <stephan@rename-it.nl> (77eb7de3)
+
+ Enotify: fixed various indent mishaps in ntfy-mailto.c.
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2009-01-10 19:15:05 +0100 Stephan Bosch <stephan@rename-it.nl> (5c0e1898)
+
+ Multiscript: added untested multiscript support to the lda sieve plugin.
+
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+
+2009-01-09 21:37:37 +0100 Stephan Bosch <stephan@rename-it.nl> (a301c3c1)
+
+ Added a few accessors to the binary object for convenience.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+
+2009-01-09 21:37:03 +0100 Stephan Bosch <stephan@rename-it.nl> (a69ec7dd)
+
+ Testsuite: fixed warning.
+
+
+M src/testsuite/testsuite.c
+
+2009-01-09 02:31:19 +0100 Stephan Bosch <stephan@rename-it.nl> (37288bc4)
+
+ Testsuite: fixed result handling.
+
+
+M src/testsuite/testsuite.c
+
+2009-01-09 01:37:28 +0100 Stephan Bosch <stephan@rename-it.nl> (b4a41703)
+
+ Removed remaining references to sieve-exec.
+
+
+M TODO
+
+2009-01-07 01:14:05 +0100 Stephan Bosch <stephan@rename-it.nl> (b3f7c89e)
+
+ Extended sievec command to allow compiling an entire directory.
+
+
+M doc/man/sievec.1
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite.c
+
+2009-01-06 23:42:30 +0100 Stephan Bosch <stephan@rename-it.nl> (c9ae3e44)
+
+ Minor revisions to the sieved man page.
+
+
+M doc/man/sieved.1
+
+2009-01-06 23:40:00 +0100 Stephan Bosch <stephan@rename-it.nl> (e1c090fe)
+
+ Made outfile argument of the sievec command optional.
+
+
+M doc/man/sievec.1
+M src/sieve-tools/sievec.c
+
+2009-01-06 23:16:32 +0100 Stephan Bosch <stephan@rename-it.nl> (338121cb)
+
+ Updated README.
+
+
+M README
+
+2009-01-06 22:48:48 +0100 Stephan Bosch <stephan@rename-it.nl> (1e538582)
+
+ Merged sieve-exec tool into sieve-test.
+
+
+M doc/man/sieve-test.1
+M doc/man/sievec.1
+M doc/man/sieved.1
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve.c
+M src/sieve-tools/Makefile.am
+D src/sieve-tools/sieve-exec.c
+M src/sieve-tools/sieve-test.c
+
+2009-01-06 01:30:55 +0100 Stephan Bosch <stephan@rename-it.nl> (3792833c)
+
+ Fixed various result error messages.
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2009-01-06 00:28:56 +0100 Stephan Bosch <stephan@rename-it.nl> (f75b4a61)
+
+ Fixed a theoretical security hole occuring when directory is opened as a
+ Sieve binary.
+
+
+M src/lib-sieve/sieve-binary.c
+
+2009-01-04 19:17:14 +0100 Stephan Bosch <stephan@rename-it.nl> (8763c8d1)
+
+ Updated TODO.
+
+
+M TODO
+M src/sieve-tools/sieve-test.c
+
+2009-01-04 18:08:23 +0100 Stephan Bosch <stephan@rename-it.nl> (d717b880)
+
+ Multiscript: fixed small bug in result printing.
+
+
+M src/lib-sieve/sieve-result.c
+M src/sieve-tools/sieve-test.c
+
+2009-01-04 17:54:12 +0100 Stephan Bosch <stephan@rename-it.nl> (11eb119a)
+
+ Multiscript: improved handling of the keep action.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/sieve-tools/sieve-test.c
+
+2009-01-04 01:00:50 +0100 Stephan Bosch <stephan@rename-it.nl> (82d7857b)
+
+ Updated TODO.
+
+
+M TODO
+
+2009-01-04 00:55:07 +0100 Stephan Bosch <stephan@rename-it.nl> (bcbb3217)
+
+ Multiscript: implemented execution of multiple scripts for the sieve-test
+ command.
+
+
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/sieve-tools/sieve-test.c
+
+2009-01-03 21:54:29 +0100 Stephan Bosch <stephan@rename-it.nl> (9f5a9b7c)
+
+ Multiscript: implemented API.
+
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+
+2009-01-03 20:26:41 +0100 Stephan Bosch <stephan@rename-it.nl> (8c269b44)
+
+ Multiscript: various changes to the interpreter to facilitate multiscript
+ support.
+
+
+M doc/man/sieve-test.1
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-exec.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite.c
+
+2009-01-02 23:23:06 +0100 Stephan Bosch <stephan@rename-it.nl> (92a22a1a)
+
+ Multiscript: added keep status evaluation to result object.
+
+
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2009-01-02 22:57:51 +0100 Stephan Bosch <stephan@rename-it.nl> (1d773826)
+
+ Updated copyright messages to 2009.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/mail-raw.h
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve-tool/sieve-tool.h
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/cmd-stop.c
+M src/lib-sieve/cmp-i-ascii-casemap.c
+M src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify-limits.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-import.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-limits.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/rfc2822.c
+M src/lib-sieve/rfc2822.h
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-limits.c
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/lib-sieve/tst-truefalse.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.h
+M src/sieve-tools/sieve-exec.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+M src/sieve-tools/sieved.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-result-print.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-arguments.c
+M src/testsuite/testsuite-arguments.h
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-log.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+M src/testsuite/testsuite-script.c
+M src/testsuite/testsuite-script.h
+M src/testsuite/testsuite-substitutions.c
+M src/testsuite/testsuite-substitutions.h
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-error.c
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-result.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+
+2009-01-02 21:48:57 +0100 Stephan Bosch <stephan@rename-it.nl> (60a4708a)
+
+ Testsuite: extended multiscript testing.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve.c
+M src/testsuite/testsuite-result.c
+M tests/multiscript/conflicts.svtest
+A tests/multiscript/fileinto-frop.sieve
+A tests/multiscript/keep.sieve
+
+2009-01-02 14:51:03 +0100 Stephan Bosch <stephan@rename-it.nl> (3285d7b9)
+
+ Testsuite: added multiscript tests and required support.
+
+
+M Makefile.am
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/testsuite/Makefile.am
+A src/testsuite/cmd-test-result-print.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-log.c
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+M src/testsuite/tst-test-result-execute.c
+M src/testsuite/tst-test-script-compile.c
+M src/testsuite/tst-test-script-run.c
+A tests/multiscript/basic.svtest
+A tests/multiscript/conflicts.svtest
+A tests/multiscript/fileinto-inbox.sieve
+A tests/multiscript/notify.sieve
+A tests/multiscript/reject-1.sieve
+A tests/multiscript/reject-2.sieve
+A tests/multiscript/vacation.sieve
+
+2009-01-02 14:12:33 +0100 Stephan Bosch <stephan@rename-it.nl> (0d907631)
+
+ Enotify: removed conflicting action flag.
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+
+2009-01-02 14:11:27 +0100 Stephan Bosch <stephan@rename-it.nl> (1cdc4fab)
+
+ Testsuite: forgot to add new files.
+
+
+A src/testsuite/testsuite-log.c
+A src/testsuite/testsuite-log.h
+A src/testsuite/testsuite-script.c
+A src/testsuite/testsuite-script.h
+
+2009-01-02 12:35:13 +0100 Stephan Bosch <stephan@rename-it.nl> (bff1bf54)
+
+ Testsuite: split off script and error handler implementations into separate
+ modules.
+
+
+M src/testsuite/Makefile.am
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-result.c
+M src/testsuite/tst-test-error.c
+M tests/extensions/enotify/basic.svtest
+
+2009-01-01 22:27:19 +0100 Stephan Bosch <stephan@rename-it.nl> (3c46a10a)
+
+ Fixed warning caused by previous changes.
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+
+2009-01-01 19:37:26 +0100 Stephan Bosch <stephan@rename-it.nl> (6cdfe4f4)
+
+ Multiscript: resolved inter-script action conflict situations.
+
+
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-result.c
+
+2009-01-01 19:14:40 +0100 Stephan Bosch <stephan@rename-it.nl> (643e8901)
+
+ Cleaned up action interface.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+
+2009-01-01 18:12:08 +0100 Stephan Bosch <stephan@rename-it.nl> (4a2e1f72)
+
+ Multiscript: adjusted result object for sequential execution.
+
+
+M TODO
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/testsuite/tst-test-result.c
+M tests/execute/actions.svtest
+M tests/extensions/vacation/execute.svtest
+
+2008-12-29 17:32:34 +0100 Stephan Bosch <stephan@rename-it.nl> (a5744734)
+
+ Updated TODO.
+
+
+M TODO
+
+2008-12-28 21:09:49 +0100 Stephan Bosch <stephan@rename-it.nl> (b73e9222)
+
+ Testsuite: added basic result execution tests for various extensions.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-result.c
+M src/testsuite/testsuite-result.c
+M tests/execute/actions.svtest
+M tests/extensions/imapflags/execute.svtest
+M tests/extensions/reject/execute.svtest
+M tests/extensions/vacation/execute.svtest
+
+2008-12-28 20:00:26 +0100 Stephan Bosch <stephan@rename-it.nl> (84b5f74b)
+
+ Testsuite: added support for executing results.
+
+
+M src/lib-sieve/sieve-result.h
+M src/testsuite/Makefile.am
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-result.c
+M src/testsuite/testsuite-result.h
+A src/testsuite/tst-test-result-execute.c
+M tests/extensions/enotify/execute.svtest
+
+2008-12-28 18:49:06 +0100 Stephan Bosch <stephan@rename-it.nl> (0e272ca2)
+
+ Testsuite: forgot committing rename in previous commit.
+
+
+R074 src/testsuite/tst-test-compile.c src/testsuite/tst-test-script-compile.c
+R065 src/testsuite/tst-test-execute.c src/testsuite/tst-test-script-run.c
+
+2008-12-28 18:47:27 +0100 Stephan Bosch <stephan@rename-it.nl> (09137580)
+
+ Testsuite: renamed script compile and run commands to be more intuitive.
+
+
+M src/testsuite/Makefile.am
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/tst-test-result.c
+M tests/compile/compile.svtest
+M tests/compile/errors.svtest
+M tests/compile/examples.svtest
+M tests/execute/actions.svtest
+M tests/execute/errors.svtest
+M tests/extensions/enotify/errors.svtest
+M tests/extensions/enotify/execute.svtest
+M tests/extensions/imapflags/execute.svtest
+M tests/extensions/include/errors.svtest
+M tests/extensions/regex/errors.svtest
+M tests/extensions/reject/execute.svtest
+M tests/extensions/relational/errors.svtest
+M tests/extensions/vacation/errors.svtest
+M tests/extensions/vacation/execute.svtest
+M tests/extensions/variables/errors.svtest
+M tests/testsuite.svtest
+
+2008-12-28 18:06:38 +0100 Stephan Bosch <stephan@rename-it.nl> (27844839)
+
+ Testsuite: started implementing support for testsuite-specific string
+ substitutions.
+
+
+M src/lib-sieve/sieve-code.c
+M src/testsuite/Makefile.am
+M src/testsuite/ext-testsuite.c
+A src/testsuite/testsuite-arguments.c
+A src/testsuite/testsuite-arguments.h
+M src/testsuite/testsuite-common.h
+A src/testsuite/testsuite-substitutions.c
+A src/testsuite/testsuite-substitutions.h
+M tests/testsuite.svtest
+
+2008-12-28 13:37:18 +0100 Stephan Bosch <stephan@rename-it.nl> (d622ff1a)
+
+ Exported variable string argument into the Sieve engine itself as 'catenated
+ string' (for similar use in other extensions like the testsuite).
+
+
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+
+2008-12-28 12:21:09 +0100 Stephan Bosch <stephan@rename-it.nl> (9c996b7e)
+
+ Exported variable string operand into the Sieve engine itself as 'catenated
+ string' (for similar use in other extensions like the testsuite).
+
+
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+
+2008-12-28 01:56:48 +0100 Stephan Bosch <stephan@rename-it.nl> (0cd98756)
+
+ Updated TODO.
+
+
+M TODO
+
+2008-12-28 01:56:39 +0100 Stephan Bosch <stephan@rename-it.nl> (2d214818)
+
+ Enotify: mailto: forgot to add 'from' header to list of reserved headers.
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-12-28 01:49:39 +0100 Stephan Bosch <stephan@rename-it.nl> (48d8584d)
+
+ Updated TODO list.
+
+
+M TODO
+
+2008-12-28 01:48:32 +0100 Stephan Bosch <stephan@rename-it.nl> (124df196)
+
+ Enotify: added enotify extension to default compile.
+
+
+M Makefile.am
+M TODO
+M configure.in
+M dsieve-config.h.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+M src/lib-sieve/sieve-extensions.c
+
+2008-12-28 01:31:35 +0100 Stephan Bosch <stephan@rename-it.nl> (3023a857)
+
+ Enotify: mailto: enforced limits on number of recipients and headers.
+
+
+M TODO
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-12-28 00:48:17 +0100 Stephan Bosch <stephan@rename-it.nl> (9b5384db)
+
+ Enotify: mailto: finished URI parsing.
+
+
+M TODO
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M tests/extensions/enotify/errors.svtest
+M tests/extensions/enotify/errors/uri-mailto.sieve
+
+2008-12-27 23:57:52 +0100 Stephan Bosch <stephan@rename-it.nl> (18e89e3a)
+
+ Enotify: mailto: fixed various bugs introduced by previous enthousiastic
+ commit.
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-12-27 23:47:26 +0100 Stephan Bosch <stephan@rename-it.nl> (8e50743d)
+
+ Enotify: mailto: added check for duplicates of unique headers in the mailto
+ URI.
+
+
+M TODO
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-12-27 22:47:45 +0100 Stephan Bosch <stephan@rename-it.nl> (ec0368c2)
+
+ Enotify: previous change did not distinguish Cc recipients.
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-12-27 22:43:33 +0100 Stephan Bosch <stephan@rename-it.nl> (877ba290)
+
+ Enotify: added check for duplicate recipients within URI.
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-12-27 21:57:43 +0100 Stephan Bosch <stephan@rename-it.nl> (9b37865e)
+
+ Updated TODO.
+
+
+M TODO
+
+2008-12-27 21:52:31 +0100 Stephan Bosch <stephan@rename-it.nl> (a3ab3278)
+
+ Enotify: added FIXME.
+
+
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+
+2008-12-27 21:33:53 +0100 Stephan Bosch <stephan@rename-it.nl> (6c1b2dff)
+
+ Enotify: added runtime support for options and performed some minor
+ cleanups.
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+
+2008-12-27 19:25:43 +0100 Stephan Bosch <stephan@rename-it.nl> (ec0a0295)
+
+ Enotify: added parsing support for the :options argument.
+
+
+M TODO
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M tests/extensions/enotify/errors.svtest
+A tests/extensions/enotify/errors/options.sieve
+
+2008-12-27 14:24:52 +0100 Stephan Bosch <stephan@rename-it.nl> (924f35f9)
+
+ Fixed semantic bug in extension handling.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2008-12-27 14:11:20 +0100 Stephan Bosch <stephan@rename-it.nl> (c744cea0)
+
+ Fixed segfault bug in extension handling.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2008-12-27 00:09:43 +0100 Stephan Bosch <stephan@rename-it.nl> (e86e6068)
+
+ Moved new_message_id function to sieve-message.c where it is more
+ appropriate.
+
+
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+
+2008-12-27 00:08:55 +0100 Stephan Bosch <stephan@rename-it.nl> (eac31301)
+
+ Updated documentation.
+
+
+M README
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+
+2008-12-25 23:31:31 +0100 Stephan Bosch <stephan@rename-it.nl> (4bf97c70)
+
+ Updated TODO.
+
+
+M TODO
+
+2008-12-25 23:26:59 +0100 Stephan Bosch <stephan@rename-it.nl> (031af6a2)
+
+ Enotify: implemented notify_method_capability test.
+
+
+M Makefile.am
+M TODO
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+A tests/extensions/enotify/notify_method_capability.svtest
+R077 tests/extensions/enotify/valid-notify-method.svtest tests/extensions/enotify/valid_notify_method.svtest
+
+2008-12-25 21:07:02 +0100 Stephan Bosch <stephan@rename-it.nl> (887c8f69)
+
+ Enotify: implemented the valid_notify_method test.
+
+
+M TODO
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M tests/extensions/enotify/errors.svtest
+R100 tests/extensions/enotify/errors/url-mailto.sieve tests/extensions/enotify/errors/uri-mailto.sieve
+R100 tests/extensions/enotify/errors/url.sieve tests/extensions/enotify/errors/uri.sieve
+A tests/extensions/enotify/valid-notify-method.svtest
+
+2008-12-25 18:02:06 +0100 Stephan Bosch <stephan@rename-it.nl> (8e29831d)
+
+ Simplified handling of extension ids.
+
+
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-validator.c
+M src/testsuite/ext-testsuite.c
+
+2008-12-25 15:26:34 +0100 Stephan Bosch <stephan@rename-it.nl> (c2a70097)
+
+ Renamed extension object registry.
+
+
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-objects.c
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+
+2008-12-21 20:50:54 +0100 Stephan Bosch <stephan@rename-it.nl> (2d060bda)
+
+ Merged concurrent changes.
+
+
+2008-12-21 20:49:19 +0100 Stephan Bosch <stephan@rename-it.nl> (9ea68a04)
+
+ Implemented support for configuring the available extensions.
+
+
+M TODO
+M doc/man/sieve-test.1
+M doc/man/sievec.1
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-tools/sieve-test.c
+M src/sieve-tools/sievec.c
+
+2008-12-21 16:32:07 +0100 Stephan Bosch <stephan@rename-it.nl> (590bcfd9)
+
+ Vacation: changed location of X-Sieve header.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2008-12-21 16:30:16 +0100 Stephan Bosch <stephan@rename-it.nl> (5eabe7ae)
+
+ Vacation: last change used wrong address.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2008-12-21 16:11:52 +0100 Stephan Bosch <stephan@rename-it.nl> (a5264617)
+
+ Vacation: properly implemented use of :from address argument.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2008-12-21 15:55:07 +0100 Stephan Bosch <stephan@rename-it.nl> (63ed66d9)
+
+ Fixed accidental paste in sieve-address.c.
+
+
+M src/lib-sieve/sieve-address.c
+
+2008-12-21 14:26:22 +0100 Stephan Bosch <stephan@rename-it.nl> (1d830b2d)
+
+ Enotify: added recipient verification and implemented proper To and Cc
+ header composition.
+
+
+M TODO
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M tests/extensions/enotify/errors.svtest
+M tests/extensions/enotify/errors/url-mailto.sieve
+
+2008-12-21 12:35:11 +0100 Stephan Bosch <stephan@rename-it.nl> (d7b2fe30)
+
+ Enotify: forgot to add new file to the test suite.
+
+
+A tests/extensions/enotify/errors/from-mailto.sieve
+
+2008-12-21 12:33:46 +0100 Stephan Bosch <stephan@rename-it.nl> (19b76ef1)
+
+ Enotify: implemented verification of the :from address.
+
+
+M TODO
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M tests/extensions/enotify/errors.svtest
+
+2008-12-21 11:38:38 +0100 Stephan Bosch <stephan@rename-it.nl> (2277d1c6)
+
+ Enotify: made log struct name shorter.
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+
+2008-12-21 11:37:24 +0100 Stephan Bosch <stephan@rename-it.nl> (73ca4dbd)
+
+ Fixed compiler warning about signed char.
+
+
+M src/lib-sieve/rfc2822.c
+
+2008-12-21 02:18:51 +0100 Stephan Bosch <stephan@rename-it.nl> (9a045825)
+
+ Enotify: corrected mailto URI error messages.
+
+
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-12-21 01:30:02 +0100 Stephan Bosch <stephan@rename-it.nl> (60e726c4)
+
+ Enotify: cleaned up URI error handling.
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-12-21 01:08:38 +0100 Stephan Bosch <stephan@rename-it.nl> (43d53ad3)
+
+ Enotify: shielded most of the method API from compiler internals.
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+
+2008-12-20 21:45:13 +0100 Stephan Bosch <stephan@rename-it.nl> (392dc84a)
+
+ Enotify: added owner email to auto-submitted header.
+
+
+M TODO
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-12-19 18:04:11 +0100 Stephan Bosch <stephan@rename-it.nl> (084ea434)
+
+ Updated TODO.
+
+
+M TODO
+
+2008-12-19 17:27:56 +0100 Stephan Bosch <stephan@rename-it.nl> (1c0ad81a)
+
+ Small cosmetic changes to lexer sources.
+
+
+M src/lib-sieve/sieve-lexer.c
+
+2008-12-19 17:20:13 +0100 Stephan Bosch <stephan@rename-it.nl> (57b1da62)
+
+ Enotify: mailto: excluded body 'header' in URI from the header field body
+ verification.
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-12-19 17:06:02 +0100 Stephan Bosch <stephan@rename-it.nl> (9e32d835)
+
+ Enotify: mailto: implemented verification of (unstructured) header field
+ bodies and improved URI syntax checking.
+
+
+M TODO
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/rfc2822.c
+M src/lib-sieve/rfc2822.h
+
+2008-12-19 16:12:57 +0100 Stephan Bosch <stephan@rename-it.nl> (87a9a696)
+
+ Substituted mail_get_headers for mail_get_headers_utf8 for those occasions
+ where utf8 is of no concern.
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/tst-exists.c
+
+2008-12-19 16:07:03 +0100 Stephan Bosch <stephan@rename-it.nl> (a2968815)
+
+ Improved result execution and prevented failure on store action on dry run
+ (with no specified namespace).
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+
+2008-12-19 16:06:09 +0100 Stephan Bosch <stephan@rename-it.nl> (419fec52)
+
+ Enotify: avoided sending notifications on auto-submitted messages.
+
+
+M TODO
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-12-19 10:25:46 +0100 Stephan Bosch <stephan@rename-it.nl> (d67280b3)
+
+ Adapted to changes in the Dovecot API.
+
+
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-validator.c
+
+2008-12-18 00:23:05 +0100 Stephan Bosch <stephan@rename-it.nl> (06e78525)
+
+ Merged concurrent changes.
+
+
+2008-12-18 00:22:17 +0100 Stephan Bosch <stephan@rename-it.nl> (7f6dcb03)
+
+ Updated TODO: listed what remains to be done for the enotify extension and
+ its mailto method.
+
+
+M TODO
+
+2008-12-18 00:21:34 +0100 Stephan Bosch <stephan@rename-it.nl> (ff5efcaa)
+
+ Updated enotify:mailto draft RFC.
+
+
+R081 doc/rfc/draft-ietf-sieve-notify-mailto-09.txt doc/rfc/draft-ietf-sieve-notify-mailto-10.txt
+
+2008-12-14 20:08:47 +0100 Stephan Bosch <stephan@rename-it.nl> (d44d2500)
+
+ Enotify: mailto: added filtering of reserved headers.
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-12-14 18:39:36 +0100 Stephan Bosch <stephan@rename-it.nl> (d3fdab9f)
+
+ Enotify: changed notify message to match the latest draft specification
+ better (not yet compliant).
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-12-14 14:12:55 +0100 Stephan Bosch <stephan@rename-it.nl> (64353ac9)
+
+ Enotify: now using new message composition functions.
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-12-14 14:12:22 +0100 Stephan Bosch <stephan@rename-it.nl> (0f4adc23)
+
+ Fixed message typo in sieve-exec tool.
+
+
+M src/sieve-tools/sieve-exec.c
+
+2008-12-14 13:51:23 +0100 Stephan Bosch <stephan@rename-it.nl> (7e21211c)
+
+ Reject: now using new message composition functions.
+
+
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/rfc2822.c
+
+2008-12-14 12:59:47 +0100 Stephan Bosch <stephan@rename-it.nl> (74a29965)
+
+ Change to configure.in caused compile error.
+
+
+M configure.in
+
+2008-12-14 12:44:53 +0100 Stephan Bosch <stephan@rename-it.nl> (f8de116f)
+
+ Fixed bug in configure script that emitted Dovecot version in config header
+ in stead of Sieve version.
+
+
+M configure.in
+
+2008-12-14 12:40:38 +0100 Stephan Bosch <stephan@rename-it.nl> (05145e75)
+
+ Added X-Sieve header to redirected messages.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2008-12-14 11:05:36 +0100 Stephan Bosch <stephan@rename-it.nl> (8b9941f5)
+
+ Vacation: now using new message composition functions.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2008-12-14 11:05:19 +0100 Stephan Bosch <stephan@rename-it.nl> (d2101dad)
+
+ Created basic internet mail message composition functionality.
+
+
+M src/lib-sieve/rfc2822.c
+M src/lib-sieve/rfc2822.h
+
+2008-12-14 00:06:38 +0100 Stephan Bosch <stephan@rename-it.nl> (78580a2c)
+
+ Vacation: added support for properly updating references header.
+
+
+M Makefile.am
+M TODO
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/rfc2822.c
+M src/lib-sieve/rfc2822.h
+A tests/extensions/vacation/references.sieve
+A tests/extensions/vacation/references.svtest
+
+2008-12-13 20:34:04 +0100 Stephan Bosch <stephan@rename-it.nl> (7a38f1a5)
+
+ Enotify: implemented basic notify mailto: execution.
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-12-13 18:41:20 +0100 Stephan Bosch <stephan@rename-it.nl> (7f6f9208)
+
+ Enotify: implemented construction and printing of action object.
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+
+2008-12-13 18:18:57 +0100 Stephan Bosch <stephan@rename-it.nl> (33da3e49)
+
+ Enotify: implemented runtime part.
+
+
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+
+2008-12-12 19:50:11 +0100 Stephan Bosch <stephan@rename-it.nl> (97450ea5)
+
+ Enotify: restructured mailto url parsing to use arrays for the results.
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-12-12 19:40:27 +0100 Stephan Bosch <stephan@rename-it.nl> (3230382e)
+
+ Enotify: added verification of header field names in mailto url.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+A tests/extensions/enotify/errors.svtest
+A tests/extensions/enotify/errors/url-mailto.sieve
+A tests/extensions/enotify/errors/url.sieve
+
+2008-12-10 13:42:03 +0100 Stephan Bosch <stephan@rename-it.nl> (c4c589b1)
+
+ Reject: improved message rejection log message.
+
+
+M src/lib-sieve/ext-reject.c
+
+2008-12-09 19:06:27 +0100 Stephan Bosch <stephan@rename-it.nl> (25db5e1a)
+
+ Compiler now warns about syntactically invalid header field names.
+
+
+M TODO
+M src/lib-sieve/rfc2822.c
+M src/lib-sieve/rfc2822.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+A tests/compile/warnings/invalid-headers.sieve
+
+2008-12-09 18:20:20 +0100 Stephan Bosch <stephan@rename-it.nl> (8bc9fddf)
+
+ Exported true and false commands to separate file.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+A src/lib-sieve/tst-truefalse.c
+
+2008-11-30 21:04:54 +0100 Stephan Bosch <stephan@rename-it.nl> (d55cc35f)
+
+ Fixed bug in improved capability string composition.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2008-11-30 21:02:18 +0100 Stephan Bosch <stephan@rename-it.nl> (0c039f4e)
+
+ Enotify: further developed URI parsing.
+
+
+M src/lib-sieve/plugins/enotify/ext-enotify-limits.h
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+
+2008-11-30 21:01:54 +0100 Stephan Bosch <stephan@rename-it.nl> (d59421e5)
+
+ Added support for header verification.
+
+
+M src/lib-sieve/Makefile.am
+A src/lib-sieve/rfc2822.c
+A src/lib-sieve/rfc2822.h
+
+2008-11-30 01:30:14 +0100 Stephan Bosch <stephan@rename-it.nl> (979b0e8e)
+
+ Enotify: implemented coarse mailto URI parsing.
+
+
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M tests/extensions/enotify/basic.svtest
+
+2008-11-30 00:45:05 +0100 Stephan Bosch <stephan@rename-it.nl> (ef717dbc)
+
+ Added new draft-bis version of mailto RFC to doc/rfc.
+
+
+A doc/rfc/draft-duerst-mailto-bis-05.txt
+
+2008-11-30 00:25:23 +0100 Stephan Bosch <stephan@rename-it.nl> (5c6fb4d8)
+
+ Activated unload handler for extensions.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2008-11-30 00:14:45 +0100 Stephan Bosch <stephan@rename-it.nl> (041b39df)
+
+ Enotify: implemented uri scheme verification.
+
+
+M src/lib-sieve/plugins/enotify/Makefile.am
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+A src/lib-sieve/plugins/enotify/ext-enotify-limits.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M tests/extensions/enotify/execute.svtest
+
+2008-11-29 21:27:50 +0100 Stephan Bosch <stephan@rename-it.nl> (fc8896f8)
+
+ Added unload method to extension object.
+
+
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-match-types.c
+M src/testsuite/ext-testsuite.c
+
+2008-11-28 23:04:40 +0100 Stephan Bosch <stephan@rename-it.nl> (4145d299)
+
+ Reprioritized TODO.
+
+
+M TODO
+
+2008-11-26 20:50:33 +0100 Stephan Bosch <stephan@rename-it.nl> (a00f056c)
+
+ Added tag 0.1.2 for changeset f01fe5f1e816
+
+
+2008-11-26 20:50:20 +0100 Stephan Bosch <stephan@rename-it.nl> (171e3bfa)
+
+ Added tag 0.1.1 for changeset e534276ecf10
+
+
+2008-11-26 20:49:50 +0100 Stephan Bosch <stephan@rename-it.nl> (cf2ad5bb)
+
+ Released v0.1.2 for Dovecot v1.2.alpha4.
+
+
+M NEWS
+M configure.in
+
+2008-11-26 17:14:40 +0100 Stephan Bosch <stephan@rename-it.nl> (02092823)
+
+ Vacation: improved log message for discarded vacation response.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2008-11-26 14:35:21 +0100 Stephan Bosch <stephan@rename-it.nl> (c8d13dac)
+
+ Fixed bug in the handling of context during result execution, which resulted
+ in broken redirect action.
+
+
+M src/lib-sieve/sieve-result.c
+
+2008-11-25 00:03:23 +0100 Stephan Bosch <stephan@rename-it.nl> (bd9e1b23)
+
+ Released v0.1.1 for Dovecot v1.2.alpha4.
+
+
+M configure.in
+
+2008-11-24 23:38:56 +0100 Stephan Bosch <stephan@rename-it.nl> (510ee56c)
+
+ Updated NEWS file.
+
+
+M NEWS
+
+2008-11-22 15:29:29 +0100 Stephan Bosch <stephan@rename-it.nl> (13716444)
+
+ Added registry for extension capabilities like the available notify methods
+ and adjusted the enotify extension accordingly.
+
+
+M src/lib-sieve/plugins/enotify/Makefile.am
+A src/lib-sieve/plugins/enotify/ext-enotify-common.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/plugins/enotify/ntfy-mailto.c
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+
+2008-11-21 23:40:14 +0100 Stephan Bosch <stephan@rename-it.nl> (671f9be3)
+
+ Forgot to move RFC 2244 to proper place in doc/rfc.
+
+
+R100 src/lib-sieve/plugins/comparator-i-ascii-numeric/rfc2244.txt doc/rfc/i-ascii-numeric.rfc2244.txt
+
+2008-11-21 23:34:40 +0100 Stephan Bosch <stephan@rename-it.nl> (be698fd0)
+
+ Enotify: implemented :encodeurl variables modifier.
+
+
+M Makefile.am
+A doc/rfc/uri.rfc3986.txt
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+A tests/extensions/enotify/encodeurl.svtest
+
+2008-11-21 22:45:08 +0100 Stephan Bosch <stephan@rename-it.nl> (3d3aa53e)
+
+ Added TODO item.
+
+
+M TODO
+
+2008-11-21 19:59:00 +0100 Stephan Bosch <stephan@rename-it.nl> (7964f451)
+
+ Adapted to changes in the mailbox_open() API.
+
+
+M src/lib-sieve-tool/mail-raw.c
+M src/lib-sieve-tool/sieve-tool.c
+M src/lib-sieve/sieve-actions.c
+M src/sieve-tools/sieve-exec.c
+M src/sieve-tools/sieve-test.c
+M src/testsuite/testsuite.c
+
+2008-11-20 00:54:54 +0100 Stephan Bosch <stephan@rename-it.nl> (bbe95b34)
+
+ Merged concurrent changes.
+
+
+2008-11-20 00:54:38 +0100 Stephan Bosch <stephan@rename-it.nl> (90f4fed4)
+
+ Enotify: copied action implementation from old plugin.
+
+
+A doc/rfc/mailto.rfc2368.txt
+M src/lib-sieve/plugins/enotify/Makefile.am
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+A src/lib-sieve/plugins/enotify/ntfy-mailto.c
+A src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
+M src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+
+2008-11-20 00:54:14 +0100 Stephan Bosch <stephan@rename-it.nl> (f461b22e)
+
+ Fixed error handling of actions that send mail.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2008-11-20 00:06:58 +0100 Stephan Bosch <stephan@rename-it.nl> (0c1b149c)
+
+ Enabled (optional) support for Valgrind in the testsuite and fixed a few
+ intricate bugs in the process.
+
+
+M Makefile.am
+M configure.in
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+
+2008-11-19 21:24:10 +0100 Stephan Bosch <stephan@rename-it.nl> (e58d90ca)
+
+ Changed acquisition of usernames in sieve command line tools.
+
+
+M src/lib-sieve-tool/sieve-tool.c
+
+2008-11-19 20:59:45 +0100 Stephan Bosch <stephan@rename-it.nl> (bdc8a61f)
+
+ Testsuite: added test for header folding.
+
+
+M tests/header.svtest
+
+2008-11-19 20:50:11 +0100 Stephan Bosch <stephan@rename-it.nl> (35e1b03b)
+
+ Fixed bug in mail_raw implementation: mail_namespaces_deinit() must not be
+ called explicitly for v1.2.
+
+
+M src/lib-sieve-tool/mail-raw.c
+
+2008-11-17 22:44:19 +0100 Stephan Bosch <stephan@rename-it.nl> (c7e0c93e)
+
+ Previous change did not compile.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2008-11-17 22:38:28 +0100 Stephan Bosch <stephan@rename-it.nl> (f7c37a6b)
+
+ Matched changes in Dovecot to properly handle/ignore the new mailbox ACL
+ support.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2008-11-16 23:31:32 +0100 Stephan Bosch <stephan@rename-it.nl> (590b593b)
+
+ Added notify mailto draft.
+
+
+A doc/rfc/draft-ietf-sieve-notify-mailto-09.txt
+
+2008-11-16 18:27:34 +0100 Stephan Bosch <stephan@rename-it.nl> (59a3a988)
+
+ Enotify: finished skeleton by addin empty :encodeurl implementation.
+
+
+M src/lib-sieve/plugins/enotify/Makefile.am
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+A src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M tests/extensions/enotify/execute.svtest
+
+2008-11-16 16:28:15 +0100 Stephan Bosch <stephan@rename-it.nl> (cdcba6c7)
+
+ Testsuite: added draft RFC examples as execution tests.
+
+
+M Makefile.am
+A tests/extensions/enotify/execute.svtest
+A tests/extensions/enotify/execute/draft-rfc-ex1.sieve
+A tests/extensions/enotify/execute/draft-rfc-ex2.sieve
+A tests/extensions/enotify/execute/draft-rfc-ex3.sieve
+A tests/extensions/enotify/execute/draft-rfc-ex5.sieve
+A tests/extensions/enotify/execute/draft-rfc-ex6.sieve
+
+2008-11-15 01:39:24 +0100 Stephan Bosch <stephan@rename-it.nl> (913e9f17)
+
+ Merged concurrent changes.
+
+
+2008-11-15 01:38:37 +0100 Stephan Bosch <stephan@rename-it.nl> (3188d46e)
+
+ Include: fixed bug in import/export commands.
+
+
+M src/lib-sieve/plugins/include/ext-include-variables.c
+
+2008-11-15 00:34:43 +0100 Stephan Bosch <stephan@rename-it.nl> (1432e68b)
+
+ Fixed small indentation error.
+
+
+M src/lib-sieve/plugins/include/ext-include-variables.c
+
+2008-11-14 23:09:11 +0100 Stephan Bosch <stephan@rename-it.nl> (375100c9)
+
+ Fixed bug in handling of non-existent scripts.
+
+
+M src/lib-sieve/sieve-script.c
+
+2008-11-14 22:57:57 +0100 Stephan Bosch <stephan@rename-it.nl> (2fb5a4e3)
+
+ Prepared NEWS file for next release.
+
+
+M NEWS
+
+2008-11-14 12:34:34 +0100 Stephan Bosch <stephan@rename-it.nl> (d900c359)
+
+ Slightly improved documentation.
+
+
+M INSTALL
+M README
+
+2008-11-12 17:05:48 +0100 Stephan Bosch <stephan@rename-it.nl> (e3488325)
+
+ Imap4flags: fixed bug in the handling of the internal variable.
+
+ Previously the final value of internal variable was for every store action
+ that didn't specify a :flags argument explicitly. This results in out-of
+ order assignment/removal of flags, e.g. also the flags assigned keep actions
+ that were executed before the addflag/setflag command were modified.
+
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-validator.c
+
+2008-11-12 10:09:23 +0100 Stephan Bosch <stephan@rename-it.nl> (3415d166)
+
+ Updated TODO.
+
+
+M TODO
+
+2008-11-12 10:03:36 +0100 Stephan Bosch <stephan@rename-it.nl> (b970b8c7)
+
+ Removed man page issue from README file.
+
+
+M README
+
+2008-11-12 00:17:36 +0100 Stephan Bosch <stephan@rename-it.nl> (d48d3b68)
+
+ Updated README.
+
+
+M README
+
+2008-11-12 00:06:35 +0100 Stephan Bosch <stephan@rename-it.nl> (a604dd72)
+
+ Created man page for the sieve-test command.
+
+
+M Makefile.am
+A doc/man/sieve-test.1
+
+2008-11-11 23:12:34 +0100 Stephan Bosch <stephan@rename-it.nl> (5a9e7203)
+
+ Created man page for the sieved command.
+
+
+M Makefile.am
+A doc/man/sieved.1
+
+2008-11-11 22:11:40 +0100 Stephan Bosch <stephan@rename-it.nl> (9002e1d9)
+
+ Enabled installation of man pages.
+
+
+M Makefile.am
+
+2008-11-11 22:11:18 +0100 Stephan Bosch <stephan@rename-it.nl> (9c9ffe38)
+
+ Forgot to add new sieve-config.h to the distribution.
+
+
+M src/lib-sieve/Makefile.am
+
+2008-11-11 21:28:37 +0100 Stephan Bosch <stephan@rename-it.nl> (e0d9b467)
+
+ Created (currently uninstalled) man page for the sievec command.
+
+
+A doc/man/sievec.1
+
+2008-11-11 11:23:21 +0100 Stephan Bosch <stephan@rename-it.nl> (8e9c34fc)
+
+ Testsuite: fail with informative error if compiled against dovecot headers
+ only.
+
+
+M Makefile.am
+
+2008-11-11 00:34:31 +0100 Stephan Bosch <stephan@rename-it.nl> (c922e57a)
+
+ Re-enabled support for compiling against Dovecot headers.
+
+
+M configure.in
+M src/Makefile.am
+
+2008-11-10 08:18:09 +0100 Stephan Bosch <stephan@rename-it.nl> (2917405f)
+
+ Enotify: added skeleton implementation of notify_method_capability test.
+
+
+M src/lib-sieve/plugins/enotify/Makefile.am
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+A src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
+
+2008-11-09 22:57:52 +0100 Stephan Bosch <stephan@rename-it.nl> (bd8d2804)
+
+ Enotify: added skeleton implementation of valid_notify_method test.
+
+
+M src/lib-sieve/plugins/enotify/Makefile.am
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+A src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
+M tests/extensions/enotify/basic.svtest
+
+2008-11-07 21:17:06 +0100 Stephan Bosch <stephan@rename-it.nl> (234a0f8b)
+
+ Enotify: implemented skeleton for the notify command.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/enotify/cmd-notify.c
+M src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+A tests/extensions/enotify/basic.svtest
+
+2008-11-02 23:29:00 +0100 Stephan Bosch <stephan@rename-it.nl> (2dc98704)
+
+ ENotify: activated empty implementation.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/sieve-extensions.c
+
+2008-11-02 22:52:30 +0100 Stephan Bosch <stephan@rename-it.nl> (94af6350)
+
+ Started using autoconf output.
+
+
+M .hgignore
+M configure.in
+A dsieve-config.h.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/sieve-common.h
+A src/lib-sieve/sieve-config.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.h
+
+2008-11-02 11:36:28 +0100 Stephan Bosch <stephan@rename-it.nl> (e18b475b)
+
+ Added UTF-8 to modified UTF-7 folder name conversion for compatibility with
+ IMAP.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/sieve-actions.h
+
+2008-11-02 11:30:46 +0100 Stephan Bosch <stephan@rename-it.nl> (76eb6954)
+
+ Accidentally added binaries for sieve tools.
+
+
+M .hgignore
+D src/sieve-tools/sieve-exec
+D src/sieve-tools/sieve-test
+D src/sieve-tools/sievec
+D src/sieve-tools/sieved
+
+2008-11-01 23:03:04 +0100 Stephan Bosch <stephan@rename-it.nl> (38f98623)
+
+ Enotify: built skeleton for the notify command.
+
+
+A doc/rfc/draft-ietf-sieve-notify-12.txt
+M src/lib-sieve/plugins/enotify/Makefile.am
+A src/lib-sieve/plugins/enotify/cmd-notify.c
+A src/lib-sieve/plugins/enotify/ext-enotify-common.h
+M src/lib-sieve/plugins/enotify/ext-enotify.c
+
+2008-11-01 20:48:57 +0100 Stephan Bosch <stephan@rename-it.nl> (7b531076)
+
+ Removed code duplication between testsuite and commandline tools. Also
+ restructured source code of the tools.
+
+
+M README
+M TODO
+M configure.in
+M src/Makefile.am
+A src/lib-sieve-tool/Makefile.am
+R100 src/lib-util/mail-raw.c src/lib-sieve-tool/mail-raw.c
+R100 src/lib-util/mail-raw.h src/lib-sieve-tool/mail-raw.h
+R075 src/sieve-bin/bin-common.c src/lib-sieve-tool/sieve-tool.c
+A src/lib-sieve-tool/sieve-tool.h
+D src/lib-util/Makefile.am
+D src/sieve-bin/bin-common.h
+R085 src/sieve-bin/Makefile.am src/sieve-tools/Makefile.am
+A src/sieve-tools/sieve-exec
+R091 src/sieve-bin/sieve-exec.c src/sieve-tools/sieve-exec.c
+A src/sieve-tools/sieve-test
+R093 src/sieve-bin/sieve-test.c src/sieve-tools/sieve-test.c
+A src/sieve-tools/sievec
+R088 src/sieve-bin/sievec.c src/sieve-tools/sievec.c
+A src/sieve-tools/sieved
+R078 src/sieve-bin/sieved.c src/sieve-tools/sieved.c
+M src/testsuite/Makefile.am
+M src/testsuite/testsuite.c
+
+2008-10-30 23:41:22 +0100 Stephan Bosch <stephan@rename-it.nl> (501216f5)
+
+ Removed now obsolete namespaces.c/h from testsuite and commandline tools.
+
+
+M src/sieve-bin/Makefile.am
+D src/sieve-bin/namespaces.c
+D src/sieve-bin/namespaces.h
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+M src/testsuite/Makefile.am
+D src/testsuite/namespaces.c
+D src/testsuite/namespaces.h
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite.c
+
+2008-10-30 23:05:38 +0100 Stephan Bosch <stephan@rename-it.nl> (bcd3ad56)
+
+ Enabled all available mail storage types (those compiled in Dovecot) for the
+ commandline tools and the testsuite.
+
+
+M src/sieve-bin/Makefile.am
+M src/sieve-bin/namespaces.c
+M src/testsuite/Makefile.am
+M src/testsuite/namespaces.c
+
+2008-10-30 22:30:17 +0100 Stephan Bosch <stephan@rename-it.nl> (078fda7e)
+
+ Merged mail-raw implementations of sieve commandline tools and the
+ testsuite, thus removing duplicate code.
+
+
+M configure.in
+M src/Makefile.am
+A src/lib-util/Makefile.am
+R076 src/sieve-bin/mail-raw.c src/lib-util/mail-raw.c
+R079 src/sieve-bin/mail-raw.h src/lib-util/mail-raw.h
+M src/sieve-bin/Makefile.am
+M src/sieve-bin/bin-common.c
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+M src/testsuite/Makefile.am
+D src/testsuite/mail-raw.c
+D src/testsuite/mail-raw.h
+M src/testsuite/testsuite-common.c
+
+2008-10-30 20:07:36 +0100 Stephan Bosch <stephan@rename-it.nl> (c67ac6db)
+
+ Made lda plugin properly refer to the main script as 'main script' and not
+ the basename of the sieve file (which is of no interest to the user for the
+ main script).
+
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-bin/bin-common.c
+
+2008-10-30 19:49:53 +0100 Stephan Bosch <stephan@rename-it.nl> (ec8fc9f2)
+
+ Improved logging of failed script load.
+
+
+M src/lib-sieve/sieve-script.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2008-10-29 23:49:47 +0100 Stephan Bosch <stephan@rename-it.nl> (4b214656)
+
+ Now using folder name as specified by user in log messages in stead of
+ internal representation.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2008-10-29 21:26:08 +0100 Stephan Bosch <stephan@rename-it.nl> (3434e90d)
+
+ Added mail_debug messages to plugin to find problems in the sieve path
+ specification more easily.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2008-10-29 01:26:25 +0100 Stephan Bosch <stephan@rename-it.nl> (69b33e90)
+
+ Added TODO item.
+
+
+M TODO
+
+2008-10-29 01:13:22 +0100 Stephan Bosch <stephan@rename-it.nl> (2adb6a61)
+
+ Command sievec -d always wrote to std out.
+
+
+M src/sieve-bin/sievec.c
+
+2008-10-29 01:12:44 +0100 Stephan Bosch <stephan@rename-it.nl> (ec932428)
+
+ Fixed missing mask argument in two open calls (bug found by Sergey Ivanov).
+
+
+M src/sieve-bin/bin-common.c
+M src/testsuite/testsuite.c
+
+2008-10-25 20:27:14 +0200 Stephan Bosch <stephan@rename-it.nl> (64869811)
+
+ Started development of enotify extension.
+
+
+M configure.in
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/enotify/Makefile.am
+A src/lib-sieve/plugins/enotify/ext-enotify.c
+
+2008-10-23 20:11:15 +0200 Stephan Bosch <stephan@rename-it.nl> (1f81f1d2)
+
+ Added tag 0.1.0 for changeset 065c12acdcc0
+
+
+2008-10-23 20:08:52 +0200 Stephan Bosch <stephan@rename-it.nl> (f7270d1e)
+
+ Released v0.1.0 for Dovecot v1.2.alpha3.
+
+
+M TODO
+M configure.in
+
+2008-10-23 19:44:57 +0200 Stephan Bosch <stephan@rename-it.nl> (419330a9)
+
+ Minor revisions to the package documentation.
+
+
+M AUTHORS
+M NEWS
+M README
+
+2008-10-22 20:26:59 +0200 Stephan Bosch <stephan@rename-it.nl> (27a05dc9)
+
+ Fixed warning caused by mixup between mail_storage and sieve_storage.
+
+
+M src/lib-sieve/sieve-types.h
+
+2008-10-22 16:10:13 +0200 Stephan Bosch <stephan@rename-it.nl> (057f6ea1)
+
+ Improved execution of store action.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2008-10-21 21:49:14 +0200 Stephan Bosch <stephan@rename-it.nl> (cf5025c7)
+
+ Properly set storage_r in plugin function to prevent double errors.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-types.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2008-10-20 02:13:27 +0200 Stephan Bosch <stephan@rename-it.nl> (ff2b8ffd)
+
+ Prevented transaction context from becoming NULL in execution of store
+ action.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-result.c
+
+2008-10-20 01:57:36 +0200 Stephan Bosch <stephan@rename-it.nl> (7e6a0ecc)
+
+ Fixed context handling bug in the result execution.
+
+
+M src/lib-sieve/sieve-result.c
+
+2008-10-19 18:35:17 +0200 Stephan Bosch <stephan@rename-it.nl> (c459d469)
+
+ Clarified errors occurring when colon is missing.
+
+
+M src/lib-sieve/sieve-validator.c
+M tests/compile/errors.svtest
+A tests/compile/errors/typos.sieve
+
+2008-10-19 17:56:01 +0200 Stephan Bosch <stephan@rename-it.nl> (71fa5a02)
+
+ Corrected error message.
+
+
+M src/lib-sieve/sieve-validator.c
+M tests/compile/errors.svtest
+
+2008-10-19 17:47:49 +0200 Stephan Bosch <stephan@rename-it.nl> (6564cc41)
+
+ Clarified error messages for missing semicolon.
+
+
+M README
+M src/lib-sieve/sieve-validator.c
+M tests/compile/errors.svtest
+
+2008-10-19 16:46:12 +0200 Stephan Bosch <stephan@rename-it.nl> (11f12b4d)
+
+ Repaired 'make dist' tarball output.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/body/Makefile.am
+D src/lib-sieve/plugins/body/body.sieve
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile.am
+D src/lib-sieve/plugins/comparator-i-ascii-numeric/cmp-i-ascii-numeric.sieve
+M src/lib-sieve/plugins/copy/Makefile.am
+D src/lib-sieve/plugins/copy/copy.sieve
+M src/lib-sieve/plugins/imapflags/Makefile.am
+D src/lib-sieve/plugins/imapflags/imapflags-2.sieve
+D src/lib-sieve/plugins/imapflags/imapflags-errors.sieve
+D src/lib-sieve/plugins/imapflags/imapflags-implicit.sieve
+D src/lib-sieve/plugins/imapflags/imapflags-variables.sieve
+D src/lib-sieve/plugins/imapflags/imapflags.sieve
+M src/lib-sieve/plugins/regex/Makefile.am
+M src/lib-sieve/plugins/relational/Makefile.am
+D src/lib-sieve/plugins/relational/relational.sieve
+M src/lib-sieve/plugins/subaddress/Makefile.am
+D src/lib-sieve/plugins/subaddress/subaddress.sieve
+M src/lib-sieve/plugins/vacation/Makefile.am
+D src/lib-sieve/plugins/vacation/vacation-errors.sieve
+D src/lib-sieve/plugins/vacation/vacation.sieve
+M src/lib-sieve/plugins/variables/Makefile.am
+D src/lib-sieve/plugins/variables/variables-errors.sieve
+D src/lib-sieve/plugins/variables/variables-match.sieve
+D src/lib-sieve/plugins/variables/variables-nspace.sieve
+D src/lib-sieve/plugins/variables/variables-regex.sieve
+D src/lib-sieve/plugins/variables/variables.sieve
+M src/testsuite/Makefile.am
+
+2008-10-19 15:48:14 +0200 Stephan Bosch <stephan@rename-it.nl> (4fc62256)
+
+ Revised README.
+
+
+M INSTALL
+M README
+M configure.in
+
+2008-10-19 15:19:54 +0200 Stephan Bosch <stephan@rename-it.nl> (599d9b5b)
+
+ Testsuite: added support for basic result checking.
+
+
+M TODO
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/testsuite/Makefile.am
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+A src/testsuite/testsuite-result.c
+A src/testsuite/testsuite-result.h
+M src/testsuite/tst-test-error.c
+A src/testsuite/tst-test-result.c
+M tests/execute/actions.svtest
+M tests/execute/actions/fileinto.sieve
+M tests/execute/actions/redirect.sieve
+M tests/extensions/reject/execute.svtest
+M tests/extensions/vacation/execute.svtest
+A tests/extensions/vacation/execute/action.sieve
+
+2008-10-19 12:36:31 +0200 Stephan Bosch <stephan@rename-it.nl> (98bd2cc5)
+
+ Reported RFC questions to the ietf-mta-filters mailinglist.
+
+
+M TODO
+D doc/rfc/RFC Controversy.txt
+A doc/rfc/RFC-questions.txt
+
+2008-10-19 11:58:33 +0200 Stephan Bosch <stephan@rename-it.nl> (7b83caf1)
+
+ Added explicit messages and tests for unsupported use of variables.
+
+
+M TODO
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/sieve-comparators.c
+M tests/compile/errors.svtest
+A tests/compile/errors/unsupported.sieve
+
+2008-10-12 12:45:10 +0200 Stephan Bosch <stephan@rename-it.nl> (3a8746c9)
+
+ Updated TODO.
+
+
+M TODO
+
+2008-10-12 12:43:34 +0200 Stephan Bosch <stephan@rename-it.nl> (76534ffd)
+
+ Fixed TODO: made sure main scope used in variables dumping is unreferenced
+ when code dumper is freed.
+
+
+M TODO
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+
+2008-10-12 12:17:30 +0200 Stephan Bosch <stephan@rename-it.nl> (830d93e4)
+
+ Tested replacing cmusieve with sieve.
+
+
+M TODO
+
+2008-10-12 00:24:32 +0200 Stephan Bosch <stephan@rename-it.nl> (d5f36c0c)
+
+ Function t_str_new_const got moved to its proper place in Dovecot.
+
+
+M src/lib-sieve/sieve-binary.c
+
+2008-10-11 23:36:32 +0200 Stephan Bosch <stephan@rename-it.nl> (e2873f16)
+
+ Added extension support to code dumper.
+
+
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+
+2008-10-11 23:13:16 +0200 Stephan Bosch <stephan@rename-it.nl> (d04c3011)
+
+ Removed/solved minor TODOs.
+
+
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-parser.c
+
+2008-10-11 22:21:35 +0200 Stephan Bosch <stephan@rename-it.nl> (f2a05b1c)
+
+ Merged concurrent changes.
+
+
+2008-10-11 22:07:06 +0200 Stephan Bosch <stephan@rename-it.nl> (1445fd34)
+
+ Variables/Include: added support for dumping variables declared in extension
+ scopes.
+
+
+M TODO
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2008-10-09 23:24:54 +0200 Stephan Bosch <stephan@rename-it.nl> (5ddf67da)
+
+ Fixed amd64 logging segfault; turns out using same va_args in multiple
+ vprintf calls is not possible.
+
+
+M TODO
+M src/lib-sieve/sieve-error.c
+
+2008-10-05 19:44:51 +0200 Stephan Bosch <stephan@rename-it.nl> (631fb839)
+
+ Added support for mailbox autocreate and autosubscribe.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2008-10-05 19:14:43 +0200 Stephan Bosch <stephan@rename-it.nl> (2a983ad8)
+
+ Made plugin use tried_default_save indicator to prevent duplicate error
+ messages.
+
+
+M TODO
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite.c
+
+2008-10-04 10:41:52 +0200 Stephan Bosch <stephan@rename-it.nl> (dc75895b)
+
+ Updated TODO.
+
+
+M TODO
+
+2008-09-28 21:24:25 +0200 Stephan Bosch <stephan@rename-it.nl> (6127ac70)
+
+ Variables: added identifier dump support for main scope.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-dump.c
+M src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+
+2008-09-18 17:46:46 +0200 Stephan Bosch <stephan@rename-it.nl> (cf568449)
+
+ Variables: added dumptime context.
+
+
+M src/lib-sieve/plugins/variables/Makefile.am
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+A src/lib-sieve/plugins/variables/ext-variables-dump.c
+A src/lib-sieve/plugins/variables/ext-variables-dump.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+
+2008-09-15 16:10:57 +0200 Stephan Bosch <stephan@rename-it.nl> (546f6cce)
+
+ Merged concurrent changes.
+
+
+2008-09-14 21:06:44 +0200 Stephan Bosch <stephan@rename-it.nl> (960ab63b)
+
+ Started NEWS file.
+
+
+M NEWS
+
+2008-09-14 21:05:45 +0200 Stephan Bosch <stephan@rename-it.nl> (13acebb5)
+
+ Moved design description to doc/devel directory.
+
+
+M Makefile.am
+R100 DESIGN doc/devel/DESIGN
+
+2008-09-14 21:02:29 +0200 Stephan Bosch <stephan@rename-it.nl> (ba5c8551)
+
+ Restructured Sieve example scripts.
+
+
+M README
+R100 sieve/examples/elvey.sieve examples/elvey.sieve
+R100 sieve/examples/jerry.sieve examples/jerry.sieve
+R100 sieve/examples/mjohnson.sieve examples/mjohnson.sieve
+R100 sieve/examples/mklose.sieve examples/mklose.sieve
+R100 sieve/examples/relational.rfc5231.sieve examples/relational.rfc5231.sieve
+R100 sieve/examples/rfc3028.sieve examples/rfc3028.sieve
+R100 sieve/examples/sanjay.sieve examples/sanjay.sieve
+R100 sieve/examples/sieve_examples.sieve examples/sieve_examples.sieve
+R100 sieve/examples/subaddress.rfc5233.sieve examples/subaddress.rfc5233.sieve
+R100 sieve/examples/vacation.sieve examples/vacation.sieve
+R100 sieve/examples/vivil.sieve examples/vivil.sieve
+D sieve/tests/actions.sieve
+D sieve/tests/address-part.sieve
+D sieve/tests/basic.sieve
+D sieve/tests/comparator.sieve
+D sieve/tests/encoded-character.sieve
+D sieve/tests/envelope.sieve
+D sieve/tests/extensions.sieve
+D sieve/tests/if.sieve
+D sieve/tests/match-type.sieve
+D sieve/tests/matches.sieve
+D sieve/tests/stop.sieve
+D sieve/tests/vacation.sieve
+M tests/compile/examples.svtest
+
+2008-09-14 20:54:05 +0200 Stephan Bosch <stephan@rename-it.nl> (632ffdc2)
+
+ Testsuite: added execution tests for core actions (to find segfaults).
+
+
+M Makefile.am
+A tests/execute/actions.svtest
+R100 sieve/tests/fileinto.sieve tests/execute/actions/fileinto.sieve
+R100 sieve/tests/redirect.sieve tests/execute/actions/redirect.sieve
+M tests/extensions/reject/execute.svtest
+
+2008-09-14 20:42:14 +0200 Stephan Bosch <stephan@rename-it.nl> (f6d0011c)
+
+ Testsuite: added trivial reject action execution test.
+
+
+M Makefile.am
+A tests/extensions/reject/execute.svtest
+R100 sieve/tests/reject.sieve tests/extensions/reject/execute/basic.sieve
+
+2008-09-13 13:12:31 +0200 Stephan Bosch <stephan@rename-it.nl> (fe47287a)
+
+ Testsuite: added final existing error tests.
+
+
+D sieve/errors/address-errors.sieve
+D sieve/errors/address-part-errors.sieve
+D sieve/errors/encoded-character.sieve
+D sieve/errors/envelope-errors.sieve
+D sieve/errors/header-errors.sieve
+D sieve/errors/if-errors.sieve
+D sieve/errors/interesting.sieve
+D sieve/errors/keep-errors.sieve
+D sieve/errors/parse-errors.sieve
+D sieve/errors/require-errors.sieve
+D sieve/errors/size-errors.sieve
+D sieve/errors/stop-errors.sieve
+D sieve/errors/tag-errors.sieve
+M tests/compile/errors.svtest
+R100 sieve/errors/out-address-errors.sieve tests/compile/errors/out-address.sieve
+A tests/compile/errors/tag.sieve
+
+2008-09-13 13:01:50 +0200 Stephan Bosch <stephan@rename-it.nl> (3e5d9e87)
+
+ Improved README to be more readable.
+
+
+M README
+
+2008-09-12 17:49:45 +0200 Stephan Bosch <stephan@rename-it.nl> (d3040380)
+
+ Removed useless PTR_OFFSET from logfile error handler implementation.
+
+
+M src/lib-sieve/sieve-error.c
+
+2008-09-12 16:55:55 +0200 Stephan Bosch <stephan@rename-it.nl> (40b09103)
+
+ Added pre-release TODO item.
+
+
+M TODO
+
+2008-09-12 16:55:07 +0200 Stephan Bosch <stephan@rename-it.nl> (6032e179)
+
+ Improved argument error reporting.
+
+
+M TODO
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/include/cmd-import.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-size.c
+M src/testsuite/testsuite-objects.c
+
+2008-09-12 15:27:26 +0200 Stephan Bosch <stephan@rename-it.nl> (b40b9a03)
+
+ Restructured error reporting in validator and code generator.
+
+
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+
+2008-09-12 12:06:46 +0200 Stephan Bosch <stephan@rename-it.nl> (441c0cf4)
+
+ Fixed new ia64 warnings.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/tst-size.c
+M src/testsuite/tst-test-error.c
+
+2008-09-12 11:56:12 +0200 Stephan Bosch <stephan@rename-it.nl> (923f1d9f)
+
+ Fixed new ia64 warnings in sieve-code.
+
+
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+
+2008-09-12 11:36:42 +0200 Stephan Bosch <stephan@rename-it.nl> (68ee3d06)
+
+ Fixed new ia64 warnings in sieve-code.
+
+
+M src/lib-sieve/sieve-code.h
+
+2008-09-12 11:29:39 +0200 Stephan Bosch <stephan@rename-it.nl> (c6cce133)
+
+ Fixed ia64 warnings in sieve-code.
+
+
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+
+2008-09-12 11:17:04 +0200 Stephan Bosch <stephan@rename-it.nl> (5ff0ca84)
+
+ Variables: fixed ia64 compiler warnings.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+
+2008-09-12 01:53:02 +0200 Stephan Bosch <stephan@rename-it.nl> (dd1e90bd)
+
+ Forgot to handle return value of o_stream_send in logfile error hander
+ implementation.
+
+
+M src/lib-sieve/sieve-error.c
+
+2008-09-12 01:42:32 +0200 Stephan Bosch <stephan@rename-it.nl> (7efd8493)
+
+ Forgot O_TRUNC in logfile error handler's second logfile open() call.
+
+
+M src/lib-sieve/sieve-error.c
+
+2008-09-12 01:39:22 +0200 Stephan Bosch <stephan@rename-it.nl> (71b15ea8)
+
+ Include: improved trace verbosity for import command.
+
+
+M src/lib-sieve/plugins/include/cmd-import.c
+
+2008-09-12 01:33:47 +0200 Stephan Bosch <stephan@rename-it.nl> (8e04ea9b)
+
+ Hopefully resolved various type cast warnings surfacing on ia_64 and not on
+ i386.
+
+
+M src/lib-sieve/plugins/include/cmd-import.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-interpreter.c
+
+2008-09-12 00:23:02 +0200 Stephan Bosch <stephan@rename-it.nl> (d7df5723)
+
+ Testsuite: added address test case for specific strange situation.
+
+
+M tests/address.svtest
+
+2008-09-12 00:14:54 +0200 Stephan Bosch <stephan@rename-it.nl> (99fbcb16)
+
+ Relational: fixed portability issue in count match type (warning).
+
+
+M src/lib-sieve/plugins/relational/mcht-count.c
+
+2008-09-10 00:12:11 +0200 Stephan Bosch <stephan@rename-it.nl> (2ed474f1)
+
+ Updated documentation.
+
+
+M README
+
+2008-09-10 00:07:44 +0200 Stephan Bosch <stephan@rename-it.nl> (41236087)
+
+ Devised simple log rotation to prevent per-user sieve processing logs to
+ grow indefinitely.
+
+
+M TODO
+M src/lib-sieve/sieve-error.c
+
+2008-09-09 23:36:22 +0200 Stephan Bosch <stephan@rename-it.nl> (c6edfbd3)
+
+ Updated TODO list.
+
+
+M TODO
+
+2008-09-09 21:52:49 +0200 Stephan Bosch <stephan@rename-it.nl> (5d7ae356)
+
+ Improved byte code dumping to be more readable.
+
+
+M TODO
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/testsuite-objects.c
+M src/testsuite/tst-test-compile.c
+M src/testsuite/tst-test-error.c
+
+2008-09-09 20:37:28 +0200 Stephan Bosch <stephan@rename-it.nl> (5ac2b5d0)
+
+ Updated TODO file.
+
+
+M TODO
+
+2008-09-07 23:51:20 +0200 Stephan Bosch <stephan@rename-it.nl> (c2aa6250)
+
+ Updated documentation.
+
+
+M INSTALL
+M README
+M TODO
+
+2008-09-07 23:44:09 +0200 Stephan Bosch <stephan@rename-it.nl> (f1a46b60)
+
+ Removed redundant security issue listed in TODO.
+
+
+M TODO
+
+2008-09-07 23:43:33 +0200 Stephan Bosch <stephan@rename-it.nl> (a3bd699e)
+
+ Resolved handling of invalid addresses in headers for the most part.
+
+
+M Makefile.am
+M TODO
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/sieve-address-parts.c
+A tests/address.svtest
+
+2008-09-07 15:41:59 +0200 Stephan Bosch <stephan@rename-it.nl> (f6e23af1)
+
+ Variables: made sure broken/malicious binary cannot allocate variable
+ storage of arbitrary size.
+
+
+M TODO
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2008-09-07 15:13:26 +0200 Stephan Bosch <stephan@rename-it.nl> (d1e1d88e)
+
+ Variables: added coding of variable scope.
+
+
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+
+2008-09-07 14:00:27 +0200 Stephan Bosch <stephan@rename-it.nl> (4f576f76)
+
+ Added support for per-script extension intialization.
+
+
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-match-types.c
+M src/testsuite/ext-testsuite.c
+
+2008-09-06 13:54:10 +0200 Stephan Bosch <stephan@rename-it.nl> (90c44cdc)
+
+ Reduced the severity of the warning indicating the experimental nature of
+ this implementation.
+
+
+M INSTALL
+M README
+
+2008-09-06 13:48:31 +0200 Stephan Bosch <stephan@rename-it.nl> (b27ff823)
+
+ Updated TODO.
+
+
+M TODO
+
+2008-08-31 22:10:21 +0200 Stephan Bosch <stephan@rename-it.nl> (fe7db221)
+
+ Minor cosmetic change to code dumping.
+
+
+M src/lib-sieve/sieve-code-dumper.c
+
+2008-08-31 22:07:20 +0200 Stephan Bosch <stephan@rename-it.nl> (acf33c8b)
+
+ Added the concept of a script code header to list the extensions actually
+ used by a script (was using all extensions listed in the binary).
+
+
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite.c
+
+2008-08-31 19:09:46 +0200 Stephan Bosch <stephan@rename-it.nl> (3be89fef)
+
+ Revised implementation of the require command.
+
+
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-validator.c
+
+2008-08-31 16:52:55 +0200 Stephan Bosch <stephan@rename-it.nl> (7c41ad4c)
+
+ Vacation: properly implemented handling of variables vs. handle generation.
+
+
+M Makefile.am
+M TODO
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+A tests/extensions/vacation/execute.svtest
+A tests/extensions/vacation/execute/no-handle.sieve
+
+2008-08-31 16:52:23 +0200 Stephan Bosch <stephan@rename-it.nl> (45e617d9)
+
+ Forgot to add niet testsuite files.
+
+
+A tests/extensions/imapflags/execute.svtest
+A tests/extensions/imapflags/execute/flags-side-effect.sieve
+
+2008-08-31 16:08:02 +0200 Stephan Bosch <stephan@rename-it.nl> (dc61b367)
+
+ Added support for runtime detection of variable strings.
+
+
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+
+2008-08-31 15:56:09 +0200 Stephan Bosch <stephan@rename-it.nl> (66e546f2)
+
+ Updated TODO.
+
+
+M TODO
+
+2008-08-31 15:43:23 +0200 Stephan Bosch <stephan@rename-it.nl> (7e424263)
+
+ Imapflags: properly implemented handling of duplicate store actions with
+ different :flags.
+
+
+M Makefile.am
+M TODO
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-result.c
+
+2008-08-30 15:34:27 +0200 Stephan Bosch <stephan@rename-it.nl> (afc00f9f)
+
+ Fixed assertion triggered at the end when redirect was executed before.
+
+
+M src/lib-sieve/cmd-redirect.c
+
+2008-08-30 15:22:33 +0200 Stephan Bosch <stephan@rename-it.nl> (395def89)
+
+ Incorporated changes in deliver into the mail-raw implementation of the
+ sieve tools.
+
+
+M src/sieve-bin/mail-raw.c
+M src/sieve-bin/mail-raw.h
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+
+2008-08-26 22:40:03 +0200 Stephan Bosch <stephan@rename-it.nl> (4b052f04)
+
+ Imapflags: Added FIXME.
+
+
+M TODO
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+
+2008-08-26 22:11:29 +0200 Stephan Bosch <stephan@rename-it.nl> (51030fce)
+
+ Implemented policy limit on the maximum number of redirect actions in a
+ result.
+
+
+M TODO
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M tests/execute/errors.svtest
+M tests/execute/errors/actions-limit.sieve
+A tests/execute/errors/redirect-limit.sieve
+
+2008-08-26 21:36:59 +0200 Stephan Bosch <stephan@rename-it.nl> (987e8c52)
+
+ Implemented limit on the number of actions active simultaneously.
+
+
+M src/lib-sieve/Makefile.am
+A src/lib-sieve/sieve-limits.c
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-result.c
+M tests/execute/errors.svtest
+A tests/execute/errors/actions-limit.sieve
+
+2008-08-26 20:36:39 +0200 Stephan Bosch <stephan@rename-it.nl> (3d88888a)
+
+ Include: fixed a stupid bug triggered when variables are not used.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+A tests/extensions/include/errors/action-conflicts.sieve
+A tests/extensions/include/errors/included/action-fileinto.sieve
+A tests/extensions/include/errors/included/action-reject.sieve
+D tests/extensions/include/errors/runtime.sieve
+
+2008-08-26 20:04:22 +0200 Stephan Bosch <stephan@rename-it.nl> (6011d823)
+
+ Testsuite: activated runtime tests for the include extension.
+
+
+M tests/extensions/include/errors.svtest
+
+2008-08-26 19:52:25 +0200 Stephan Bosch <stephan@rename-it.nl> (a97f7c97)
+
+ Testsuite: added runtime error tests for vacation extension.
+
+
+M Makefile.am
+A tests/extensions/vacation/errors.svtest
+A tests/extensions/vacation/errors/conflict-reject.sieve
+
+2008-08-26 17:04:27 +0200 Stephan Bosch <stephan@rename-it.nl> (7170fd88)
+
+ Testsuite: added simple runtime action conflict tests.
+
+
+M Makefile.am
+A tests/execute/errors.svtest
+R050 tests/execute/errors/action-conflicts.sieve tests/execute/errors/conflict-reject-fileinto.sieve
+A tests/execute/errors/conflict-reject-keep.sieve
+A tests/execute/errors/conflict-reject-redirect.sieve
+
+2008-08-26 17:02:38 +0200 Stephan Bosch <stephan@rename-it.nl> (abae653f)
+
+ Installed refuse-reject draft RFC in doc/rfc directory.
+
+
+A doc/rfc/draft-ietf-sieve-refuse-reject-07.txt
+
+2008-08-25 17:50:51 +0200 Stephan Bosch <stephan@rename-it.nl> (cf7d2f83)
+
+ Testsuite: added support for testing runtime errors.
+
+
+M src/lib-sieve/sieve-interpreter.c
+M src/testsuite/Makefile.am
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite.c
+A src/testsuite/tst-test-execute.c
+R061 sieve/errors/action-conflicts.sieve tests/execute/errors/action-conflicts.sieve
+R100 sieve/errors/action-duplicates.sieve tests/execute/errors/action-duplicates.sieve
+
+2008-08-25 13:25:19 +0200 Stephan Bosch <stephan@rename-it.nl> (682dfe3d)
+
+ Vacation: discovered and partially fixed various RFC-related issues.
+
+
+M TODO
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+
+2008-08-25 12:41:30 +0200 Stephan Bosch <stephan@rename-it.nl> (7db9c846)
+
+ Installed new RFC for vacation extension in doc/rfc directory.
+
+
+R069 src/lib-sieve/plugins/vacation/draft-ietf-sieve-vacation-07.txt doc/rfc/vacation.rfc5230.txt
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+
+2008-08-25 12:30:17 +0200 Stephan Bosch <stephan@rename-it.nl> (4c312848)
+
+ Updated TODO.
+
+
+M TODO
+
+2008-08-25 12:28:52 +0200 Stephan Bosch <stephan@rename-it.nl> (e24042e2)
+
+ Finished code cleanup for now.
+
+
+M TODO
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/mail-raw.c
+M src/testsuite/mail-raw.h
+M src/testsuite/namespaces.c
+M src/testsuite/namespaces.h
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-compile.c
+M src/testsuite/tst-test-error.c
+
+2008-08-25 12:15:46 +0200 Stephan Bosch <stephan@rename-it.nl> (badedb46)
+
+ Cleaned up Sieve tools.
+
+
+M src/sieve-bin/bin-common.c
+M src/sieve-bin/bin-common.h
+M src/sieve-bin/mail-raw.c
+M src/sieve-bin/mail-raw.h
+M src/sieve-bin/namespaces.c
+M src/sieve-bin/namespaces.h
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+M src/sieve-bin/sievec.c
+M src/sieve-bin/sieved.c
+
+2008-08-25 12:01:35 +0200 Stephan Bosch <stephan@rename-it.nl> (a56cf623)
+
+ Cleaned up LDA Sieve plugin.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.h
+
+2008-08-25 11:55:55 +0200 Stephan Bosch <stephan@rename-it.nl> (c4123b21)
+
+ Cleaned up variables extension.
+
+
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+
+2008-08-25 11:23:47 +0200 Stephan Bosch <stephan@rename-it.nl> (d346afab)
+
+ Vacation: removed useless duplicate_mark call.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+
+2008-08-25 11:13:19 +0200 Stephan Bosch <stephan@rename-it.nl> (39c91487)
+
+ Cleaned up vacation extension.
+
+
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+
+2008-08-18 00:05:57 +0200 Stephan Bosch <stephan@rename-it.nl> (b023088a)
+
+ Testsuite: extended tests for the subaddress extension.
+
+
+M Makefile.am
+A sieve/examples/subaddress.rfc5233.sieve
+M tests/compile/examples.svtest
+R100 tests/address-parts/subaddress.svtest tests/extensions/subaddress/basic.svtest
+A tests/extensions/subaddress/rfc.svtest
+
+2008-08-17 23:46:10 +0200 Stephan Bosch <stephan@rename-it.nl> (fa36892b)
+
+ Installed new subaddress RFC in doc/rfc directory.
+
+
+A doc/rfc/subaddress.rfc5233.txt
+D src/lib-sieve/plugins/subaddress/rfc3598.txt
+
+2008-08-17 23:44:02 +0200 Stephan Bosch <stephan@rename-it.nl> (c2d12799)
+
+ Cleaned up subaddress extension.
+
+
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+
+2008-08-17 23:37:10 +0200 Stephan Bosch <stephan@rename-it.nl> (16553960)
+
+ Testsuite: restructured and extended tests for the relational extension.
+
+
+M Makefile.am
+A sieve/examples/relational.rfc5231.sieve
+R086 tests/compile/compile-examples.svtest tests/compile/examples.svtest
+R100 tests/match-types/relational.svtest tests/extensions/relational/basic.svtest
+A tests/extensions/relational/errors.svtest
+A tests/extensions/relational/errors/validation.sieve
+A tests/extensions/relational/rfc.svtest
+
+2008-08-17 23:09:25 +0200 Stephan Bosch <stephan@rename-it.nl> (969153d7)
+
+ Installed new relational RFC in doc/rfc directory.
+
+
+A doc/rfc/relational.rfc5231.txt
+D src/lib-sieve/plugins/relational/rfc3431.txt
+
+2008-08-17 23:03:21 +0200 Stephan Bosch <stephan@rename-it.nl> (60278d79)
+
+ Cleaned up relational extension.
+
+
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+
+2008-08-17 22:54:18 +0200 Stephan Bosch <stephan@rename-it.nl> (0031692b)
+
+ Cleaned up regex extension.
+
+
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+
+2008-08-17 22:41:33 +0200 Stephan Bosch <stephan@rename-it.nl> (78bbdc89)
+
+ Cleaned up include extension.
+
+
+M src/lib-sieve/plugins/include/cmd-import.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-limits.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+
+2008-08-17 19:31:10 +0200 Stephan Bosch <stephan@rename-it.nl> (eb2f38ca)
+
+ Cleaned up imapflags extension.
+
+
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+
+2008-08-17 19:03:50 +0200 Stephan Bosch <stephan@rename-it.nl> (43aedf5b)
+
+ Cleaned up copy extension.
+
+
+M src/lib-sieve/plugins/copy/ext-copy.c
+
+2008-08-17 18:52:38 +0200 Stephan Bosch <stephan@rename-it.nl> (91888b9d)
+
+ Cleaned up comparator-i;ascii-numeric.
+
+
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+
+2008-08-16 20:47:26 +0200 Stephan Bosch <stephan@rename-it.nl> (75233d72)
+
+ Forgot to add test file.
+
+
+A tests/extensions/body/match-values.svtest
+
+2008-08-16 20:46:59 +0200 Stephan Bosch <stephan@rename-it.nl> (bfc6d259)
+
+ Testsuite: added test for the behavior of the body test with match values.
+
+
+M Makefile.am
+
+2008-08-16 20:36:29 +0200 Stephan Bosch <stephan@rename-it.nl> (47d3a843)
+
+ Body: now disables match value processing during body test evaluation as
+ required by RFC.
+
+
+M src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/sieve-match-types.c
+
+2008-08-16 20:12:08 +0200 Stephan Bosch <stephan@rename-it.nl> (f7ae127f)
+
+ Finished code cleanup of the sieve library itself.
+
+
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+
+2008-08-16 19:31:55 +0200 Stephan Bosch <stephan@rename-it.nl> (151d4705)
+
+ Broad code cleanup.
+
+
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+
+2008-08-16 18:41:02 +0200 Stephan Bosch <stephan@rename-it.nl> (c4c7722f)
+
+ Forgot to add new file for stop command.
+
+
+A src/lib-sieve/cmd-stop.c
+
+2008-08-16 18:40:25 +0200 Stephan Bosch <stephan@rename-it.nl> (1fe262fe)
+
+ Cleaned up commands implementation.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/include/cmd-import.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-code-dumper.c
+D src/lib-sieve/sieve-commands-private.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/tst-test-compile.c
+M src/testsuite/tst-test-error.c
+
+2008-08-16 16:08:35 +0200 Stephan Bosch <stephan@rename-it.nl> (17c6bc69)
+
+ Cleaned up sieve-code.
+
+
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+
+2008-08-16 15:46:37 +0200 Stephan Bosch <stephan@rename-it.nl> (e6a1cd52)
+
+ Cleaned up sieve-binary-dumper.
+
+
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+
+2008-08-16 15:42:23 +0200 Stephan Bosch <stephan@rename-it.nl> (e04f3bfe)
+
+ Cleaned up sieve-binary.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+
+2008-08-16 15:30:15 +0200 Stephan Bosch <stephan@rename-it.nl> (cda64c34)
+
+ Cleaned up sieve-ast.
+
+
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+
+2008-08-16 15:10:05 +0200 Stephan Bosch <stephan@rename-it.nl> (211fafea)
+
+ Cleaned up sieve-address.
+
+
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+
+2008-08-16 15:01:01 +0200 Stephan Bosch <stephan@rename-it.nl> (680c052b)
+
+ Cleaned up actions implementation.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+
+2008-08-16 14:41:35 +0200 Stephan Bosch <stephan@rename-it.nl> (0d246fa2)
+
+ Cleaned up address part and comparator implementation.
+
+
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-comparators.c
+
+2008-08-16 14:33:40 +0200 Stephan Bosch <stephan@rename-it.nl> (ad66ace5)
+
+ Cleaned up match type implementation.
+
+
+D sieve/errors/match-type-errors.sieve
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+M src/testsuite/tst-test-error.c
+M tests/compile/errors.svtest
+A tests/compile/errors/match-type.sieve
+
+2008-08-16 13:28:51 +0200 Stephan Bosch <stephan@rename-it.nl> (4001d8dd)
+
+ Regex: improvements and bugfixes.
+
+
+M TODO
+M src/lib-sieve/plugins/regex/mcht-regex.c
+
+2008-08-16 12:49:35 +0200 Stephan Bosch <stephan@rename-it.nl> (64ab6616)
+
+ Testsuite: restructured regex tests.
+
+
+M Makefile.am
+R100 tests/match-types/regex.svtest tests/extensions/regex/basic.svtest
+A tests/extensions/regex/errors.svtest
+R100 src/lib-sieve/plugins/regex/regex-errors.sieve tests/extensions/regex/errors/compile.sieve
+
+2008-08-16 12:29:06 +0200 Stephan Bosch <stephan@rename-it.nl> (556da050)
+
+ Regex: fixed a few minor bugs.
+
+
+M Makefile.am
+R100 src/lib-sieve/plugins/regex/draft-murchison-sieve-regex-07.txt doc/rfc/draft-murchison-sieve-regex-07.txt
+M src/lib-sieve/plugins/regex/mcht-regex.c
+D src/lib-sieve/plugins/regex/regex.sieve
+M src/lib-sieve/sieve-match-types.c
+A tests/extensions/variables/regex.svtest
+M tests/match-types/regex.svtest
+
+2008-08-14 01:35:12 +0200 Stephan Bosch <stephan@rename-it.nl> (9c6afd6b)
+
+ Compile fix for changes in Dovecot.
+
+
+M src/sieve-bin/mail-raw.c
+M src/sieve-bin/mail-raw.h
+M src/sieve-bin/namespaces.c
+M src/sieve-bin/namespaces.h
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+M src/testsuite/mail-raw.c
+M src/testsuite/mail-raw.h
+M src/testsuite/namespaces.c
+M src/testsuite/namespaces.h
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite.c
+
+2008-08-13 23:50:15 +0200 Stephan Bosch <stephan@rename-it.nl> (d728be0d)
+
+ Include: implemented runtime checking of export/import.
+
+
+M TODO
+M src/lib-sieve/plugins/include/cmd-import.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+A tests/extensions/include/errors/runtime.sieve
+
+2008-08-13 22:51:59 +0200 Stephan Bosch <stephan@rename-it.nl> (d532a1e6)
+
+ Include: transformed import and export to actual code operations for runtime
+ checking.
+
+
+M src/lib-sieve/plugins/include/cmd-import.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-validator.c
+M tests/extensions/include/variables.svtest
+
+2008-08-13 00:20:23 +0200 Stephan Bosch <stephan@rename-it.nl> (efa202a1)
+
+ Variables: added functionality to obtain variable identifier from storage
+ using linked scope.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2008-08-13 00:08:39 +0200 Stephan Bosch <stephan@rename-it.nl> (e82940d9)
+
+ Variables: invalid variable indexes now trigger interpretation to fail with
+ EXEC_BIN_CORRUPT.
+
+
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2008-08-12 23:44:46 +0200 Stephan Bosch <stephan@rename-it.nl> (6aa6745d)
+
+ Include: variable indexes are now verified to the global variable scope,
+ meaning that a corrupt binary cannot allocate arbitrary global variables
+ anymore.
+
+
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+
+2008-08-12 23:23:01 +0200 Stephan Bosch <stephan@rename-it.nl> (6cef9457)
+
+ Removed obsoleted runtime_load() extension event.
+
+
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-match-types.c
+M src/testsuite/ext-testsuite.c
+
+2008-08-12 23:12:17 +0200 Stephan Bosch <stephan@rename-it.nl> (de5f14ed)
+
+ Added run() event to the interpreter_extension object.
+
+
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-match-types.c
+
+2008-08-12 22:18:50 +0200 Stephan Bosch <stephan@rename-it.nl> (501ff34c)
+
+ Cleaned up TODO file.
+
+
+M TODO
+
+2008-08-12 22:14:35 +0200 Stephan Bosch <stephan@rename-it.nl> (de454e6f)
+
+ Variables: implemented limits on number of variables in a scope, the length
+ of variable names, size of variable values and the number of accesible match
+ values.
+
+
+M TODO
+M doc/rfc/RFC Controversy.txt
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/variables/Makefile.am
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+A src/lib-sieve/plugins/variables/ext-variables-limits.h
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M tests/extensions/variables/basic.svtest
+M tests/extensions/variables/errors.svtest
+A tests/extensions/variables/errors/limits.sieve
+
+2008-08-12 19:51:56 +0200 Stephan Bosch <stephan@rename-it.nl> (2f3c95e5)
+
+ Limited number of accepted match values
+
+
+M TODO
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/include/Makefile.am
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-match-types.c
+
+2008-08-12 19:04:37 +0200 Stephan Bosch <stephan@rename-it.nl> (2fcb69aa)
+
+ Include: forgot to add new file to the repository.
+
+
+A src/lib-sieve/plugins/include/ext-include-limits.h
+
+2008-08-12 19:03:12 +0200 Stephan Bosch <stephan@rename-it.nl> (e91c056f)
+
+ Merged concurrent changes.
+
+
+2008-08-12 19:02:12 +0200 Stephan Bosch <stephan@rename-it.nl> (1307169e)
+
+ Include: limited the number of included scripts.
+
+
+M TODO
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+
+2008-08-12 00:56:25 +0200 Stephan Bosch <stephan@rename-it.nl> (85d12ee4)
+
+ LDA-Plugin: prevented plugin from polluting the logfiles when the script
+ does not exist.
+
+
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-bin/bin-common.c
+
+2008-08-11 00:11:57 +0200 Stephan Bosch <stephan@rename-it.nl> (de2e6138)
+
+ Include: used wrong messaging function in previous commit.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+M tests/extensions/include/errors.svtest
+M tests/extensions/include/errors/generic.sieve
+
+2008-08-11 00:05:22 +0200 Stephan Bosch <stephan@rename-it.nl> (01ce939b)
+
+ Include: prohibited use of '/' in scriptnames.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+
+2008-08-10 22:12:24 +0200 Stephan Bosch <stephan@rename-it.nl> (3f062944)
+
+ Body: discovered various issues (listed in disabled tests).
+
+
+M TODO
+M tests/extensions/body/basic.svtest
+
+2008-08-10 21:34:17 +0200 Stephan Bosch <stephan@rename-it.nl> (d15163da)
+
+ Body: added test regarding empty bodies and fixed testsuite to flush the
+ message context when the message is changed.
+
+
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/testsuite/cmd-test-set.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+M tests/extensions/body/basic.svtest
+
+2008-08-10 20:44:56 +0200 Stephan Bosch <stephan@rename-it.nl> (60316c19)
+
+ Body: fixed default comparator and added testsuite test to prevent this in
+ the future.
+
+
+M src/lib-sieve/plugins/body/tst-body.c
+M tests/extensions/body/basic.svtest
+
+2008-08-10 20:20:54 +0200 Stephan Bosch <stephan@rename-it.nl> (a6ccf5ae)
+
+ Body: fixed bug in the :raw transform, added much comment to the body
+ extraction code and added a first simple test to the testsuite.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/tst-body.c
+A tests/extensions/body/basic.svtest
+
+2008-08-10 18:52:13 +0200 Stephan Bosch <stephan@rename-it.nl> (97b967b5)
+
+ Made the lexer conform to the new Sieve RFC.
+
+
+M src/lib-sieve/sieve-lexer.c
+M src/testsuite/mail-raw.c
+
+2008-08-10 14:43:06 +0200 Stephan Bosch <stephan@rename-it.nl> (84fab47c)
+
+ Installed RFC for the body extension in the doc/rfc directory.
+
+
+A doc/rfc/body.rfc5173.txt
+D src/lib-sieve/plugins/body/draft-ietf-sieve-body-07.txt
+M src/lib-sieve/plugins/body/ext-body.c
+
+2008-08-10 13:35:55 +0200 Stephan Bosch <stephan@rename-it.nl> (d9c6094e)
+
+ Made sure error messages do not print large erroneous values.
+
+
+M TODO
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/tst-address.c
+
+2008-08-10 11:54:28 +0200 Stephan Bosch <stephan@rename-it.nl> (287f7c2e)
+
+ Limited the depth of the AST and added tests to verify that it is resolved
+ gracefully.
+
+
+M TODO
+M src/lib-sieve/sieve-parser.c
+M tests/compile/errors.svtest
+M tests/compile/errors/parser.sieve
+
+2008-08-09 20:31:22 +0200 Stephan Bosch <stephan@rename-it.nl> (6e979c25)
+
+ Limited number of command arguments.
+
+
+M src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-parser.c
+M tests/compile/errors.svtest
+A tests/compile/errors/parser.sieve
+
+2008-08-09 19:40:20 +0200 Stephan Bosch <stephan@rename-it.nl> (ad194526)
+
+ Made lexer use the (i_*) ctype.h functions.
+
+
+M src/lib-sieve/sieve-lexer.c
+
+2008-08-09 18:51:39 +0200 Stephan Bosch <stephan@rename-it.nl> (4d8f8da7)
+
+ Limited the length of identifiers.
+
+
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-limits.h
+M tests/compile/errors.svtest
+M tests/compile/errors/lexer.sieve
+
+2008-08-09 17:34:13 +0200 Stephan Bosch <stephan@rename-it.nl> (2bdf696e)
+
+ Enforced limits on string length and handled the finite nature of integers
+ for number parsing and the construction of the AST.
+
+
+M TODO
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-lexer.c
+A src/lib-sieve/sieve-limits.h
+M src/lib-sieve/sieve-parser.c
+M tests/compile/errors.svtest
+A tests/compile/errors/lexer.sieve
+
+2008-08-06 00:00:40 +0200 Stephan Bosch <stephan@rename-it.nl> (fe0422ab)
+
+ Include: fixed bug in global variables referencing the main script.
+
+
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-variables.c
+
+2008-08-05 23:12:00 +0200 Stephan Bosch <stephan@rename-it.nl> (85b8865c)
+
+ Include: symbol table for global variables now also includes locations for
+ the first import/export of each known variable.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M tests/extensions/include/variables.svtest
+
+2008-08-05 22:32:19 +0200 Stephan Bosch <stephan@rename-it.nl> (af990c23)
+
+ Include: included scripts are now referenced by an include_id in stead of
+ the binary block id.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+
+2008-08-05 21:25:47 +0200 Stephan Bosch <stephan@rename-it.nl> (e0a8b6be)
+
+ Forgot to implement free() event for validator and interpreter extensions.
+
+
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-validator.c
+
+2008-08-05 20:15:09 +0200 Stephan Bosch <stephan@rename-it.nl> (5b195b1c)
+
+ Include: added symbol table to the binary for global variables.
+
+
+M src/lib-sieve/plugins/include/cmd-import.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/testsuite/ext-testsuite.c
+M tests/extensions/include/errors.svtest
+A tests/extensions/include/errors/import-runtime.sieve
+M tests/extensions/include/errors/variables.sieve
+
+2008-08-05 10:02:25 +0200 Stephan Bosch <stephan@rename-it.nl> (33ec65c7)
+
+ Updated documentation.
+
+
+M README
+M TODO
+
+2008-08-03 23:33:47 +0200 Stephan Bosch <stephan@rename-it.nl> (f475b6da)
+
+ Minor TODO file revisions.
+
+
+M TODO
+
+2008-08-03 23:21:02 +0200 Stephan Bosch <stephan@rename-it.nl> (c1e6e217)
+
+ Testsuite: added match values test for the :regex match
+
+
+M Makefile.am
+A tests/match-types/regex.svtest
+
+2008-08-03 23:15:31 +0200 Stephan Bosch <stephan@rename-it.nl> (ea223592)
+
+ Fixed replacing match values only when a test succeeds.
+
+
+M TODO
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M tests/extensions/variables/match.svtest
+M tests/match-types/matches.svtest
+
+2008-08-03 19:34:01 +0200 Stephan Bosch <stephan@rename-it.nl> (b043e882)
+
+ Upgraded validator and interpreter extension support to provide destruction
+ notifications.
+
+
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+
+2008-08-02 17:24:03 +0200 Stephan Bosch <stephan@rename-it.nl> (e3afed79)
+
+ Include: found one issue.
+
+
+M TODO
+
+2008-08-02 16:22:04 +0200 Stephan Bosch <stephan@rename-it.nl> (e83f2e46)
+
+ Testsuite: added circular include tests.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite.c
+M tests/extensions/include/errors.svtest
+A tests/extensions/include/errors/circular-1.sieve
+A tests/extensions/include/errors/circular-2.sieve
+A tests/extensions/include/errors/circular-3.sieve
+A tests/extensions/include/errors/included/circular-one.sieve
+A tests/extensions/include/errors/included/circular-three-2.sieve
+A tests/extensions/include/errors/included/circular-three-3.sieve
+A tests/extensions/include/errors/included/circular-three.sieve
+A tests/extensions/include/errors/included/circular-two-2.sieve
+A tests/extensions/include/errors/included/circular-two.sieve
+R100 tests/extensions/include/variables-included1.sieve tests/extensions/include/included/variables-included1.sieve
+R100 tests/extensions/include/variables-included2.sieve tests/extensions/include/included/variables-included2.sieve
+R100 tests/extensions/include/variables-included3.sieve tests/extensions/include/included/variables-included3.sieve
+
+2008-08-02 15:48:00 +0200 Stephan Bosch <stephan@rename-it.nl> (a78fd5bb)
+
+ Include: cleaned up source directory.
+
+
+R100 src/lib-sieve/plugins/include/draft-daboo-sieve-include-05.txt doc/rfc/draft-daboo-sieve-include-05.txt
+M src/lib-sieve/plugins/include/Makefile.am
+D src/lib-sieve/plugins/include/include-variables.sieve
+D src/lib-sieve/plugins/include/include-variables1.sieve
+D src/lib-sieve/plugins/include/include-variables2.sieve
+D src/lib-sieve/plugins/include/include-variables3.sieve
+D src/lib-sieve/plugins/include/include.sieve
+D src/lib-sieve/plugins/include/included1.sieve
+D src/lib-sieve/plugins/include/included2.sieve
+D src/lib-sieve/plugins/include/included3.sieve
+M tests/extensions/include/errors.svtest
+R060 src/lib-sieve/plugins/include/include-error.sieve tests/extensions/include/errors/generic.sieve
+
+2008-08-02 15:36:26 +0200 Stephan Bosch <stephan@rename-it.nl> (45c19dad)
+
+ Testsuite: added compile error tests for the include extension.
+
+
+M Makefile.am
+D src/lib-sieve/plugins/include/include-variables-error2.sieve
+A tests/extensions/include/errors.svtest
+R080 src/lib-sieve/plugins/include/include-variables-error.sieve tests/extensions/include/errors/variables-inactive.sieve
+A tests/extensions/include/errors/variables.sieve
+
+2008-08-02 15:35:54 +0200 Stephan Bosch <stephan@rename-it.nl> (718c4b72)
+
+ Copy: forgot to remove RFC from old location.
+
+
+D src/lib-sieve/plugins/copy/rfc3894.txt
+
+2008-08-02 15:34:21 +0200 Stephan Bosch <stephan@rename-it.nl> (a65a1af8)
+
+ Copy: moved RFC to doc/rfc directory.
+
+
+A doc/rfc/copy.rfc3894.txt
+
+2008-08-02 15:12:31 +0200 Stephan Bosch <stephan@rename-it.nl> (2a48ee8c)
+
+ Imapflags: updated specification to RFC 5232.
+
+
+A doc/rfc/imap4flags.rfc5232.txt
+D src/lib-sieve/plugins/imapflags/draft-ietf-sieve-imapflags-05.txt
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+
+2008-08-02 15:04:20 +0200 Stephan Bosch <stephan@rename-it.nl> (d77cbb86)
+
+ Imapflags: found one new issue.
+
+
+M TODO
+
+2008-08-02 14:55:45 +0200 Stephan Bosch <stephan@rename-it.nl> (a22b5d49)
+
+ Imapflags: accidentally omitted support for multiple variables in the
+ hasflag test.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/sieve-generator.c
+R080 tests/extensions/imapflags/rfc.svtest tests/extensions/imapflags/hasflag.svtest
+
+2008-08-02 13:02:22 +0200 Stephan Bosch <stephan@rename-it.nl> (91eb50e0)
+
+ Testsuite: added new tests for the variables extension.
+
+
+M TODO
+M tests/extensions/variables/errors.svtest
+M tests/extensions/variables/errors/set.sieve
+M tests/extensions/variables/string.svtest
+
+2008-08-02 12:41:30 +0200 Stephan Bosch <stephan@rename-it.nl> (0999c475)
+
+ Fixed various case-sensitivily-related issues.
+
+
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-validator.c
+M tests/compile/trivial.sieve
+M tests/extensions/variables/errors.svtest
+
+2008-08-02 12:25:07 +0200 Stephan Bosch <stephan@rename-it.nl> (30c8cf2e)
+
+ Variables: fixed various error handling issues.
+
+
+M Makefile.am
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+A tests/extensions/variables/errors.svtest
+A tests/extensions/variables/errors/namespace.sieve
+A tests/extensions/variables/errors/set.sieve
+
+2008-08-02 12:24:30 +0200 Stephan Bosch <stephan@rename-it.nl> (d1dfd428)
+
+ Fixed a warning.
+
+
+M src/lib-sieve/sieve-address.c
+
+2008-08-01 22:02:55 +0200 Stephan Bosch <stephan@rename-it.nl> (e4ac3052)
+
+ Fixed 'make dist' to produce a working tarball.
+
+
+M Makefile.am
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/variables/Makefile.am
+M src/lib-sieve/plugins/variables/ext-variables.c
+
+2008-08-01 21:22:44 +0200 Stephan Bosch <stephan@rename-it.nl> (5e87e933)
+
+ Testsuite: added test regarding matching the empty string and fixed an issue
+ in the i;ascii-numeric comparator.
+
+
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M tests/match-types/contains.svtest
+M tests/match-types/is.svtest
+M tests/match-types/matches.svtest
+M tests/match-types/relational.svtest
+
+2008-08-01 20:40:36 +0200 Stephan Bosch <stephan@rename-it.nl> (548ad669)
+
+ Variables: fixed :count issue for the string test.
+
+
+M Makefile.am
+M TODO
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M tests/extensions/variables/string.svtest
+
+2008-08-01 20:11:39 +0200 Stephan Bosch <stephan@rename-it.nl> (8b678f10)
+
+ Testsuite: added more tests for the variables extension and found one issue.
+
+
+M TODO
+M tests/extensions/variables/basic.svtest
+M tests/extensions/variables/modifiers.svtest
+A tests/extensions/variables/string.svtest
+
+2008-08-01 19:25:36 +0200 Stephan Bosch <stephan@rename-it.nl> (6f1a5e10)
+
+ Testsuite: added RFC compliance tests for the variables extension and fixed
+ use of wrong default comparator.
+
+
+M Makefile.am
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+M tests/extensions/variables/basic.svtest
+M tests/extensions/variables/match.svtest
+A tests/extensions/variables/modifiers.svtest
+M tests/match-types/contains.svtest
+
+2008-08-01 17:54:40 +0200 Stephan Bosch <stephan@rename-it.nl> (353c11c7)
+
+ Fixed bug in the order of default argument processing. Variable strings were
+ evaluated befor constant strings, which is wrong.
+
+
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/sieve-validator.c
+A tests/extensions/variables/quoting.svtest
+
+2008-08-01 16:32:58 +0200 Stephan Bosch <stephan@rename-it.nl> (5e3518f2)
+
+ Envelope: added more test and fixed source route parsing.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/sieve-address.c
+M tests/extensions/envelope.svtest
+
+2008-08-01 02:26:16 +0200 Stephan Bosch <stephan@rename-it.nl> (be8b4eb0)
+
+ Envelope: fixed one bug in the path parsing (printfs active).
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/sieve-address.c
+M tests/extensions/envelope.svtest
+
+2008-07-31 10:44:17 +0200 Stephan Bosch <stephan@rename-it.nl> (d65ee78e)
+
+ Envelope: working towards proper RFC compliance of forward/return-path
+ parsing.
+
+
+M TODO
+M doc/rfc/RFC Controversy.txt
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-common.h
+M tests/extensions/envelope.svtest
+M tests/testsuite.svtest
+
+2008-07-29 23:05:05 +0200 Stephan Bosch <stephan@rename-it.nl> (51a0cc34)
+
+ Variables: fixed RFC compliance issue regarding failing validation on
+ unknown namespaces.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M tests/extensions/variables/basic.svtest
+
+2008-07-29 22:38:44 +0200 Stephan Bosch <stephan@rename-it.nl> (71e66c81)
+
+ Variables: fixed bug in variables substitution (RFC example failed during
+ testing).
+
+
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M tests/extensions/variables/basic.svtest
+
+2008-07-29 22:21:32 +0200 Stephan Bosch <stephan@rename-it.nl> (b29320f2)
+
+ Variables: fixed very significant bug in the variable scope implementation.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M tests/extensions/variables/basic.svtest
+
+2008-07-29 22:21:04 +0200 Stephan Bosch <stephan@rename-it.nl> (a1c77607)
+
+ Removed superfluous include.
+
+
+M src/lib-sieve/sieve-binary.h
+
+2008-07-29 19:32:30 +0200 Stephan Bosch <stephan@rename-it.nl> (e64a9b8f)
+
+ Testsuite: cleaned up basic varibles test case.
+
+
+M tests/extensions/variables/basic.svtest
+
+2008-07-29 19:15:35 +0200 Stephan Bosch <stephan@rename-it.nl> (a4faba00)
+
+ Testsuite: moved tests directory to the root of the package.
+
+
+M Makefile.am
+M configure.in
+M src/testsuite/Makefile.am
+R100 src/testsuite/tests/address-parts/subaddress.svtest tests/address-parts/subaddress.svtest
+R100 src/testsuite/tests/comparators/core.svtest tests/comparators/core.svtest
+R052 src/testsuite/tests/compile/compile-examples.svtest tests/compile/compile-examples.svtest
+R100 src/testsuite/tests/compile/compile.svtest tests/compile/compile.svtest
+R100 src/testsuite/tests/compile/errors.svtest tests/compile/errors.svtest
+R100 src/testsuite/tests/compile/errors/address-part.sieve tests/compile/errors/address-part.sieve
+R100 src/testsuite/tests/compile/errors/address.sieve tests/compile/errors/address.sieve
+R100 src/testsuite/tests/compile/errors/encoded-character.sieve tests/compile/errors/encoded-character.sieve
+R100 src/testsuite/tests/compile/errors/envelope.sieve tests/compile/errors/envelope.sieve
+R100 src/testsuite/tests/compile/errors/header.sieve tests/compile/errors/header.sieve
+R100 src/testsuite/tests/compile/errors/if.sieve tests/compile/errors/if.sieve
+R100 src/testsuite/tests/compile/errors/keep.sieve tests/compile/errors/keep.sieve
+R100 src/testsuite/tests/compile/errors/require.sieve tests/compile/errors/require.sieve
+R100 src/testsuite/tests/compile/errors/size.sieve tests/compile/errors/size.sieve
+R100 src/testsuite/tests/compile/errors/stop.sieve tests/compile/errors/stop.sieve
+R100 src/testsuite/tests/compile/redirect.sieve tests/compile/redirect.sieve
+R100 src/testsuite/tests/compile/trivial.sieve tests/compile/trivial.sieve
+R100 src/testsuite/tests/control-structures.svtest tests/control-structures.svtest
+R100 src/testsuite/tests/exists.svtest tests/exists.svtest
+R100 src/testsuite/tests/extensions/encoded-character.svtest tests/extensions/encoded-character.svtest
+R100 src/testsuite/tests/extensions/envelope.svtest tests/extensions/envelope.svtest
+R100 src/testsuite/tests/extensions/imapflags/basic.svtest tests/extensions/imapflags/basic.svtest
+R100 src/testsuite/tests/extensions/imapflags/rfc.svtest tests/extensions/imapflags/rfc.svtest
+R100 src/testsuite/tests/extensions/include/variables-included1.sieve tests/extensions/include/variables-included1.sieve
+R100 src/testsuite/tests/extensions/include/variables-included2.sieve tests/extensions/include/variables-included2.sieve
+R100 src/testsuite/tests/extensions/include/variables-included3.sieve tests/extensions/include/variables-included3.sieve
+R100 src/testsuite/tests/extensions/include/variables.svtest tests/extensions/include/variables.svtest
+R100 src/testsuite/tests/extensions/variables/basic.svtest tests/extensions/variables/basic.svtest
+R100 src/testsuite/tests/extensions/variables/match.svtest tests/extensions/variables/match.svtest
+R100 src/testsuite/tests/header.svtest tests/header.svtest
+R100 src/testsuite/tests/lexer.svtest tests/lexer.svtest
+R100 src/testsuite/tests/match-types/contains.svtest tests/match-types/contains.svtest
+R100 src/testsuite/tests/match-types/is.svtest tests/match-types/is.svtest
+R100 src/testsuite/tests/match-types/matches.svtest tests/match-types/matches.svtest
+R100 src/testsuite/tests/match-types/relational.svtest tests/match-types/relational.svtest
+R100 src/testsuite/tests/testsuite.svtest tests/testsuite.svtest
+
+2008-07-29 18:55:47 +0200 Stephan Bosch <stephan@rename-it.nl> (e3b19039)
+
+ Installed variables rfc in the doc/rfc directory.
+
+
+R100 src/lib-sieve/plugins/variables/rfc5229.txt doc/rfc/variables.rfc5229.txt
+
+2008-07-29 17:08:15 +0200 Stephan Bosch <stephan@rename-it.nl> (734239f9)
+
+ Encoded-character: resolved error reporting issue, added some syntax error
+ tests and fixed some parsing bugs in the process.
+
+
+M TODO
+M src/lib-sieve/ext-encoded-character.c
+M src/testsuite/tests/compile/errors/encoded-character.sieve
+M src/testsuite/tests/extensions/encoded-character.svtest
+
+2008-07-29 15:19:28 +0200 Stephan Bosch <stephan@rename-it.nl> (c2c58e59)
+
+ Testsuite: added compile error testcases and discovered one new issue.
+
+
+M TODO
+M src/lib-sieve/ext-encoded-character.c
+M src/testsuite/tests/compile/errors.svtest
+A src/testsuite/tests/compile/errors/address-part.sieve
+A src/testsuite/tests/compile/errors/encoded-character.sieve
+A src/testsuite/tests/compile/errors/envelope.sieve
+A src/testsuite/tests/compile/errors/keep.sieve
+A src/testsuite/tests/compile/errors/size.sieve
+A src/testsuite/tests/compile/errors/stop.sieve
+M src/testsuite/tests/control-structures.svtest
+
+2008-07-29 11:36:26 +0200 Stephan Bosch <stephan@rename-it.nl> (9e2140cb)
+
+ Reprioritized TODO file.
+
+
+M TODO
+
+2008-07-29 11:30:15 +0200 Stephan Bosch <stephan@rename-it.nl> (ea0e6b49)
+
+ Variables: resolved issues in the scope implementation.
+
+
+M TODO
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2008-07-29 10:58:17 +0200 Stephan Bosch <stephan@rename-it.nl> (c4879d7c)
+
+ Added proper extension support to AST object.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+
+2008-07-28 20:39:51 +0200 Stephan Bosch <stephan@rename-it.nl> (f597ac97)
+
+ Testsuite: added a few more compile error test cases.
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-validator.c
+M src/testsuite/tests/compile/errors.svtest
+A src/testsuite/tests/compile/errors/address.sieve
+M src/testsuite/tests/compile/errors/header.sieve
+A src/testsuite/tests/compile/errors/if.sieve
+A src/testsuite/tests/compile/errors/require.sieve
+M src/testsuite/testsuite-common.c
+
+2008-07-28 18:44:23 +0200 Stephan Bosch <stephan@rename-it.nl> (7b048e6c)
+
+ Testsuite: completed support for error validation and added one test case.
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/testsuite/Makefile.am
+R097 src/testsuite/tests/errors.svtest src/testsuite/tests/compile/errors.svtest
+R100 src/testsuite/tests/header-errors.sieve src/testsuite/tests/compile/errors/header.sieve
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite.c
+M src/testsuite/tst-test-compile.c
+M src/testsuite/tst-test-error.c
+
+2008-07-28 16:29:12 +0200 Stephan Bosch <stephan@rename-it.nl> (616b274f)
+
+ Testsuite: started support for error validation.
+
+
+M src/testsuite/Makefile.am
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/ext-testsuite.c
+A src/testsuite/tests/errors.svtest
+A src/testsuite/tests/header-errors.sieve
+M src/testsuite/testsuite-common.h
+M src/testsuite/tst-test-compile.c
+A src/testsuite/tst-test-error.c
+
+2008-07-28 14:59:16 +0200 Stephan Bosch <stephan@rename-it.nl> (43d05ac5)
+
+ Testsuite: marginally improved match-type tests.
+
+
+M TODO
+M src/testsuite/Makefile.am
+M src/testsuite/tests/match-types/contains.svtest
+A src/testsuite/tests/match-types/is.svtest
+
+2008-07-28 12:49:45 +0200 Stephan Bosch <stephan@rename-it.nl> (141a7794)
+
+ Added variables testcase to the testsuite.
+
+
+M src/testsuite/Makefile.am
+
+2008-07-28 12:48:14 +0200 Stephan Bosch <stephan@rename-it.nl> (34fd1a7b)
+
+ Fixed bugs in the :matches match type.
+
+
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+A src/testsuite/tests/extensions/variables/match.svtest
+M src/testsuite/tests/lexer.svtest
+M src/testsuite/tests/match-types/matches.svtest
+
+2008-07-28 00:22:23 +0200 Stephan Bosch <stephan@rename-it.nl> (f153305d)
+
+ Encoded-character: fixed a few bugs to properly match the examples provided
+ in the RFC.
+
+
+M src/lib-sieve/ext-encoded-character.c
+M src/testsuite/Makefile.am
+A src/testsuite/tests/extensions/encoded-character.svtest
+
+2008-07-27 21:53:04 +0200 Stephan Bosch <stephan@rename-it.nl> (8de497f0)
+
+ Added stripping of right white space from header content.
+
+
+M TODO
+M src/lib-sieve/tst-header.c
+
+2008-07-27 18:00:21 +0200 Stephan Bosch <stephan@rename-it.nl> (ed2c80bc)
+
+ Updated TODO
+
+
+M TODO
+
+2008-07-27 17:52:34 +0200 Stephan Bosch <stephan@rename-it.nl> (47b8548c)
+
+ Envelope: forgot to add new test case.
+
+
+A src/testsuite/tests/extensions/envelope.svtest
+
+2008-07-27 17:52:03 +0200 Stephan Bosch <stephan@rename-it.nl> (1118aaef)
+
+ Envelope: <> return path now always matches as the empty string, regardless
+ of the specified address part.
+
+
+M TODO
+M src/lib-sieve/ext-envelope.c
+M src/testsuite/Makefile.am
+
+2008-07-27 17:17:57 +0200 Stephan Bosch <stephan@rename-it.nl> (a924297f)
+
+ Minor TODO file change.
+
+
+M TODO
+
+2008-07-27 17:17:02 +0200 Stephan Bosch <stephan@rename-it.nl> (3b233deb)
+
+ Forgot to adjust comment.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/tst-address.c
+
+2008-07-27 17:15:24 +0200 Stephan Bosch <stephan@rename-it.nl> (b1e91a0a)
+
+ Updated documentation.
+
+
+M doc/rfc/RFC Controversy.txt
+
+2008-07-27 17:12:10 +0200 Stephan Bosch <stephan@rename-it.nl> (7aa007fb)
+
+ Envelope: added compile-time envelope-part verification.
+
+
+M TODO
+M doc/rfc/RFC Controversy.txt
+A sieve/errors/envelope-errors.sieve
+M sieve/examples/elvey.sieve
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/tst-address.c
+
+2008-07-27 16:27:40 +0200 Stephan Bosch <stephan@rename-it.nl> (6a1073f6)
+
+ Added RFC controversy file to log all matters that require clarification
+ from RFC editors.
+
+
+A doc/rfc/RFC Controversy.txt
+
+2008-07-27 16:00:47 +0200 Stephan Bosch <stephan@rename-it.nl> (ae34854c)
+
+ Restricted allowable headers for the address test.
+
+
+M TODO
+
+2008-07-27 15:59:47 +0200 Stephan Bosch <stephan@rename-it.nl> (7a0738ab)
+
+ Imapflags: forgot to add testcase file.
+
+
+M TODO
+M sieve/errors/address-errors.sieve
+M src/lib-sieve/tst-address.c
+A src/testsuite/tests/extensions/imapflags/rfc.svtest
+
+2008-07-27 13:12:07 +0200 Stephan Bosch <stephan@rename-it.nl> (0db3a614)
+
+ Disallowed extraction of key elements from key strings for match types for
+ with that would not make sense.
+
+
+M src/lib-sieve/sieve-match.c
+
+2008-07-27 13:08:33 +0200 Stephan Bosch <stephan@rename-it.nl> (a26cb52c)
+
+ Imapflags: resolved problem of hasflags encountering duplicate flags in flag
+ lists contained in a variable.
+
+
+M TODO
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/testsuite/Makefile.am
+M src/testsuite/tests/extensions/imapflags/basic.svtest
+
+2008-07-27 12:43:29 +0200 Stephan Bosch <stephan@rename-it.nl> (0b2f9a20)
+
+ Imapflags: resolved string representation issue in hasflag.
+
+
+M TODO
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+M src/testsuite/Makefile.am
+M src/testsuite/tests/extensions/imapflags/basic.svtest
+
+2008-07-27 11:50:07 +0200 Stephan Bosch <stephan@rename-it.nl> (778eab7c)
+
+ Resolved code duplication among commands that use comparators and
+ match-types and found problems in the imapflags extension in the process.
+
+
+M TODO
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-match.c
+M src/lib-sieve/sieve-match.h
+M src/lib-sieve/tst-header.c
+A src/testsuite/tests/extensions/imapflags/basic.svtest
+
+2008-07-26 10:28:50 +0200 Stephan Bosch <stephan@rename-it.nl> (a79ccdb9)
+
+ LDA-Sieve plugin: forgot to save the new binary when encountered a corrupt
+ one.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2008-07-26 00:11:06 +0200 Stephan Bosch <stephan@rename-it.nl> (540a6429)
+
+ Improved the handling corrupt binaries further for the action commands.
+
+
+M TODO
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+
+2008-07-25 23:30:26 +0200 Stephan Bosch <stephan@rename-it.nl> (31fb8075)
+
+ Significantly improved handling of old/corrupt binaries and revised matching
+ implementation in the process.
+
+
+M TODO
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+A src/lib-sieve/sieve-match.c
+A src/lib-sieve/sieve-match.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+M src/sieve-bin/sieve-test.c
+M src/testsuite/Makefile.am
+M src/testsuite/tests/control-structures.svtest
+A src/testsuite/tests/match-types/relational.svtest
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite.c
+
+2008-07-25 20:54:21 +0200 Stephan Bosch <stephan@rename-it.nl> (4a5d8262)
+
+ Fixed extremely stupid bug in the i;ascii-numeric comparator.
+
+
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+
+2008-07-25 19:17:20 +0200 Stephan Bosch <stephan@rename-it.nl> (d3d97752)
+
+ Implemented graceful handling of corrupt binaries by the sieve lda plugin.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-interpreter.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+
+2008-07-25 17:38:44 +0200 Stephan Bosch <stephan@rename-it.nl> (8ba069ed)
+
+ Properly configured package name.
+
+
+M configure.in
+
+2008-07-25 17:26:40 +0200 Stephan Bosch <stephan@rename-it.nl> (c17c8361)
+
+ Working towards improving the handling of currupt binaries: defined multiple
+ exit codes for execution functions and defined trace macro for reporting
+ binary corruptions.
+
+
+M TODO
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-types.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+M src/sieve-bin/sieve-exec.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/tst-test-compile.c
+
+2008-07-25 14:23:02 +0200 Stephan Bosch <stephan@rename-it.nl> (4b4530a3)
+
+ Testsuite: forgot to add test cases for include extension.
+
+
+M TODO
+A src/testsuite/tests/extensions/include/variables-included1.sieve
+A src/testsuite/tests/extensions/include/variables-included2.sieve
+A src/testsuite/tests/extensions/include/variables-included3.sieve
+A src/testsuite/tests/extensions/include/variables.svtest
+
+2008-07-25 12:12:33 +0200 Stephan Bosch <stephan@rename-it.nl> (2ff8eeed)
+
+ Fixed code emission for extension-defined variables and removed hardcoded
+ paths from include extension.
+
+
+M TODO
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/testsuite/Makefile.am
+M src/testsuite/testsuite.c
+
+2008-07-25 10:25:47 +0200 Stephan Bosch <stephan@rename-it.nl> (2959236f)
+
+ Added future TODO item.
+
+
+M TODO
+
+2008-07-25 01:05:51 +0200 Stephan Bosch <stephan@rename-it.nl> (dd937bb3)
+
+ Updated TODO and removed spurious FIXME.
+
+
+M TODO
+M src/lib-sieve/sieve-interpreter.h
+
+2008-07-25 00:48:21 +0200 Stephan Bosch <stephan@rename-it.nl> (8c1c6f61)
+
+ Updated documentation.
+
+
+M README
+M src/testsuite/ext-testsuite.c
+
+2008-07-25 00:05:16 +0200 Stephan Bosch <stephan@rename-it.nl> (e38b0bbd)
+
+ Testsuite: added test_compile command to test compilation of scripts.
+
+
+M .hgignore
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/testsuite/Makefile.am
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+A src/testsuite/tests/compile/compile-examples.svtest
+A src/testsuite/tests/compile/compile.svtest
+A src/testsuite/tests/compile/redirect.sieve
+A src/testsuite/tests/compile/trivial.sieve
+M src/testsuite/testsuite-common.h
+A src/testsuite/tst-test-compile.c
+
+2008-07-24 22:59:18 +0200 Stephan Bosch <stephan@rename-it.nl> (1af2938b)
+
+ Revised Sieve address validation functionality.
+
+
+M TODO
+M sieve/errors/out-address-errors.sieve
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-binary.c
+
+2008-07-24 17:48:56 +0200 Stephan Bosch <stephan@rename-it.nl> (c0e64243)
+
+ Started using new str_new_const() function.
+
+
+M README
+M TODO
+M configure.in
+M src/lib-sieve/sieve-binary.c
+
+2008-07-24 17:35:47 +0200 Stephan Bosch <stephan@rename-it.nl> (e6995fc0)
+
+ Imapflags: improved handling of invalid flags.
+
+
+M TODO
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/imapflags/imapflags-errors.sieve
+M src/lib-sieve/plugins/imapflags/imapflags.sieve
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2008-07-24 13:50:03 +0200 Stephan Bosch <stephan@rename-it.nl> (7f089988)
+
+ Significantly improved pool allocation by checking --enable-debug warnings
+ from dovecot.
+
+
+M TODO
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-validator.c
+
+2008-07-24 09:37:56 +0200 Stephan Bosch <stephan@rename-it.nl> (b62a2c59)
+
+ Removed all legacy use of array_create().
+
+
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-validator.c
+
+2008-07-24 08:49:20 +0200 Stephan Bosch <stephan@rename-it.nl> (293e7d6b)
+
+ Lexer: fixed repetitive string alloation problem.
+
+
+M src/lib-sieve/sieve-lexer.c
+
+2008-07-23 18:53:22 +0200 Stephan Bosch <stephan@rename-it.nl> (473c9384)
+
+ Fixed bug introduced by previous change.
+
+
+M src/lib-sieve/sieve-binary.c
+
+2008-07-23 18:38:14 +0200 Stephan Bosch <stephan@rename-it.nl> (73b03bea)
+
+ Reworked operand and operation binary coding functions.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+D src/lib-sieve/sieve-extensions-private.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-match-types.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-objects.c
+
+2008-07-23 13:51:51 +0200 Stephan Bosch <stephan@rename-it.nl> (4a7ba645)
+
+ Fully substituted the use of extension ids with the use of the extension
+ object itself.
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-extensions-private.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-message.c
+M src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+
+2008-07-23 11:38:15 +0200 Stephan Bosch <stephan@rename-it.nl> (be78a55b)
+
+ Made initially assigned extension id available directly from the const
+ extension object itself.
+
+
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-validator.c
+M src/testsuite/ext-testsuite.c
+
+2008-07-23 00:42:51 +0200 Stephan Bosch <stephan@rename-it.nl> (e81dd2cf)
+
+ Reworked previous change into three elegant macros.
+
+
+M TODO
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+
+2008-07-22 20:14:45 +0200 Stephan Bosch <stephan@rename-it.nl> (79d351ae)
+
+ Made utility functions for neatly handing system errors, warnings and
+ notices.
+
+
+M TODO
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-script.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2008-07-22 11:02:20 +0200 Stephan Bosch <stephan@rename-it.nl> (6359fb85)
+
+ Testsuite: added tests for use of allof/anyof with a single test and
+ optimized code generation.
+
+
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/testsuite/tests/control-structures.svtest
+
+2008-07-22 10:38:40 +0200 Stephan Bosch <stephan@rename-it.nl> (9ecbfb56)
+
+ Testsuite: added test case for the header test and found one issue.
+
+
+M TODO
+A src/testsuite/tests/header.svtest
+M src/testsuite/tests/match-types/contains.svtest
+
+2008-07-22 09:43:15 +0200 Stephan Bosch <stephan@rename-it.nl> (630d8e4b)
+
+ Testsuite: added lexer string scan comparison test and fixed lexer bug in
+ the process.
+
+
+M src/lib-sieve/sieve-lexer.c
+M src/testsuite/Makefile.am
+A src/testsuite/tests/lexer.svtest
+
+2008-07-21 23:57:05 +0200 Stephan Bosch <stephan@rename-it.nl> (6e9716f2)
+
+ Testsuite: added some control structure tests involving nesting.
+
+
+M TODO
+M src/testsuite/tests/control-structures.svtest
+
+2008-07-21 23:37:01 +0200 Stephan Bosch <stephan@rename-it.nl> (5a47c74b)
+
+ Testsuite: added tests for 'exists' test and fixed a semantic error in the
+ 'exists' test.
+
+
+M TODO
+M src/lib-sieve/tst-exists.c
+M src/testsuite/Makefile.am
+A src/testsuite/tests/exists.svtest
+M src/testsuite/testsuite-objects.c
+
+2008-07-21 23:19:39 +0200 Stephan Bosch <stephan@rename-it.nl> (3b53c87f)
+
+ Testsuite: tested handling of teststuite envelope environment and fixed bugs
+ in the envelope test in the process.
+
+
+M TODO
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/sieve-address-parts.c
+M src/testsuite/tests/testsuite.svtest
+M src/testsuite/testsuite-objects.c
+
+2008-07-21 21:59:37 +0200 Stephan Bosch <stephan@rename-it.nl> (ed86429a)
+
+ Testsuite: added test case for subadress extension.
+
+
+M src/testsuite/Makefile.am
+A src/testsuite/tests/address-parts/subaddress.svtest
+M src/testsuite/testsuite-common.c
+
+2008-07-21 19:30:16 +0200 Stephan Bosch <stephan@rename-it.nl> (3f15068e)
+
+ Coupled testsuite to 'make test'.
+
+
+M Makefile.am
+M TODO
+M configure.in
+M src/Makefile.am
+M src/testsuite/Makefile.am
+M src/testsuite/tests/testsuite.svtest
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite.c
+
+2008-07-21 17:26:18 +0200 Stephan Bosch <stephan@rename-it.nl> (78c2ac15)
+
+ Cleaned up test and core extension implementations.
+
+
+M sieve/tests/encoded-character.sieve
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+
+2008-07-21 16:11:56 +0200 Stephan Bosch <stephan@rename-it.nl> (5fb4684d)
+
+ Cleaned up command implementations.
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+
+2008-07-21 13:41:43 +0200 Stephan Bosch <stephan@rename-it.nl> (2793a703)
+
+ Fixed handling of script files that are in fact symbolic links.
+
+
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+
+2008-07-21 12:37:57 +0200 Stephan Bosch <stephan@rename-it.nl> (04ac5df4)
+
+ Fixed bug in binary created without a corresponding script object.
+
+
+M src/lib-sieve/sieve-binary.c
+
+2008-07-21 12:23:50 +0200 Stephan Bosch <stephan@rename-it.nl> (a0203d2e)
+
+ Reversed stat() and open() on two occasions to make retrieved stat
+ information guaranteed to be valid for the opened file and added error
+ handling for various close() system calls.
+
+
+M TODO
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-script.c
+
+2008-07-21 02:26:25 +0200 Stephan Bosch <stephan@rename-it.nl> (778874e1)
+
+ Updated TODO list.
+
+
+M TODO
+
+2008-07-21 02:09:28 +0200 Stephan Bosch <stephan@rename-it.nl> (7c33d499)
+
+ Removed various unnecessary includes of <ctype.h> and replaced yey another
+ toupper() with its i_* equivalent.
+
+
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+M src/lib-sieve/plugins/variables/ext-variables-name.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/sieve-actions.c
+
+2008-07-21 01:52:49 +0200 Stephan Bosch <stephan@rename-it.nl> (a4a7eba1)
+
+ Removed direct use of isdigit, isalpha and isalnum and replaced these with
+ their dovecot i_* equivalents to prevent problems on some systems.
+
+
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/variables/ext-variables-name.c
+
+2008-07-21 01:45:08 +0200 Stephan Bosch <stephan@rename-it.nl> (81dc9e2e)
+
+ Updated TODO.
+
+
+M TODO
+
+2008-07-21 01:20:05 +0200 Stephan Bosch <stephan@rename-it.nl> (9f778b94)
+
+ Variables: made set modifiers descendants of the sieve object too.
+
+
+M src/lib-sieve/plugins/variables/Makefile.am
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+A src/lib-sieve/plugins/variables/ext-variables-modifiers.c
+A src/lib-sieve/plugins/variables/ext-variables-modifiers.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/variables-match.sieve
+A src/testsuite/tests/extensions/variables/basic.svtest
+
+2008-07-20 21:37:18 +0200 Stephan Bosch <stephan@rename-it.nl> (966d850b)
+
+ Testsuite: made testsuite objects a descendant from sieve objects.
+
+
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-objects.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+
+2008-07-20 18:32:25 +0200 Stephan Bosch <stephan@rename-it.nl> (a2562989)
+
+ Removed remaining code duplication among comparators, match types and
+ address parts.
+
+
+M TODO
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+
+2008-07-20 17:01:29 +0200 Stephan Bosch <stephan@rename-it.nl> (655f933f)
+
+ Updated TODO list.
+
+
+M TODO
+
+2008-07-20 16:59:49 +0200 Stephan Bosch <stephan@rename-it.nl> (d1bcfc06)
+
+ Made side effects sieve objects too.
+
+
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-objects.c
+M src/lib-sieve/sieve-objects.h
+
+2008-07-20 15:27:02 +0200 Stephan Bosch <stephan@rename-it.nl> (1947ba30)
+
+ Introduced the concept of a sieve object to merge the coding of comparators,
+ match types, address parts and other objects that might need to be
+ represented in byte code (removes lots of code duplication).
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmp-i-ascii-casemap.c
+M src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+A src/lib-sieve/sieve-objects.c
+A src/lib-sieve/sieve-objects.h
+
+2008-07-19 19:43:29 +0200 Stephan Bosch <stephan@rename-it.nl> (c289acca)
+
+ Revised extension support for match-types.
+
+
+M TODO
+M src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/mcht-contains.c
+M src/lib-sieve/mcht-is.c
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/regex/Makefile.am
+A src/lib-sieve/plugins/regex/ext-regex-common.c
+M src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/relational/ext-relational-common.c
+M src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/mcht-count.c
+M src/lib-sieve/plugins/relational/mcht-value.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+
+2008-07-19 16:31:14 +0200 Stephan Bosch <stephan@rename-it.nl> (db760623)
+
+ Cleaned up comparator implementation.
+
+
+M src/lib-sieve/Makefile.am
+A src/lib-sieve/cmp-i-ascii-casemap.c
+A src/lib-sieve/cmp-i-octet.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+
+2008-07-19 15:57:46 +0200 Stephan Bosch <stephan@rename-it.nl> (b4c6eaff)
+
+ Revised extension support for comparators.
+
+
+M TODO
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+A src/testsuite/tests/comparators/core.svtest
+
+2008-07-18 21:31:11 +0200 Stephan Bosch <stephan@rename-it.nl> (a5dba1ca)
+
+ Fixed stupid bug in the match-type context validation.
+
+
+M src/lib-sieve/sieve-comparators.c
+
+2008-07-18 18:32:29 +0200 Stephan Bosch <stephan@rename-it.nl> (37d7c200)
+
+ Made error reporting cleaner by avoiding the scriptname of the main script
+ and indicating that the printed numbers are in fact source code lines.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+A src/lib-sieve/sieve-types.h
+M src/lib-sieve/sieve.h
+
+2008-07-18 12:37:30 +0200 Stephan Bosch <stephan@rename-it.nl> (c71a9299)
+
+ Fixed warnings caused by remaining spurious inline definitions in
+ sieve-validator.h
+
+
+M src/lib-sieve/sieve-validator.h
+
+2008-07-17 17:30:59 +0200 Stephan Bosch <stephan@rename-it.nl> (998fd1b4)
+
+ Code cleanup: parser, lexer, lda-plugin and main interface.
+
+
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2008-07-17 00:02:29 +0200 Stephan Bosch <stephan@rename-it.nl> (536aa183)
+
+ Updated TODO.
+
+
+M TODO
+
+2008-07-16 23:50:54 +0200 Stephan Bosch <stephan@rename-it.nl> (68a97ad7)
+
+ Update INSTALL file.
+
+
+M INSTALL
+
+2008-07-16 23:35:23 +0200 Stephan Bosch <stephan@rename-it.nl> (eece6d40)
+
+ Updated documentation.
+
+
+M README
+M TODO
+
+2008-07-16 23:22:54 +0200 Stephan Bosch <stephan@rename-it.nl> (66156bc7)
+
+ Made runtime errors for action conflicts more user-friendly by adding
+ sourcecode line numbers.
+
+
+M TODO
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2008-07-16 21:02:53 +0200 Stephan Bosch <stephan@rename-it.nl> (86706f81)
+
+ Cleaned up generator code and added emission of source line positions for
+ all actions.
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/testsuite-objects.c
+
+2008-07-14 23:51:56 +0200 Stephan Bosch <stephan@rename-it.nl> (59a8068d)
+
+ Resolved various small issues.
+
+
+M TODO
+M sieve/tests/stop.sieve
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-parser.c
+
+2008-07-14 23:18:52 +0200 Stephan Bosch <stephan@rename-it.nl> (e2bc8e5f)
+
+ Removed last significant printf()s from library code.
+
+
+M TODO
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+M src/testsuite/testsuite.c
+
+2008-07-14 22:33:58 +0200 Stephan Bosch <stephan@rename-it.nl> (79333170)
+
+ Added address normalization to prevent redirect action duplicates.
+
+
+M sieve/tests/actions.sieve
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-result.c
+
+2008-07-14 20:19:25 +0200 Stephan Bosch <stephan@rename-it.nl> (a0dd0dfe)
+
+ Made "INBOX" folder name case-insensitive.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2008-07-14 19:57:37 +0200 Stephan Bosch <stephan@rename-it.nl> (4e78793d)
+
+ Built result print functions thus removing various printf()s.
+
+
+M TODO
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+A src/lib-sieve/plugins/imapflags/imapflags-implicit.sieve
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/sieve-bin/sieve-test.c
+M src/testsuite/testsuite.c
+
+2008-07-14 15:35:33 +0200 Stephan Bosch <stephan@rename-it.nl> (cbca6b3c)
+
+ Removed various printf()s.
+
+
+M TODO
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-result.c
+M src/sieve-bin/sieve-exec.c
+
+2008-07-14 15:09:44 +0200 Stephan Bosch <stephan@rename-it.nl> (e3b369ee)
+
+ Implemented support for side-effects to implicit keep and finished the
+ imapflags extension.
+
+
+M README
+M TODO
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/imapflags/imapflags.sieve
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/sieve-result.c
+
+2008-07-14 12:55:35 +0200 Stephan Bosch <stephan@rename-it.nl> (1a10419a)
+
+ Previous change in extension interface for implicit side effect support
+ broke include extension.
+
+
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-match-types.c
+M src/testsuite/ext-testsuite.c
+
+2008-07-14 12:19:21 +0200 Stephan Bosch <stephan@rename-it.nl> (3b694edd)
+
+ Added support for implicit side effects and adjusted imapflags extension
+ accordingly.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/include/include.sieve
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+A src/lib-sieve/sieve-message.c
+A src/lib-sieve/sieve-message.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2008-07-13 08:29:32 +0200 Stephan Bosch <stephan@rename-it.nl> (2165100f)
+
+ Imapflags: flags are stored for explicit actions.
+
+
+M TODO
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+
+2008-07-12 23:43:49 +0200 Stephan Bosch <stephan@rename-it.nl> (2cef2750)
+
+ Imapflags: cleaned up some debug messages and fixed triggered assertion.
+
+
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+
+2008-07-12 23:36:31 +0200 Stephan Bosch <stephan@rename-it.nl> (ca866fee)
+
+ Forgot a few trace macros.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+
+2008-07-12 23:22:21 +0200 Stephan Bosch <stephan@rename-it.nl> (ba7d7f88)
+
+ Updated TODO list.
+
+
+M TODO
+
+2008-07-12 23:21:03 +0200 Stephan Bosch <stephan@rename-it.nl> (4a5820ad)
+
+ Fixed typos in some error messages.
+
+
+M src/lib-sieve/sieve-actions.c
+
+2008-07-12 21:32:37 +0200 Stephan Bosch <stephan@rename-it.nl> (edfef28a)
+
+ Improved address validation significantly.
+
+
+M sieve/errors/out-address-errors.sieve
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+R091 src/lib-sieve/sieve-validator-address.c src/lib-sieve/sieve-address.c
+A src/lib-sieve/sieve-address.h
+M src/lib-sieve/sieve-validator.h
+
+2008-07-12 18:23:44 +0200 Stephan Bosch <stephan@rename-it.nl> (dd65eb4d)
+
+ Added two simple test cases.
+
+
+A src/testsuite/tests/control-structures.svtest
+A src/testsuite/tests/match-types/contains.svtest
+
+2008-07-12 18:23:25 +0200 Stephan Bosch <stephan@rename-it.nl> (edc41252)
+
+ Forgot trace macro for the stop command.
+
+
+M src/lib-sieve/sieve-commands.c
+
+2008-07-12 18:19:04 +0200 Stephan Bosch <stephan@rename-it.nl> (fc8962d1)
+
+ Removed llist TODO item, turns out to be less mergeable than initially
+ thought.
+
+
+M TODO
+
+2008-06-29 20:57:42 +0200 Stephan Bosch <stephan@rename-it.nl> (141727dd)
+
+ Testsuite: extended :matches tests.
+
+
+M src/testsuite/tests/match-types/matches.svtest
+
+2008-06-29 17:58:11 +0200 Stephan Bosch <stephan@rename-it.nl> (e3033532)
+
+ Introduced trace macro for runtime tracing and improved testsuite
+ implementation.
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+M src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test-set.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/tests/match-types/matches.svtest
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite.c
+
+2008-06-29 14:49:34 +0200 Stephan Bosch <stephan@rename-it.nl> (3cbee323)
+
+ Testsuite: fixed CRLF bug in reading a script-specified mail message.
+
+
+M src/lib-sieve/mcht-matches.c
+M src/testsuite/mail-raw.c
+M src/testsuite/tests/match-types/matches.svtest
+
+2008-06-29 12:09:23 +0200 Stephan Bosch <stephan@rename-it.nl> (8fbebb06)
+
+ Fixed bugs in :matches implementation.
+
+
+M sieve/tests/matches.sieve
+M src/lib-sieve/mcht-matches.c
+M src/lib-sieve/tst-header.c
+M src/testsuite/tests/match-types/matches.svtest
+
+2008-06-28 23:37:44 +0200 Stephan Bosch <stephan@rename-it.nl> (2761af1e)
+
+ Added testcase to the testsuite.
+
+
+M src/lib-sieve/sieve-generator.c
+A src/testsuite/tests/match-types/matches.svtest
+R100 src/testsuite/tests/testsuite.sieve src/testsuite/tests/testsuite.svtest
+
+2008-06-28 20:13:53 +0200 Stephan Bosch <stephan@rename-it.nl> (2e03af4e)
+
+ Updated documentation.
+
+
+M README
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/variables/ext-variables.c
+
+2008-06-28 20:06:50 +0200 Stephan Bosch <stephan@rename-it.nl> (2ca344ea)
+
+ Updated TODO.
+
+
+M TODO
+
+2008-06-28 20:04:54 +0200 Stephan Bosch <stephan@rename-it.nl> (64fb240c)
+
+ Added support for limits on the maximum number of errors collected during
+ compilation.
+
+
+M TODO
+M src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-validator.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-bin/bin-common.c
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+M src/testsuite/testsuite.c
+
+2008-06-28 18:34:16 +0200 Stephan Bosch <stephan@rename-it.nl> (f9a27524)
+
+ Updated documentation.
+
+
+M README
+M TODO
+
+2008-06-28 18:30:21 +0200 Stephan Bosch <stephan@rename-it.nl> (5c408f0a)
+
+ Added compile-time address validation.
+
+
+A sieve/errors/out-address-errors.sieve
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+D src/lib-sieve/sieve-address.c
+M src/lib-sieve/sieve-commands.h
+A src/lib-sieve/sieve-validator-address.c
+M src/lib-sieve/sieve-validator.h
+
+2008-06-28 14:58:59 +0200 Stephan Bosch <stephan@rename-it.nl> (7df409aa)
+
+ Added IMAIL rfc.
+
+
+A doc/rfc/imail.rfc2822.txt
+
+2008-06-28 14:50:10 +0200 Stephan Bosch <stephan@rename-it.nl> (4dcc0210)
+
+ Updated doc/rfc directory.
+
+
+D doc/rfc/rfc3028.txt
+R065 doc/rfc/draft-ietf-sieve-3028bis-13.txt doc/rfc/sieve.rfc5228.txt
+R100 doc/rfc/rfc3629.txt doc/rfc/utf-8.rfc3629.txt
+
+2008-06-28 14:45:48 +0200 Stephan Bosch <stephan@rename-it.nl> (a35aa2c2)
+
+ Updated documentation.
+
+
+M README
+M TODO
+
+2008-06-28 14:42:22 +0200 Stephan Bosch <stephan@rename-it.nl> (e968cf85)
+
+ Imapflags: finished for implicit flag attachment to fileinto and keep
+ commands.
+
+
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-extensions-private.h
+
+2008-06-17 12:25:59 +0200 Stephan Bosch <stephan@rename-it.nl> (5cd6a700)
+
+ Added the concept of persistent tags and implemented imapflags extension for
+ bare keep and fileinto commands (intermittent commit, not working properly
+ yet).
+
+
+M TODO
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/vacation/cmd-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/tst-size.c
+M src/testsuite/testsuite-objects.c
+
+2008-06-04 02:04:08 +0200 Stephan Bosch <stephan@rename-it.nl> (c1dfc976)
+
+ Imapflags: added execution support for variables.
+
+
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/imapflags-variables.sieve
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2008-06-04 01:32:28 +0200 Stephan Bosch <stephan@rename-it.nl> (dc90fc9c)
+
+ Imapflags: added validation and code support for variables.
+
+
+M src/lib-sieve/plugins/imapflags/Makefile.am
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+A src/lib-sieve/plugins/imapflags/imapflags-variables.sieve
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+
+2008-06-03 19:03:55 +0200 Stephan Bosch <stephan@rename-it.nl> (51da5845)
+
+ Fixed bug in duplicate argument detection.
+
+
+M TODO
+M src/lib-sieve/plugins/vacation/vacation.sieve
+M src/lib-sieve/sieve-validator.c
+
+2008-06-03 18:10:01 +0200 Stephan Bosch <stephan@rename-it.nl> (346397cd)
+
+ Vacation: exported command implementation to separate file.
+
+
+M src/lib-sieve/plugins/vacation/Makefile.am
+A src/lib-sieve/plugins/vacation/cmd-vacation.c
+A src/lib-sieve/plugins/vacation/ext-vacation-common.h
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+
+2008-06-03 17:43:26 +0200 Stephan Bosch <stephan@rename-it.nl> (f1ba624e)
+
+ Fixed bug in sieved.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/sieve-bin/sieved.c
+
+2008-06-03 17:25:49 +0200 Stephan Bosch <stephan@rename-it.nl> (9a6010b5)
+
+ Minor compile and documentation changes.
+
+
+M INSTALL
+M README
+M configure.in
+M src/sieve-bin/Makefile.am
+
+2008-06-03 13:02:00 +0200 Stephan Bosch <stephan@rename-it.nl> (f9539ec2)
+
+ Made lda sieve plugin save and load binaries.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2008-06-03 12:10:56 +0200 Stephan Bosch <stephan@rename-it.nl> (b66c7cfd)
+
+ Resolved all outstanding warnings.
+
+
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/sieve-bin/sievec.c
+M src/testsuite/cmd-test.c
+M src/testsuite/testsuite-common.c
+
+2008-06-03 11:32:18 +0200 Stephan Bosch <stephan@rename-it.nl> (3f22c88d)
+
+ Updated documentation and fixed 'make dist'.
+
+
+A DESIGN
+M INSTALL
+M Makefile.am
+M README
+A TODO
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/body/Makefile.am
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile.am
+M src/lib-sieve/plugins/copy/Makefile.am
+M src/lib-sieve/plugins/imapflags/Makefile.am
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/include/Makefile.am
+M src/lib-sieve/plugins/regex/Makefile.am
+M src/lib-sieve/plugins/relational/Makefile.am
+M src/lib-sieve/plugins/subaddress/Makefile.am
+M src/lib-sieve/plugins/vacation/Makefile.am
+M src/lib-sieve/plugins/variables/Makefile.am
+
+2008-05-29 10:10:49 +0200 Stephan Bosch <stephan@rename-it.nl> (7e5c0211)
+
+ Testsuite: added test_fail command.
+
+
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/testsuite/Makefile.am
+A src/testsuite/cmd-test-fail.c
+M src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/tests/testsuite.sieve
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+
+2008-05-29 01:57:55 +0200 Stephan Bosch <stephan@rename-it.nl> (67dc990f)
+
+ Testsuite: added 'test' command to group sieve statements into a test.
+
+
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/testsuite/Makefile.am
+M src/testsuite/cmd-test-set.c
+A src/testsuite/cmd-test.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/tests/testsuite.sieve
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-objects.c
+
+2008-05-27 17:47:24 +0200 Stephan Bosch <stephan@rename-it.nl> (5e293402)
+
+ Testsuite: added support for test object members.
+
+
+M src/testsuite/cmd-test-set.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/tests/testsuite.sieve
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite-objects.c
+M src/testsuite/testsuite-objects.h
+
+2008-05-25 12:48:24 +0200 Stephan Bosch <stephan@rename-it.nl> (d8bd4292)
+
+ Testsuite: exported testsuit object interface to separate files.
+
+
+M src/testsuite/Makefile.am
+M src/testsuite/cmd-test-set.c
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+A src/testsuite/testsuite-objects.c
+A src/testsuite/testsuite-objects.h
+
+2008-05-25 12:25:47 +0200 Stephan Bosch <stephan@rename-it.nl> (52d25c52)
+
+ Testsuite: implemented testsuite object interface.
+
+
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-extensions-private.h
+M src/testsuite/Makefile.am
+R051 src/testsuite/cmd-test-message.c src/testsuite/cmd-test-set.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/tests/testsuite.sieve
+M src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+
+2008-05-21 16:24:13 +0200 Stephan Bosch <stephan@rename-it.nl> (356ba5cc)
+
+ vacation: added TODO regarding duplicate tagged arguments to the vacation
+ command.
+
+
+M README
+A src/lib-sieve/plugins/vacation/vacation-errors.sieve
+
+2008-05-21 16:23:12 +0200 Stephan Bosch <stephan@rename-it.nl> (2c5b0d7c)
+
+ testsuite: removed spurious binary from repository.
+
+
+M .hgignore
+D src/testsuite/testsuite
+
+2008-05-21 12:58:31 +0200 Stephan Bosch <stephan@rename-it.nl> (a74fc814)
+
+ Testsuite: setting message content works.
+
+
+M configure.in
+M src/testsuite/Makefile.am
+M src/testsuite/cmd-test-message.c
+M src/testsuite/mail-raw.c
+M src/testsuite/tests/testsuite.sieve
+M src/testsuite/testsuite
+A src/testsuite/testsuite-common.c
+M src/testsuite/testsuite-common.h
+M src/testsuite/testsuite.c
+
+2008-05-21 00:29:40 +0200 Stephan Bosch <stephan@rename-it.nl> (98274544)
+
+ Fixed execution of initial testsuite implementation.
+
+
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-extensions-private.h
+M src/lib-sieve/sieve-extensions.c
+M src/testsuite/cmd-test-message.c
+M src/testsuite/ext-testsuite.c
+M src/testsuite/testsuite
+M src/testsuite/testsuite.c
+
+2008-05-20 17:31:45 +0200 Stephan Bosch <stephan@rename-it.nl> (9e50d466)
+
+ Properly implemented dumping a binary including a list of required
+ extensions and support for extension-specific output.
+
+
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/include/ext-include-binary.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-binary-dumper.c
+M src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-match-types.c
+M src/testsuite/testsuite
+
+2008-05-18 18:03:19 +0200 Stephan Bosch <stephan@rename-it.nl> (40747643)
+
+ RECOVERED FROM INCONSISTENCY: developed testsuite and binary dumping and
+ fixed various small issues.
+
+
+M .hgignore
+M src/Makefile.am
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/imapflags.sieve
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-arguments.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-address-parts.c
+A src/lib-sieve/sieve-binary-dumper.c
+A src/lib-sieve/sieve-binary-dumper.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+A src/lib-sieve/sieve-dump.h
+M src/lib-sieve/sieve-extensions-private.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/tst-header.c
+A src/testsuite/Makefile.am
+A src/testsuite/cmd-test-message.c
+A src/testsuite/ext-testsuite.c
+A src/testsuite/mail-raw.c
+A src/testsuite/mail-raw.h
+A src/testsuite/namespaces.c
+A src/testsuite/namespaces.h
+A src/testsuite/tests/testsuite.sieve
+A src/testsuite/testsuite
+A src/testsuite/testsuite-common.h
+A src/testsuite/testsuite.c
+
+2008-04-06 22:02:08 +0200 Stephan Bosch <stephan@rename-it.nl> (5148f381)
+
+ Updated documentation.
+
+
+M README
+
+2008-04-06 21:57:32 +0200 Stephan Bosch <stephan@rename-it.nl> (dd105ea5)
+
+ Include: merged import and export commands into a single implementation and
+ implemented global variable storage.
+
+
+M src/lib-sieve/plugins/include/Makefile.am
+D src/lib-sieve/plugins/include/cmd-export.c
+M src/lib-sieve/plugins/include/cmd-import.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/include-variables.sieve
+M src/lib-sieve/plugins/include/include-variables1.sieve
+M src/lib-sieve/plugins/include/include-variables2.sieve
+A src/lib-sieve/plugins/include/include-variables3.sieve
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables-operands.c
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2008-04-06 15:16:37 +0200 Stephan Bosch <stephan@rename-it.nl> (d0d6216f)
+
+ Variables: exported new operand definitions to separate file.
+
+
+M README
+M src/lib-sieve/plugins/variables/Makefile.am
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+A src/lib-sieve/plugins/variables/ext-variables-operands.c
+A src/lib-sieve/plugins/variables/ext-variables-operands.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+
+2008-04-05 18:14:17 +0200 Stephan Bosch <stephan@rename-it.nl> (86364f53)
+
+ Variables: exported new argument definitions to separate file.
+
+
+M src/lib-sieve/plugins/variables/Makefile.am
+A src/lib-sieve/plugins/variables/ext-variables-arguments.c
+A src/lib-sieve/plugins/variables/ext-variables-arguments.h
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+
+2008-04-05 16:58:18 +0200 Stephan Bosch <stephan@rename-it.nl> (c4612dce)
+
+ Include: implemented global variable scope.
+
+
+M src/lib-sieve/plugins/include/cmd-export.c
+M src/lib-sieve/plugins/include/cmd-import.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-variables.c
+M src/lib-sieve/plugins/include/ext-include-variables.h
+
+2008-04-03 17:10:58 +0200 Stephan Bosch <stephan@rename-it.nl> (36e5af33)
+
+ Added -c option to sieve-test to force compile.
+
+
+M README
+M src/sieve-bin/sieve-test.c
+
+2008-03-24 23:29:00 +0100 Stephan Bosch <stephan@rename-it.nl> (fbbe6f49)
+
+ Updated documentation.
+
+
+M README
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/variables/ext-variables.c
+
+2008-03-24 23:12:00 +0100 Stephan Bosch <stephan@rename-it.nl> (d728ffb3)
+
+ Include: moved variables support to separate file.
+
+
+M src/lib-sieve/plugins/include/Makefile.am
+M src/lib-sieve/plugins/include/cmd-export.c
+M src/lib-sieve/plugins/include/cmd-import.c
+M src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+A src/lib-sieve/plugins/include/ext-include-variables.c
+A src/lib-sieve/plugins/include/ext-include-variables.h
+M src/lib-sieve/plugins/include/include-variables1.sieve
+M src/lib-sieve/plugins/include/include-variables2.sieve
+
+2008-03-24 22:07:07 +0100 Stephan Bosch <stephan@rename-it.nl> (4b8dc91a)
+
+ Include: moved implementation of binary extension to separate file.
+
+
+M src/lib-sieve/plugins/include/Makefile.am
+M src/lib-sieve/plugins/include/cmd-export.c
+A src/lib-sieve/plugins/include/ext-include-binary.c
+A src/lib-sieve/plugins/include/ext-include-binary.h
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+
+2008-03-24 20:39:05 +0100 Stephan Bosch <stephan@rename-it.nl> (5f9a9f99)
+
+ Include: added AST context and now export context detectects export of
+ imported variables.
+
+
+M src/lib-sieve/plugins/include/cmd-export.c
+M src/lib-sieve/plugins/include/cmd-import.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+A src/lib-sieve/plugins/include/include-variables-error2.sieve
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+
+2008-03-24 15:08:20 +0100 Stephan Bosch <stephan@rename-it.nl> (95a88e1f)
+
+ Include: moved script existance validation back to validation stage.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+A src/lib-sieve/plugins/include/include-error.sieve
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+
+2008-03-24 01:01:05 +0100 Stephan Bosch <stephan@rename-it.nl> (c6e94477)
+
+ Include: made import and export commands check whether the variables
+ extension is active.
+
+
+M src/lib-sieve/plugins/include/Makefile.am
+M src/lib-sieve/plugins/include/cmd-export.c
+M src/lib-sieve/plugins/include/cmd-import.c
+A src/lib-sieve/plugins/include/include-variables-error.sieve
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2008-03-23 23:56:50 +0100 Stephan Bosch <stephan@rename-it.nl> (a43e9271)
+
+ Include: added skeleton import and export commands.
+
+
+M src/lib-sieve/plugins/include/Makefile.am
+A src/lib-sieve/plugins/include/cmd-export.c
+A src/lib-sieve/plugins/include/cmd-import.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+A src/lib-sieve/plugins/include/include-variables.sieve
+A src/lib-sieve/plugins/include/include-variables1.sieve
+A src/lib-sieve/plugins/include/include-variables2.sieve
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-script.c
+
+2008-03-23 19:14:51 +0100 Stephan Bosch <stephan@rename-it.nl> (d91124d5)
+
+ Updated TODO.
+
+
+M README
+
+2008-03-23 18:42:18 +0100 Stephan Bosch <stephan@rename-it.nl> (2d4e8c07)
+
+ Regex: added match values support.
+
+
+M src/lib-sieve/plugins/regex/mcht-regex.c
+M src/lib-sieve/plugins/variables/Makefile.am
+A src/lib-sieve/plugins/variables/variables-regex.sieve
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+
+2008-03-23 16:03:02 +0100 Stephan Bosch <stephan@rename-it.nl> (a5b4c2c5)
+
+ Relational: split match-type implementation into separate file.
+
+
+M src/lib-sieve/plugins/relational/Makefile.am
+A src/lib-sieve/plugins/relational/ext-relational-common.c
+A src/lib-sieve/plugins/relational/ext-relational-common.h
+M src/lib-sieve/plugins/relational/ext-relational.c
+A src/lib-sieve/plugins/relational/mcht-count.c
+A src/lib-sieve/plugins/relational/mcht-value.c
+
+2008-03-23 15:03:54 +0100 Stephan Bosch <stephan@rename-it.nl> (4192b800)
+
+ Regex: split match type implementation into separate file.
+
+
+M src/lib-sieve/plugins/regex/Makefile.am
+A src/lib-sieve/plugins/regex/ext-regex-common.h
+M src/lib-sieve/plugins/regex/ext-regex.c
+A src/lib-sieve/plugins/regex/mcht-regex.c
+
+2008-03-23 11:20:50 +0100 Stephan Bosch <stephan@rename-it.nl> (eaae9678)
+
+ Exported match type implementations to separate files.
+
+
+M src/lib-sieve/Makefile.am
+A src/lib-sieve/mcht-contains.c
+A src/lib-sieve/mcht-is.c
+A src/lib-sieve/mcht-matches.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+
+2008-03-22 18:35:48 +0100 Stephan Bosch <stephan@rename-it.nl> (a493b63b)
+
+ Finished :matches function for now, but it can still be improved and it
+ needs more testing.
+
+
+M src/lib-sieve/plugins/variables/variables-match.sieve
+M src/lib-sieve/sieve-match-types.c
+
+2008-03-09 20:36:42 +0100 Stephan Bosch <stephan@rename-it.nl> (8a09df74)
+
+ Revised :matches function, but did finish.
+
+
+M src/lib-sieve/plugins/variables/variables-match.sieve
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+
+2008-03-08 01:05:38 +0100 Stephan Bosch <stephan@rename-it.nl> (188a18a5)
+
+ Variables: fixed bug in match value indexing.
+
+
+M src/lib-sieve/plugins/variables/variables-match.sieve
+M src/lib-sieve/sieve-match-types.c
+
+2008-03-08 00:28:34 +0100 Stephan Bosch <stephan@rename-it.nl> (1935269d)
+
+ Variables: First work towards match value support.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/tst-string.c
+A src/lib-sieve/plugins/variables/variables-match.sieve
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+
+2008-02-28 23:43:36 +0100 Stephan Bosch <stephan@rename-it.nl> (6c74642f)
+
+ Updated documentation.
+
+
+M README
+M src/lib-sieve/plugins/variables/ext-variables.c
+
+2008-02-28 23:21:03 +0100 Stephan Bosch <stephan@rename-it.nl> (65fe3d7c)
+
+ Variables: added variable name parsing to the set command and added error
+ handling.
+
+
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/variables-errors.sieve
+
+2008-02-28 22:10:44 +0100 Stephan Bosch <stephan@rename-it.nl> (83b1f62e)
+
+ Variables: exported namespace+variable parsing to separate file.
+
+
+M src/lib-sieve/plugins/variables/Makefile.am
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+A src/lib-sieve/plugins/variables/ext-variables-name.c
+A src/lib-sieve/plugins/variables/ext-variables-name.h
+A src/lib-sieve/plugins/variables/variables-nspace.sieve
+
+2008-02-28 21:30:33 +0100 Stephan Bosch <stephan@rename-it.nl> (4c929247)
+
+ Variables: exported namespace+variable parsing to separate function.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+
+2008-02-28 11:04:29 +0100 Stephan Bosch <stephan@rename-it.nl> (8bd12076)
+
+ Updated documentation.
+
+
+M README
+
+2008-02-27 23:55:24 +0100 Stephan Bosch <stephan@rename-it.nl> (2ffba54f)
+
+ Variables: added parsing support for namespaces.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+
+2008-02-27 20:38:43 +0100 Stephan Bosch <stephan@rename-it.nl> (5d741fcd)
+
+ Variables: fixed string test.
+
+
+M src/lib-sieve/plugins/variables/tst-string.c
+
+2008-02-26 09:55:39 +0100 Stephan Bosch <stephan@rename-it.nl> (4101df7d)
+
+ Expand ~ to home in sieve path.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2008-02-25 17:56:56 +0100 Stephan Bosch <stephan@rename-it.nl> (68da5027)
+
+ Fixed indent in sieve-banary.c
+
+
+M src/lib-sieve/sieve-binary.c
+
+2008-02-25 17:33:12 +0100 Stephan Bosch <stephan@rename-it.nl> (53258ecd)
+
+ Simplified needlessly complex assignment.
+
+
+M src/lib-sieve/sieve-script.c
+
+2008-02-25 17:30:53 +0100 Stephan Bosch <stephan@rename-it.nl> (9b8e94bb)
+
+ Added TODO item.
+
+
+M README
+
+2008-02-25 17:27:39 +0100 Stephan Bosch <stephan@rename-it.nl> (d3bfafef)
+
+ Avoid direct to_lower() invocations; replaced by i_tolower().
+
+
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/sieve-comparators.c
+
+2008-02-25 17:19:40 +0100 Stephan Bosch <stephan@rename-it.nl> (5b654ed2)
+
+ Updated documentation.
+
+
+M README
+
+2008-02-25 17:17:46 +0100 Stephan Bosch <stephan@rename-it.nl> (5687d842)
+
+ Changed various p_new(pool_datastack_create(),) invocations to t_new()
+
+
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-match-types.c
+
+2008-02-25 17:04:48 +0100 Stephan Bosch <stephan@rename-it.nl> (c43f035f)
+
+ Envelope: changed p_array_init(,pool_datastack_create(),) into
+ t_array_init(,)
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/plugins/variables/variables.sieve
+
+2008-02-25 16:57:07 +0100 Stephan Bosch <stephan@rename-it.nl> (be81f60a)
+
+ Updated documentation.
+
+
+M README
+
+2008-02-23 23:59:25 +0100 Stephan Bosch <stephan@rename-it.nl> (df66a8ed)
+
+ Variables: fixed bug in string-list containing variables.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/variables.sieve
+M src/lib-sieve/sieve-code.c
+
+2008-02-23 22:17:54 +0100 Stephan Bosch <stephan@rename-it.nl> (7d36798b)
+
+ Fixed bugs in string substitution support and the regex extension.
+
+
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/plugins/variables/variables.sieve
+M src/lib-sieve/sieve-commands.c
+
+2008-02-23 18:47:10 +0100 Stephan Bosch <stephan@rename-it.nl> (6ea9cce1)
+
+ Variables: updated included specification to new RFC 5229.
+
+
+D src/lib-sieve/plugins/variables/draft-ietf-sieve-variables-08.txt
+M src/lib-sieve/plugins/variables/ext-variables.c
+A src/lib-sieve/plugins/variables/rfc5229.txt
+
+2008-02-23 00:49:36 +0100 Stephan Bosch <stephan@rename-it.nl> (a1dc327b)
+
+ Updated documentation.
+
+
+M README
+
+2008-02-23 00:24:08 +0100 Stephan Bosch <stephan@rename-it.nl> (f5e9b9ce)
+
+ Variables: made variable identifiers case insensitive.
+
+
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/variables.sieve
+
+2008-02-22 23:29:06 +0100 Stephan Bosch <stephan@rename-it.nl> (03e43440)
+
+ Variables: added check for equal precedence and added comment.
+
+
+M src/lib-sieve/plugins/variables/cmd-set.c
+A src/lib-sieve/plugins/variables/variables-errors.sieve
+
+2008-02-22 22:29:08 +0100 Stephan Bosch <stephan@rename-it.nl> (f4156454)
+
+ Variables: activated 'quotewildcard' set modifier and fixed a bug.
+
+
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/variables.sieve
+
+2008-02-22 21:22:43 +0100 Stephan Bosch <stephan@rename-it.nl> (b7f46207)
+
+ Variables: activated 'length' set modifier.
+
+
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/variables.sieve
+
+2008-02-22 20:49:14 +0100 Stephan Bosch <stephan@rename-it.nl> (7fcf3e32)
+
+ Variables: activated support for set command modifiers.
+
+
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/variables.sieve
+
+2008-02-22 17:19:39 +0100 Stephan Bosch <stephan@rename-it.nl> (4aefe421)
+
+ Adjusted body extension to compile with dovecot past 1.1.beta16 (message
+ parser changes)
+
+
+M src/lib-sieve/plugins/body/ext-body-common.c
+
+2008-02-14 12:20:36 +0100 Stephan Bosch <stephan@rename-it.nl> (a12b44f5)
+
+ Added notice about the omission CMU code to the AUTHORS file.
+
+
+M AUTHORS
+
+2008-02-14 12:16:29 +0100 Stephan Bosch <stephan@rename-it.nl> (c8a4690e)
+
+ Assigned proper package version and name.
+
+
+M .hgignore
+M configure.in
+
+2008-02-14 11:39:59 +0100 Stephan Bosch <stephan@rename-it.nl> (8fd8b8ae)
+
+ Removed duplicate licence.
+
+
+M .hgignore
+A COPYING
+
+2008-02-14 11:39:22 +0100 Stephan Bosch <stephan@rename-it.nl> (b6123c0e)
+
+ Added maintainermode functions to Makefile.am
+
+
+M Makefile.am
+
+2008-02-13 13:24:35 +0100 Stephan Bosch <stephan@rename-it.nl> (81324947)
+
+ Incorporated changes in dovecot-1.1
+
+
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve.c
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2008-02-11 09:59:02 +0100 Stephan Bosch <stephan@rename-it.nl> (c3678c45)
+
+ Variables: set modifiers are now sorted.
+
+
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/variables.sieve
+
+2008-02-10 16:41:20 +0100 Stephan Bosch <stephan@rename-it.nl> (792852f3)
+
+ Added code support for set modifiers.
+
+
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2008-01-06 01:26:12 +0100 Stephan Bosch <stephan@rename-it.nl> (6a490856)
+
+ Fixed bugs in validation error handling and fixed bugs in dynamic argument
+ support.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/plugins/variables/variables.sieve
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+
+2008-01-05 23:11:59 +0100 Stephan Bosch <stephan@rename-it.nl> (53ea2603)
+
+ First successful variable substitutions.
+
+
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/variables.sieve
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-validator.c
+
+2008-01-05 02:25:41 +0100 Stephan Bosch <stephan@rename-it.nl> (5e2e9f9b)
+
+ Merged concurrent changes.
+
+
+2008-01-05 02:24:29 +0100 Stephan Bosch <stephan@rename-it.nl> (3337b5df)
+
+ Changed operand read API to get access to the runtime environment inside the
+ read functions.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/sieve-ext-variables.h
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+
+2008-01-04 17:50:23 +0100 Stephan Bosch <stephan@rename-it.nl> (ca44fcdc)
+
+ Minor fix in the error reporting of the sieve parser.
+
+
+M sieve/errors/interesting.sieve
+M src/lib-sieve/sieve-parser.c
+
+2008-01-04 01:53:00 +0100 Stephan Bosch <stephan@rename-it.nl> (6a1ff206)
+
+ Implemented dynamic sieve_get_capabilities() for proper MANAGESIEVE support.
+
+
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve.c
+
+2008-01-04 01:11:56 +0100 Stephan Bosch <stephan@rename-it.nl> (020fe587)
+
+ Published compiler API using script objects instead of paths.
+
+
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+
+2008-01-04 00:45:32 +0100 Stephan Bosch <stephan@rename-it.nl> (c752483a)
+
+ Fixed segfault occuring when command did not exist.
+
+
+M src/lib-sieve/sieve-validator.c
+
+2008-01-04 00:10:37 +0100 Stephan Bosch <stephan@rename-it.nl> (03c3f569)
+
+ Small changes: removed T_FRAME and improved an error message.
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-script.c
+
+2008-01-03 20:28:10 +0100 Stephan Bosch <stephan@rename-it.nl> (5d7f1005)
+
+ Implemented required features for use with MANAGESIEVE service.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/sieve-binary.c
+A src/lib-sieve/sieve-error-private.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-result.c
+A src/lib-sieve/sieve-script-private.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-bin/bin-common.c
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+
+2008-01-03 01:49:54 +0100 Stephan Bosch <stephan@rename-it.nl> (8b47f293)
+
+ Added strbuf error handler.
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+
+2007-12-30 03:35:40 +0100 Stephan Bosch <stephan@rename-it.nl> (3cc0395d)
+
+ Added variable operand to the variables extension.
+
+
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-match-types.c
+
+2007-12-30 02:23:24 +0100 Stephan Bosch <stephan@rename-it.nl> (aa8f3937)
+
+ Added support for adding new types operands to the engine.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-match-types.c
+
+2007-12-30 01:49:45 +0100 Stephan Bosch <stephan@rename-it.nl> (91438bbe)
+
+ Defined variable argument for the variables extension.
+
+
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+A src/lib-sieve/plugins/variables/sieve-ext-variables.h
+
+2007-12-29 16:20:54 +0100 Stephan Bosch <stephan@rename-it.nl> (97987192)
+
+ Changed validation and generation of string list argument to fully support
+ the new string list encoding.
+
+
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+
+2007-12-29 15:25:30 +0100 Stephan Bosch <stephan@rename-it.nl> (c14634ab)
+
+ Changed encoding of stringlist. Now it contains string operands in stead of
+ bare strings.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-code.c
+
+2007-12-29 05:54:31 +0100 Stephan Bosch <stephan@rename-it.nl> (aed4bf79)
+
+ Removed obsolete code.
+
+
+M src/lib-sieve/sieve-extensions-private.h
+
+2007-12-29 05:42:08 +0100 Stephan Bosch <stephan@rename-it.nl> (b4d68be1)
+
+ Removed much code duplication between extensions that provide support for
+ further extension.
+
+
+M sieve/tests/address-part.sieve
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-extensions-private.h
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-validator.c
+
+2007-12-27 14:42:41 +0100 Stephan Bosch <stephan@rename-it.nl> (817b48ce)
+
+ Further migrated implementation of extensions to new extension architecture.
+
+
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-extensions-private.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+
+2007-12-27 01:24:42 +0100 Stephan Bosch <stephan@rename-it.nl> (9846f24f)
+
+ Major changes in the extensions support.
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/copy/copy.sieve
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/plugins/variables/cmd-set.c
+M src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+M src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+A src/lib-sieve/sieve-extensions-private.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+
+2007-12-26 15:40:50 +0100 Stephan Bosch <stephan@rename-it.nl> (1b1d60f8)
+
+ Changed implementation of command context handling and instanced tags to
+ avoid duplicate lookups.
+
+
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+
+2007-12-26 14:00:12 +0100 Stephan Bosch <stephan@rename-it.nl> (6ca7825d)
+
+ Further developed the variables extension.
+
+
+M src/lib-sieve/plugins/variables/Makefile.am
+A src/lib-sieve/plugins/variables/cmd-set.c
+A src/lib-sieve/plugins/variables/ext-variables-common.c
+A src/lib-sieve/plugins/variables/ext-variables-common.h
+M src/lib-sieve/plugins/variables/ext-variables.c
+A src/lib-sieve/plugins/variables/tst-string.c
+M src/lib-sieve/plugins/variables/variables.sieve
+
+2007-12-25 16:16:15 +0100 Stephan Bosch <stephan@rename-it.nl> (549382e0)
+
+ Started skeleton implementation of variables extension.
+
+
+M README
+M configure.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/variables/Makefile.am
+A src/lib-sieve/plugins/variables/draft-ietf-sieve-variables-08.txt
+A src/lib-sieve/plugins/variables/ext-variables.c
+A src/lib-sieve/plugins/variables/variables.sieve
+M src/lib-sieve/sieve-extensions.c
+
+2007-12-25 12:40:06 +0100 Stephan Bosch <stephan@rename-it.nl> (82e4024e)
+
+ Fixed non-standard behavior for the encoded-character extension.
+
+
+M sieve/tests/encoded-character.sieve
+M src/lib-sieve/ext-encoded-character.c
+
+2007-12-25 12:06:41 +0100 Stephan Bosch <stephan@rename-it.nl> (d2cbd795)
+
+ Finished encoded-character extension.
+
+
+M README
+A sieve/errors/encoded-character.sieve
+M sieve/tests/encoded-character.sieve
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/sieve-bin/mail-raw.c
+
+2007-12-25 11:07:31 +0100 Stephan Bosch <stephan@rename-it.nl> (151cb427)
+
+ Added UTF-8 rfc to doc/rfc directory.
+
+
+A doc/rfc/rfc3629.txt
+
+2007-12-25 11:07:01 +0100 Stephan Bosch <stephan@rename-it.nl> (54f7acfd)
+
+ Built a little more extensive tests for the encoded-character extension.
+
+
+M sieve/tests/encoded-character.sieve
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/sieve-validator.c
+
+2007-12-24 16:11:33 +0100 Stephan Bosch <stephan@rename-it.nl> (56aa3902)
+
+ Encoded character extension basicly works, but no unicode support is
+ implemented.
+
+
+M sieve/tests/encoded-character.sieve
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+
+2007-12-19 14:51:36 +0100 Stephan Bosch <stephan@rename-it.nl> (688742fa)
+
+ Implemented support for overriding default argument implementations of
+ number, string and string-list.
+
+
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/ext-encoded-character.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+
+2007-12-18 23:46:46 +0100 Stephan Bosch <stephan@rename-it.nl> (b8dc1073)
+
+ Added sieve rfc and new sieve 3028bis to the doc/rfc directory.
+
+
+A doc/rfc/draft-ietf-sieve-3028bis-13.txt
+A doc/rfc/rfc3028.txt
+
+2007-12-18 23:46:00 +0100 Stephan Bosch <stephan@rename-it.nl> (0281b79a)
+
+ Removed erroneous rfc file from new doc dir.
+
+
+D doc/rfc
+
+2007-12-18 23:41:39 +0100 Stephan Bosch <stephan@rename-it.nl> (1a1dc484)
+
+ Forgot to add new files.
+
+
+A doc/rfc
+A sieve/tests/encoded-character.sieve
+A src/lib-sieve/ext-encoded-character.c
+
+2007-12-18 23:38:32 +0100 Stephan Bosch <stephan@rename-it.nl> (7823beb1)
+
+ Updated documentation.
+
+
+M README
+
+2007-12-18 23:34:08 +0100 Stephan Bosch <stephan@rename-it.nl> (b868111d)
+
+ Started skeleton for the encoded-character extension.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/sieve-extensions.c
+
+2007-12-18 23:14:13 +0100 Stephan Bosch <stephan@rename-it.nl> (ab8d5d31)
+
+ Updated TODO list.
+
+
+M README
+
+2007-12-18 23:11:18 +0100 Stephan Bosch <stephan@rename-it.nl> (2274e9fe)
+
+ Updated documentation.
+
+
+M README
+M src/lib-sieve/plugins/body/ext-body.c
+
+2007-12-18 23:00:47 +0100 Stephan Bosch <stephan@rename-it.nl> (93a757ca)
+
+ Changed imapflags extension to use the message context instead of the
+ interpreter context.
+
+
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+
+2007-12-18 22:43:21 +0100 Stephan Bosch <stephan@rename-it.nl> (0cbc4a05)
+
+ Changed body extension to use the message context instead of the interpreter
+ context.
+
+
+M src/lib-sieve/plugins/body/ext-body-common.c
+
+2007-12-18 22:40:03 +0100 Stephan Bosch <stephan@rename-it.nl> (ef12c613)
+
+ Introduced message context to give extensions the ability to associate
+ context data with the currently processed message.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+
+2007-12-18 21:39:31 +0100 Stephan Bosch <stephan@rename-it.nl> (3b8a1988)
+
+ Updated documentation.
+
+
+M README
+M src/lib-sieve/plugins/body/ext-body.c
+
+2007-12-18 21:19:06 +0100 Stephan Bosch <stephan@rename-it.nl> (01f58520)
+
+ Fixed minor bug in the body extension.
+
+
+M src/lib-sieve/plugins/body/body.sieve
+M src/lib-sieve/plugins/body/ext-body-common.c
+M src/lib-sieve/plugins/body/tst-body.c
+
+2007-12-18 21:08:06 +0100 Stephan Bosch <stephan@rename-it.nl> (ddfd461e)
+
+ Implemented evaluation for the body test introduced by the body extension.
+
+
+M AUTHORS
+M src/lib-sieve/plugins/body/Makefile.am
+A src/lib-sieve/plugins/body/body.sieve
+A src/lib-sieve/plugins/body/ext-body-common.c
+A src/lib-sieve/plugins/body/ext-body-common.h
+M src/lib-sieve/plugins/body/ext-body.c
+A src/lib-sieve/plugins/body/tst-body.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/tst-header.c
+
+2007-12-18 16:41:42 +0100 Stephan Bosch <stephan@rename-it.nl> (0b27d776)
+
+ Implemented validation and code generation for body extension.
+
+
+M src/lib-sieve/plugins/body/ext-body.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+
+2007-12-18 15:11:24 +0100 Stephan Bosch <stephan@rename-it.nl> (345703f3)
+
+ Started skeleton for the body extension.
+
+
+M README
+M configure.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/body/Makefile.am
+A src/lib-sieve/plugins/body/draft-ietf-sieve-body-07.txt
+A src/lib-sieve/plugins/body/ext-body.c
+
+2007-12-18 01:08:02 +0100 Stephan Bosch <stephan@rename-it.nl> (cad1f74f)
+
+ Updated documentation.
+
+
+M README
+M src/lib-sieve/plugins/include/ext-include.c
+
+2007-12-18 00:38:58 +0100 Stephan Bosch <stephan@rename-it.nl> (1abd9f94)
+
+ Implemented return command for include extension.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/cmd-return.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/included2.sieve
+M src/lib-sieve/sieve-binary.c
+
+2007-12-18 00:11:02 +0100 Stephan Bosch <stephan@rename-it.nl> (c661d5db)
+
+ Basic include functionality seems to be working and if source scripts are
+ changed the binary is always recompiled.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-error.c
+
+2007-12-16 18:35:04 +0100 Stephan Bosch <stephan@rename-it.nl> (c3ffb25d)
+
+ Working towards proper dependency handling for sieve binaries.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve.c
+
+2007-12-16 00:49:46 +0100 Stephan Bosch <stephan@rename-it.nl> (56cb692d)
+
+ Added support for lazy binary load.
+
+
+M src/lib-sieve/sieve-binary.c
+
+2007-12-15 23:16:16 +0100 Stephan Bosch <stephan@rename-it.nl> (9f9ec317)
+
+ Added internal support for different methods of loading a binary.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/sieve-binary.c
+
+2007-12-15 21:30:00 +0100 Stephan Bosch <stephan@rename-it.nl> (abe54c85)
+
+ Working towards complete binary support for the include extension.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve.c
+M src/sieve-bin/sieved.c
+
+2007-12-14 18:34:02 +0100 Stephan Bosch <stephan@rename-it.nl> (898aa186)
+
+ Updated documentation.
+
+
+M README
+
+2007-12-14 02:20:41 +0100 Stephan Bosch <stephan@rename-it.nl> (d0171770)
+
+ Fixed bug regarding stop command in combination with include extension.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/included2.sieve
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-interpreter.c
+
+2007-12-14 01:57:58 +0100 Stephan Bosch <stephan@rename-it.nl> (28ed01a2)
+
+ Simplified the include loop a little.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+
+2007-12-14 01:41:14 +0100 Stephan Bosch <stephan@rename-it.nl> (95ea119b)
+
+ Implemented mostly untested deep-level include execution support.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/include.sieve
+M src/lib-sieve/plugins/include/included2.sieve
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+
+2007-12-13 22:59:24 +0100 Stephan Bosch <stephan@rename-it.nl> (c061f389)
+
+ First successful (single level) execution of four consecutive includes.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve.c
+
+2007-12-13 17:45:38 +0100 Stephan Bosch <stephan@rename-it.nl> (67a5e20b)
+
+ Added support for interrupting an interpreter and continuing execution
+ later.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+
+2007-12-13 13:23:41 +0100 Stephan Bosch <stephan@rename-it.nl> (5aa15bb3)
+
+ Include extension now generates include opcode. Not executable yet though.
+
+
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+
+2007-12-13 11:58:17 +0100 Stephan Bosch <stephan@rename-it.nl> (db2a3ef0)
+
+ Implemented the binary_free event for binary extensions. Script references
+ in the include extension are now properly released.
+
+
+M src/lib-sieve/sieve-binary.c
+
+2007-12-13 11:42:50 +0100 Stephan Bosch <stephan@rename-it.nl> (9848bb77)
+
+ Fixed behavior of binary object with respect to pre-loaded extensons. Broke
+ it with last change.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-common.h
+
+2007-12-13 01:20:59 +0100 Stephan Bosch <stephan@rename-it.nl> (fa295e4b)
+
+ Changed binary object's extension linkage for extending the binary itself.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+
+2007-12-11 12:44:57 +0100 Stephan Bosch <stephan@rename-it.nl> (ad733634)
+
+ Doubly included scripts are no longer compiled and included multiple times.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+
+2007-12-11 11:23:53 +0100 Stephan Bosch <stephan@rename-it.nl> (1d9b48ba)
+
+ Forgot to set the number of blocks in the binary header.
+
+
+M src/lib-sieve/plugins/include/included1.sieve
+M src/lib-sieve/sieve-binary.c
+
+2007-12-11 10:55:05 +0100 Stephan Bosch <stephan@rename-it.nl> (e1f26173)
+
+ Re-established circular include detection for include extension.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/included1.sieve
+
+2007-12-11 11:38:42 +0100 Stephan Bosch <stephan@rename-it.nl> (f49a0473)
+
+ Further developed the include extension to compile included scripts in
+ additional blocks of the binary.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/included1.sieve
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve.c
+
+2007-12-10 18:59:44 +0100 Stephan Bosch <stephan@rename-it.nl> (8d3d12c1)
+
+ Further developed the binary format: binary can now contain multiple blocks
+ with arbitrary data.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve.c
+
+2007-12-10 11:08:13 +0100 Stephan Bosch <stephan@rename-it.nl> (ee92eea1)
+
+ Updated documentation: Changed priorities in TODO list.
+
+
+M README
+
+2007-12-10 11:01:40 +0100 Stephan Bosch <stephan@rename-it.nl> (09775f2c)
+
+ Updated documentation.
+
+
+M README
+
+2007-12-09 23:22:33 +0100 Stephan Bosch <stephan@rename-it.nl> (4fccec75)
+
+ Moved actual include operation from validator to generator stage.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/include/included1.sieve
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/sieve-bin/sieved.c
+
+2007-12-09 19:59:47 +0100 Stephan Bosch <stephan@rename-it.nl> (beeed72c)
+
+ Sieve executables now work with binaries too.
+
+
+M .hgignore
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/sieve-bin/bin-common.c
+M src/sieve-bin/bin-common.h
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+M src/sieve-bin/sievec.c
+
+2007-12-09 17:42:36 +0100 Stephan Bosch <stephan@rename-it.nl> (c255daa0)
+
+ Made a basic implementation of saving binaries to disk.
+
+
+M .hgignore
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-script.c
+M src/sieve-bin/Makefile.am
+M src/sieve-bin/sievec.c
+A src/sieve-bin/sieved.c
+
+2007-12-08 15:23:21 +0100 Stephan Bosch <stephan@rename-it.nl> (e7bb1789)
+
+ Cleaned up ast implementation a little.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/include.sieve
+M src/lib-sieve/plugins/include/included2.sieve
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve.c
+
+2007-12-08 14:11:04 +0100 Stephan Bosch <stephan@rename-it.nl> (d24e1789)
+
+ Prevented more scripts from being included when errors have occured.
+
+
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/included2.sieve
+M src/lib-sieve/plugins/include/included3.sieve
+M src/lib-sieve/sieve.c
+
+2007-12-08 13:13:26 +0100 Stephan Bosch <stephan@rename-it.nl> (b01bd7c9)
+
+ Properly implemented circular include detection for the include extension.
+
+
+M src/lib-sieve/plugins/include/cmd-include.c
+M src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/included3.sieve
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-script.c
+M src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve.c
+
+2007-12-08 00:08:12 +0100 Stephan Bosch <stephan@rename-it.nl> (23ce5aba)
+
+ First defined an encapsulating script object and implemented part of the
+ include extension.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/include/Makefile.am
+M src/lib-sieve/plugins/include/cmd-include.c
+A src/lib-sieve/plugins/include/ext-include-common.c
+M src/lib-sieve/plugins/include/ext-include-common.h
+M src/lib-sieve/plugins/include/ext-include.c
+M src/lib-sieve/plugins/include/include.sieve
+A src/lib-sieve/plugins/include/included1.sieve
+A src/lib-sieve/plugins/include/included2.sieve
+A src/lib-sieve/plugins/include/included3.sieve
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+A src/lib-sieve/sieve-script.c
+A src/lib-sieve/sieve-script.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+
+2007-12-07 01:17:48 +0100 Stephan Bosch <stephan@rename-it.nl> (c69e9040)
+
+ Started skeleton implementation for the include extension.
+
+
+M README
+M configure.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/include/Makefile.am
+A src/lib-sieve/plugins/include/cmd-include.c
+A src/lib-sieve/plugins/include/cmd-return.c
+A src/lib-sieve/plugins/include/draft-daboo-sieve-include-05.txt
+A src/lib-sieve/plugins/include/ext-include-common.h
+A src/lib-sieve/plugins/include/ext-include.c
+A src/lib-sieve/plugins/include/include.sieve
+M src/lib-sieve/sieve-extensions.c
+
+2007-12-07 00:22:48 +0100 Stephan Bosch <stephan@rename-it.nl> (cdefa5f4)
+
+ Updated documentation.
+
+
+M README
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+
+2007-12-06 23:13:25 +0100 Stephan Bosch <stephan@rename-it.nl> (97edb9ca)
+
+ Added :addresses support to the vacation extension.
+
+
+M sieve/tests/vacation.sieve
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+
+2007-12-06 22:47:44 +0100 Stephan Bosch <stephan@rename-it.nl> (e2e92dd6)
+
+ Added support for reading an entire stringlist into memory. Also fixed
+ various identical bugs in stringlist-related error handling.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+
+2007-12-06 22:15:56 +0100 Stephan Bosch <stephan@rename-it.nl> (80274dca)
+
+ Added two TODO items.
+
+
+M README
+
+2007-12-06 21:59:21 +0100 Stephan Bosch <stephan@rename-it.nl> (940ea3d7)
+
+ Tiny update to documentation and removed a compiler warning.
+
+
+M README
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+
+2007-12-06 21:48:44 +0100 Stephan Bosch <stephan@rename-it.nl> (03952bf0)
+
+ Added :mime support to vacation extension.
+
+
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-generator.c
+
+2007-12-06 21:00:35 +0100 Stephan Bosch <stephan@rename-it.nl> (d24406e3)
+
+ Renamed mail_environment to script_env.
+
+
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+
+2007-12-06 17:45:44 +0100 Stephan Bosch <stephan@rename-it.nl> (bddf8c83)
+
+ Added mail-loop detection to the redirect action.
+
+
+M README
+M src/lib-sieve/cmd-redirect.c
+
+2007-12-06 17:22:16 +0100 Stephan Bosch <stephan@rename-it.nl> (bb78d0b1)
+
+ Changed execution error handling a little.
+
+
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-bin/sieve-exec.c
+
+2007-12-06 15:43:47 +0100 Stephan Bosch <stephan@rename-it.nl> (289716f9)
+
+ Adopted code to use Dovecot's new T_FRAME* macros.
+
+
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-validator.c
+
+2007-12-06 14:10:30 +0100 Stephan Bosch <stephan@rename-it.nl> (2e9603a5)
+
+ Added proper ATTR_FORMAT to all functions that accept a string format and
+ fixed one bug in the process.
+
+
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-validator.h
+
+2007-12-06 12:42:45 +0100 Stephan Bosch <stephan@rename-it.nl> (66004fba)
+
+ Further updated documentation and cleaned up the README file.
+
+
+M README
+
+2007-12-06 02:48:02 +0100 Stephan Bosch <stephan@rename-it.nl> (38a72a86)
+
+ Updated documentation. We are gettin closer to a first release.
+
+
+M INSTALL
+M README
+
+2007-12-06 02:26:57 +0100 Stephan Bosch <stephan@rename-it.nl> (df1bb287)
+
+ Implemented implicit keep to execute when not canceled or when the
+ preceeding action execution fails.
+
+
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-result.c
+M src/sieve-bin/bin-common.c
+M src/sieve-bin/sieve-exec.c
+
+2007-12-05 23:07:44 +0100 Stephan Bosch <stephan@rename-it.nl> (ebc0485a)
+
+ Fixed minor bugs in the error reporting.
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-interpreter.c
+
+2007-12-05 23:18:47 +0100 Stephan Bosch <stephan@rename-it.nl> (ff209a04)
+
+ Fixed tiny bug in the error reporting in the lda-sieve plugin.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2007-12-05 22:48:16 +0100 Stephan Bosch <stephan@rename-it.nl> (8817dda5)
+
+ Further developed the error handling.
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+
+2007-12-04 02:31:57 +0100 Stephan Bosch <stephan@rename-it.nl> (6f184ace)
+
+ Added a little more error logging to the lda-sieve plugin.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2007-12-04 02:07:48 +0100 Stephan Bosch <stephan@rename-it.nl> (7dabf5bc)
+
+ Implemented logfile error handler and assigned it to the lda-sieve plugin.
+
+
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2007-12-03 23:25:01 +0100 Stephan Bosch <stephan@rename-it.nl> (d688d73e)
+
+ Further developed error handling.
+
+
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-bin/bin-common.c
+M src/sieve-bin/sievec.c
+
+2007-12-02 23:37:52 +0100 Stephan Bosch <stephan@rename-it.nl> (3ccf3ebf)
+
+ Forgot to initialize sieve library in lda-sieve plugin. It has now
+ successfully delivered its first message.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+
+2007-12-02 23:59:30 +0100 Stephan Bosch <stephan@rename-it.nl> (88560cef)
+
+ Fixed misnamed module entry points for the lda-sieve plugin.
+
+
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.h
+
+2007-12-02 19:58:29 +0100 Stephan Bosch <stephan@rename-it.nl> (deb9f705)
+
+ Included sieve plugin into the build process.
+
+
+M configure.in
+M src/Makefile.am
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/Makefile.am
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/plugins/lda-sieve/lda-sieve-plugin.h
+M src/sieve-bin/bin-common.c
+
+2007-12-02 18:55:51 +0100 Stephan Bosch <stephan@rename-it.nl> (23953fce)
+
+ Documentation updates.
+
+
+M README
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/plugins/lda-sieve/lda-sieve-plugin.c
+M src/sieve-bin/sievec.c
+
+2007-12-02 17:57:50 +0100 Stephan Bosch <stephan@rename-it.nl> (41c19809)
+
+ Implemented sieve test binaries further. They now have proper command line
+ arguments.
+
+
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/sieve-bin/bin-common.c
+M src/sieve-bin/bin-common.h
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+M src/sieve-bin/sievec.c
+
+2007-12-02 15:34:38 +0100 Stephan Bosch <stephan@rename-it.nl> (5611ba3b)
+
+ Updated and cleaned-up the sieve test binaries.
+
+
+M src/sieve-bin/Makefile.am
+M src/sieve-bin/bin-common.c
+M src/sieve-bin/bin-common.h
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+M src/sieve-bin/sievec.c
+
+2007-12-02 14:44:01 +0100 Stephan Bosch <stephan@rename-it.nl> (95803e31)
+
+ Properly implemented the code dumper. Dumps are now printed in a stream. The
+ individual opcode and operand implementations no longer use printf()s.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-code-dumper.c
+M src/lib-sieve/sieve-code-dumper.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+M src/sieve-bin/sievec.c
+
+2007-12-02 12:04:41 +0100 Stephan Bosch <stephan@rename-it.nl> (ea987434)
+
+ Forgot to add new files.
+
+
+A src/lib-sieve/sieve-code-dumper.c
+A src/lib-sieve/sieve-code-dumper.h
+
+2007-12-02 00:19:16 +0100 Stephan Bosch <stephan@rename-it.nl> (8fa2f53c)
+
+ Exported sieve-code-dumper from sieve-interpreter containing all code
+ dumping related implementation. Now to remove all printfs....
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+
+2007-12-01 21:11:47 +0100 Stephan Bosch <stephan@rename-it.nl> (b2168ea1)
+
+ Fixed bug in handling optional operands to opcodes that have no mandatory
+ operands (0 is no longer a valid opcode)
+
+
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+
+2007-12-01 21:02:00 +0100 Stephan Bosch <stephan@rename-it.nl> (ba261b2d)
+
+ Added conflict and duplicate checking to vacation and reject actions.
+
+
+A sieve/errors/action-conflicts.sieve
+A sieve/errors/action-duplicates.sieve
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-commands-private.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2007-12-01 19:06:18 +0100 Stephan Bosch <stephan@rename-it.nl> (750ccb61)
+
+ Implemented actions reject and vacation.
+
+
+M sieve/tests/vacation.sieve
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve.h
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+
+2007-12-01 14:59:35 +0100 Stephan Bosch <stephan@rename-it.nl> (60399b42)
+
+ Fixed minor bug in envelope extension.
+
+
+M src/lib-sieve/ext-envelope.c
+
+2007-11-30 21:56:55 +0100 Stephan Bosch <stephan@rename-it.nl> (2b6bc923)
+
+ Further developed imapflags extension and added proper logging functions to
+ the result object.
+
+
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/imapflags.sieve
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve-validator.c
+
+2007-11-29 21:50:58 +0100 Stephan Bosch <stephan@rename-it.nl> (16f2ef46)
+
+ The :flags tag introduced by the imapflags extension now attaches
+ side-effects to the appropriate action commands.
+
+
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-interpreter.c
+
+2007-11-29 18:02:05 +0100 Stephan Bosch <stephan@rename-it.nl> (44fe503f)
+
+ Properly implemented handling of the implicit keep flag and fully
+ implemented the copy extension.
+
+
+M README
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+
+2007-11-29 14:20:10 +0100 Stephan Bosch <stephan@rename-it.nl> (a2f1ad80)
+
+ Added basic execution support to copy extension. Not completely functional
+ yet.
+
+
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2007-11-29 01:22:17 +0100 Stephan Bosch <stephan@rename-it.nl> (230cd1f3)
+
+ Added support for reading side effect operands.
+
+
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code.c
+
+2007-11-29 00:40:42 +0100 Stephan Bosch <stephan@rename-it.nl> (20b47a0d)
+
+ Added registration of side-effect extension into binary.
+
+
+M src/lib-sieve/plugins/copy/ext-copy.c
+
+2007-11-29 00:35:22 +0100 Stephan Bosch <stephan@rename-it.nl> (169a3649)
+
+ Defined side-effect object for the copy extension.
+
+
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+
+2007-11-29 00:14:14 +0100 Stephan Bosch <stephan@rename-it.nl> (08c97ffd)
+
+ Incorporated the signedness of the id_code in the optional_read functions as
+ well
+
+
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/tst-header.c
+
+2007-11-28 23:31:50 +0100 Stephan Bosch <stephan@rename-it.nl> (19f30a5f)
+
+ Changed id_code for optional operands to signed and fixed a
+ ext_my_id-related error in the vacation and copy extensions.
+
+
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/tst-size.c
+
+2007-11-28 22:35:05 +0100 Stephan Bosch <stephan@rename-it.nl> (90a67f1a)
+
+ Added operand emission support for action side effects.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-extensions.c
+
+2007-11-28 21:56:47 +0100 Stephan Bosch <stephan@rename-it.nl> (0a7f6dcd)
+
+ Created pre-loaded action side effects 'extension'.
+
+
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+
+2007-11-28 21:11:05 +0100 Stephan Bosch <stephan@rename-it.nl> (21b41f04)
+
+ Removed part of the code duplication between address-part, match-type and
+ comparator implementations.
+
+
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-match-types.c
+
+2007-11-28 20:28:21 +0100 Stephan Bosch <stephan@rename-it.nl> (317b1d33)
+
+ Added untested support for side effects to result object.
+
+
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2007-11-27 23:42:04 +0100 Stephan Bosch <stephan@rename-it.nl> (5d26995a)
+
+ Added :flags tag to the imapflags extension and fixed bug in the result
+ execution.
+
+
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/plugins/imapflags/Makefile.am
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/imapflags/imapflags.sieve
+A src/lib-sieve/plugins/imapflags/tag-flags.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-result.c
+
+2007-11-27 23:00:32 +0100 Stephan Bosch <stephan@rename-it.nl> (90bfc52b)
+
+ Updated documentation.
+
+
+M README
+
+2007-11-27 22:50:22 +0100 Stephan Bosch <stephan@rename-it.nl> (99c169ae)
+
+ Added support for externally adding tags to (possibly not yet registered)
+ command. The copy extension now adds such a tag to fileinto and redirect.
+
+
+A src/lib-sieve/plugins/copy/copy.sieve
+M src/lib-sieve/plugins/copy/ext-copy.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+
+2007-11-27 21:56:37 +0100 Stephan Bosch <stephan@rename-it.nl> (e7b84c64)
+
+ Added skeleton for the copy extension.
+
+
+M configure.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/copy/Makefile.am
+A src/lib-sieve/plugins/copy/ext-copy.c
+A src/lib-sieve/plugins/copy/rfc3894.txt
+M src/lib-sieve/sieve-extensions.c
+M src/sieve-bin/sieve-exec.c
+
+2007-11-27 21:09:46 +0100 Stephan Bosch <stephan@rename-it.nl> (5d73546c)
+
+ Minor changes
+
+
+M sieve/tests/actions.sieve
+M src/lib-sieve/sieve-actions.c
+
+2007-11-27 19:38:26 +0100 Stephan Bosch <stephan@rename-it.nl> (78eaa955)
+
+ Store action seems to work properly now.
+
+
+M sieve/tests/actions.sieve
+M src/lib-sieve/sieve-actions.c
+M src/sieve-bin/sieve-exec.c
+
+2007-11-27 03:38:49 +0100 Stephan Bosch <stephan@rename-it.nl> (b7f741e7)
+
+ Almost finished implementing the store action. But, I still get strange
+ errors when the mail transaction commits. Mail is stored though.
+
+
+M sieve/tests/actions.sieve
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve.h
+M src/sieve-bin/Makefile.am
+M src/sieve-bin/mail-raw.c
+M src/sieve-bin/mail-raw.h
+A src/sieve-bin/namespaces.c
+A src/sieve-bin/namespaces.h
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+
+2007-11-27 01:12:29 +0100 Stephan Bosch <stephan@rename-it.nl> (6cf3d1d3)
+
+ Turned action execution into a transaction.
+
+
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/sieve-actions.c
+M src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-result.c
+
+2007-11-27 00:25:12 +0100 Stephan Bosch <stephan@rename-it.nl> (385ce7aa)
+
+ Added (not yet active) handling of implicit keep and adjusted commands
+ accordingly.
+
+
+M README
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2007-11-27 00:07:12 +0100 Stephan Bosch <stephan@rename-it.nl> (26eefd04)
+
+ Added TODO item.
+
+
+M README
+
+2007-11-26 21:50:16 +0100 Stephan Bosch <stephan@rename-it.nl> (b4bbc93f)
+
+ Added inbox location to mail environment and made keep command use it to
+ generate its store action.
+
+
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+
+2007-11-26 21:29:17 +0100 Stephan Bosch <stephan@rename-it.nl> (fcaeb9e7)
+
+ Updated documentation.
+
+
+M README
+M src/lib-sieve/ext-fileinto.c
+
+2007-11-26 21:20:20 +0100 Stephan Bosch <stephan@rename-it.nl> (463ff297)
+
+ Fileinto command now produces a store action which is now produced by the
+ keep command as well.
+
+
+M sieve/tests/actions.sieve
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-fileinto.c
+A src/lib-sieve/sieve-actions.c
+A src/lib-sieve/sieve-actions.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2007-11-26 19:31:38 +0100 Stephan Bosch <stephan@rename-it.nl> (c445794f)
+
+ Made discard command add discard action to the result.
+
+
+A sieve/tests/actions.sieve
+M src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+
+2007-11-26 19:19:16 +0100 Stephan Bosch <stephan@rename-it.nl> (c5ae8068)
+
+ Exported discard command to its own separate file.
+
+
+M src/lib-sieve/Makefile.am
+A src/lib-sieve/cmd-discard.c
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/sieve-commands.c
+
+2007-11-26 19:04:10 +0100 Stephan Bosch <stephan@rename-it.nl> (0bde3903)
+
+ Added support for detecting action conflicts.
+
+
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2007-11-26 17:18:57 +0100 Stephan Bosch <stephan@rename-it.nl> (94e4cfe6)
+
+ Updated documentation.
+
+
+M README
+
+2007-11-26 17:09:54 +0100 Stephan Bosch <stephan@rename-it.nl> (88c1edae)
+
+ Added support for avoiding duplicate actions in the sieve result.
+
+
+M sieve/tests/redirect.sieve
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+
+2007-11-26 16:52:04 +0100 Stephan Bosch <stephan@rename-it.nl> (55632704)
+
+ Made keep command add keep action to the result.
+
+
+M src/lib-sieve/cmd-keep.c
+M src/lib-sieve/cmd-redirect.c
+
+2007-11-26 16:43:30 +0100 Stephan Bosch <stephan@rename-it.nl> (6dee82eb)
+
+ Exported keep command to its own separate file.
+
+
+M src/lib-sieve/Makefile.am
+A src/lib-sieve/cmd-keep.c
+M src/lib-sieve/sieve-commands-private.h
+M src/lib-sieve/sieve-commands.c
+
+2007-11-25 16:59:01 +0100 Stephan Bosch <stephan@rename-it.nl> (ec4184ed)
+
+ Minor changes to the executables.
+
+
+M src/sieve-bin/bin-common.c
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+
+2007-11-25 16:13:48 +0100 Stephan Bosch <stephan@rename-it.nl> (14a07351)
+
+ Added mail-file parameter to the sieve-test and sieve-exec binaries.
+
+
+M README
+M src/lib-sieve/sieve-interpreter.c
+M src/sieve-bin/sieve-exec.c
+M src/sieve-bin/sieve-test.c
+
+2007-11-25 11:54:54 +0100 Stephan Bosch <stephan@rename-it.nl> (77344245)
+
+ Cleaned up implementation of sieve test binaries and added sieve-exec
+
+
+M .hgignore
+M sieve/tests/redirect.sieve
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/sieve-bin/Makefile.am
+A src/sieve-bin/bin-common.c
+A src/sieve-bin/bin-common.h
+A src/sieve-bin/mail-raw.c
+A src/sieve-bin/mail-raw.h
+A src/sieve-bin/sieve-exec.c
+A src/sieve-bin/sieve-test.c
+D src/sieve-bin/sieve_test.c
+M src/sieve-bin/sievec.c
+
+2007-11-25 00:09:35 +0100 Stephan Bosch <stephan@rename-it.nl> (52f9a47e)
+
+ Removed spurious debug message.
+
+
+M src/lib-sieve/sieve-match-types.c
+
+2007-11-24 23:54:41 +0100 Stephan Bosch <stephan@rename-it.nl> (9ebef39b)
+
+ Added first action execution support. Redirect is the first command to
+ actually work.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/sieve-bin/Makefile.am
+M src/sieve-bin/sieve_test.c
+
+2007-11-24 18:59:29 +0100 Stephan Bosch <stephan@rename-it.nl> (1788802c)
+
+ Added TODO item.
+
+
+M README
+
+2007-11-24 18:55:04 +0100 Stephan Bosch <stephan@rename-it.nl> (7bc6d514)
+
+ Moved address-part, match-type and comparator code registries from
+ interpreter to binary where they belong.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/relational.sieve
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+
+2007-11-24 17:48:38 +0100 Stephan Bosch <stephan@rename-it.nl> (53ff5113)
+
+ Added extension context storage support to the sieve binary.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-interpreter.c
+
+2007-11-24 17:35:48 +0100 Stephan Bosch <stephan@rename-it.nl> (ec61c8ea)
+
+ Added binary_load event to the sieve extensions.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-match-types.c
+
+2007-11-24 15:37:12 +0100 Stephan Bosch <stephan@rename-it.nl> (4d14341a)
+
+ Grouped runtime parameters into a single runtime environment and started
+ implementation of result composition/execution.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-result.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+
+2007-11-24 13:04:37 +0100 Stephan Bosch <stephan@rename-it.nl> (ef8d3cc5)
+
+ Changed interpreter in the event of an unimplemented opcode.
+
+
+M src/lib-sieve/sieve-interpreter.c
+
+2007-11-24 13:00:16 +0100 Stephan Bosch <stephan@rename-it.nl> (ff44b78d)
+
+ Updated documentation.
+
+
+M README
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+
+2007-11-24 02:05:39 +0100 Stephan Bosch <stephan@rename-it.nl> (dd0ffe54)
+
+ Implemented hasflag command interpretation for the imapflags extension.
+
+
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/imapflags-2.sieve
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+
+2007-11-23 23:56:31 +0100 Stephan Bosch <stephan@rename-it.nl> (4bad5e4c)
+
+ Added actual flag management to the imapflags extension. Addflag, removeflag
+ and setflag now do what they should do.
+
+
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+A src/lib-sieve/plugins/imapflags/imapflags-2.sieve
+M src/lib-sieve/plugins/imapflags/imapflags.sieve
+M src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/tst-size.c
+
+2007-11-23 13:34:55 +0100 Stephan Bosch <stephan@rename-it.nl> (cb095ead)
+
+ Finished i;ascii-numeric comparator and fixed a segfault bug in the process.
+
+
+M README
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/relational/relational.sieve
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+
+2007-11-23 12:35:20 +0100 Stephan Bosch <stephan@rename-it.nl> (84c99223)
+
+ Added hasflag test to the imapflags extension.
+
+
+M README
+M src/lib-sieve/plugins/imapflags/Makefile.am
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/imapflags/imapflags-errors.sieve
+M src/lib-sieve/plugins/imapflags/imapflags.sieve
+A src/lib-sieve/plugins/imapflags/tst-hasflag.c
+M src/lib-sieve/tst-header.c
+
+2007-11-23 00:37:41 +0100 Stephan Bosch <stephan@rename-it.nl> (ccf4377f)
+
+ Implemented code generation and interpretation for the commands introduced
+ by the imapflags extension.
+
+
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/imapflags/imapflags.sieve
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+
+2007-11-23 00:18:17 +0100 Stephan Bosch <stephan@rename-it.nl> (bac51d56)
+
+ Upgraded opcode extension support to handle more than one opcode per
+ extension.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/imapflags/cmd-addflag.c
+M src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+M src/lib-sieve/plugins/imapflags/cmd-setflag.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+
+2007-11-22 20:20:28 +0100 Stephan Bosch <stephan@rename-it.nl> (62efe088)
+
+ imapflags: Added (dummy) check for the existance of the variables extension.
+
+
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+M src/lib-sieve/plugins/imapflags/imapflags.sieve
+
+2007-11-22 20:02:57 +0100 Stephan Bosch <stephan@rename-it.nl> (4e603ce4)
+
+ Implemented validation for the commands introduced by the imapflags
+ extension.
+
+
+M src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+A src/lib-sieve/plugins/imapflags/imapflags-errors.sieve
+M src/lib-sieve/sieve-validator.c
+
+2007-11-22 19:35:44 +0100 Stephan Bosch <stephan@rename-it.nl> (60770a2a)
+
+ Created skeletons for the commands introduced by the imapflags extension.
+
+
+M src/lib-sieve/plugins/imapflags/Makefile.am
+A src/lib-sieve/plugins/imapflags/cmd-addflag.c
+A src/lib-sieve/plugins/imapflags/cmd-removeflag.c
+A src/lib-sieve/plugins/imapflags/cmd-setflag.c
+A src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+A src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+M src/lib-sieve/plugins/imapflags/ext-imapflags.c
+A src/lib-sieve/plugins/imapflags/imapflags.sieve
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-validator.c
+
+2007-11-22 17:17:25 +0100 Stephan Bosch <stephan@rename-it.nl> (91669a17)
+
+ Started skeleton for the imapflags extension.
+
+
+M configure.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/imapflags/Makefile.am
+A src/lib-sieve/plugins/imapflags/draft-ietf-sieve-imapflags-05.txt
+A src/lib-sieve/plugins/imapflags/ext-imapflags.c
+
+2007-11-22 16:57:48 +0100 Stephan Bosch <stephan@rename-it.nl> (a2c51b31)
+
+ Cleaned up make process and included the 'plugins' into the main sieve
+ library archive.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/Makefile.am
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile.am
+M src/lib-sieve/plugins/regex/Makefile.am
+M src/lib-sieve/plugins/relational/Makefile.am
+M src/lib-sieve/plugins/subaddress/Makefile.am
+M src/lib-sieve/plugins/vacation/Makefile.am
+M src/sieve-bin/Makefile.am
+
+2007-11-22 13:19:43 +0100 Stephan Bosch <stephan@rename-it.nl> (441a81d5)
+
+ Updated documentation.
+
+
+M README
+M src/lib-sieve/sieve-commands.c
+
+2007-11-22 13:00:17 +0100 Stephan Bosch <stephan@rename-it.nl> (8c021fd9)
+
+ Removed unecessary jump after commands like stop.
+
+
+M sieve/examples/vivil.sieve
+A sieve/tests/stop.sieve
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+
+2007-11-22 11:56:32 +0100 Stephan Bosch <stephan@rename-it.nl> (6e5638ce)
+
+ Debugged :matches match type and no more bugs are currently known.
+
+
+M sieve/tests/matches.sieve
+M src/lib-sieve/sieve-match-types.c
+
+2007-11-22 00:41:00 +0100 Stephan Bosch <stephan@rename-it.nl> (6a6b3409)
+
+ Made first buggy implementation of :matches match type.
+
+
+A sieve/tests/matches.sieve
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-match-types.c
+
+2007-11-21 16:18:36 +0100 Stephan Bosch <stephan@rename-it.nl> (def18c3b)
+
+ Updated documentation with respect to extensions.
+
+
+M README
+
+2007-11-21 16:16:17 +0100 Stephan Bosch <stephan@rename-it.nl> (e22e8718)
+
+ Added dummy execution support to reject extension.
+
+
+A sieve/tests/reject.sieve
+M src/lib-sieve/ext-reject.c
+
+2007-11-21 16:04:49 +0100 Stephan Bosch <stephan@rename-it.nl> (cf64e6d4)
+
+ Updated documentation.
+
+
+M README
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+
+2007-11-21 15:45:23 +0100 Stephan Bosch <stephan@rename-it.nl> (9b1b731c)
+
+ Implemented dummy execution for vacation extension.
+
+
+A sieve/tests/vacation.sieve
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+
+2007-11-21 14:22:17 +0100 Stephan Bosch <stephan@rename-it.nl> (d2eee94d)
+
+ Resolved compiler warning in envelope extension.
+
+
+M src/lib-sieve/ext-envelope.c
+
+2007-11-21 14:21:14 +0100 Stephan Bosch <stephan@rename-it.nl> (01b80d1a)
+
+ Added test script for redirect command.
+
+
+A sieve/tests/redirect.sieve
+
+2007-11-21 14:20:51 +0100 Stephan Bosch <stephan@rename-it.nl> (95738f98)
+
+ Properly implemented stop command and associated opcode.
+
+
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+
+2007-11-21 14:11:13 +0100 Stephan Bosch <stephan@rename-it.nl> (ea70ff34)
+
+ Added status message to sieve_test to indicate successful script run.
+
+
+M src/sieve-bin/sieve_test.c
+
+2007-11-21 14:06:56 +0100 Stephan Bosch <stephan@rename-it.nl> (21e78107)
+
+ Created dummy interpretation support for the redirect command.
+
+
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-interpreter.h
+
+2007-11-21 12:54:14 +0100 Stephan Bosch <stephan@rename-it.nl> (966324cd)
+
+ Created dummy interpretation support for the fileinto extension.
+
+
+A sieve/tests/fileinto.sieve
+M src/lib-sieve/ext-fileinto.c
+
+2007-11-21 12:42:05 +0100 Stephan Bosch <stephan@rename-it.nl> (56a07d5a)
+
+ Removed debug lines in envelope extension.
+
+
+M src/lib-sieve/ext-envelope.c
+
+2007-11-21 12:37:59 +0100 Stephan Bosch <stephan@rename-it.nl> (b4777986)
+
+ Made ext_envelope_get_fields cleaner.
+
+
+M src/lib-sieve/ext-envelope.c
+
+2007-11-21 12:32:12 +0100 Stephan Bosch <stephan@rename-it.nl> (e0f6bd8a)
+
+ Updated documentation.
+
+
+M README
+M src/lib-sieve/ext-envelope.c
+
+2007-11-21 12:26:35 +0100 Stephan Bosch <stephan@rename-it.nl> (b18527bd)
+
+ Made basic execution implementation of the envelope extension.
+
+
+A sieve/tests/envelope.sieve
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve.h
+M src/lib-sieve/tst-address.c
+M src/sieve-bin/sieve_test.c
+
+2007-11-21 11:53:44 +0100 Stephan Bosch <stephan@rename-it.nl> (8c0c5a98)
+
+ Added envelope data to the interpreter environment.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+M src/sieve-bin/sieve_test.c
+
+2007-11-21 04:11:47 +0100 Stephan Bosch <stephan@rename-it.nl> (d951cfec)
+
+ Completed implementation of the relational extension.
+
+
+M README
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/relational.sieve
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+
+2007-11-21 02:46:30 +0100 Stephan Bosch <stephan@rename-it.nl> (0ee0dd7d)
+
+ Improved match handling and started implementing the interpretation of the
+ relational match type.
+
+
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/regex.sieve
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+
+2007-11-20 23:53:15 +0100 Stephan Bosch <stephan@rename-it.nl> (2f3561f5)
+
+ Implemented context validation for :contains match type.
+
+
+M sieve/errors/match-type-errors.sieve
+M sieve/tests/match-type.sieve
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-match-types.c
+
+2007-11-20 23:02:37 +0100 Stephan Bosch <stephan@rename-it.nl> (eb4b1f97)
+
+ Updated documentation with respect to regex externsion and match-type
+ support.
+
+
+M README
+M src/lib-sieve/plugins/regex/ext-regex.c
+
+2007-11-20 22:42:31 +0100 Stephan Bosch <stephan@rename-it.nl> (fbc4e037)
+
+ Last commit broke execution of match types other than :regex...fixed.
+
+
+M src/lib-sieve/sieve-match-types.c
+
+2007-11-20 22:18:07 +0100 Stephan Bosch <stephan@rename-it.nl> (19f3572d)
+
+ Implemented regex match execution.
+
+
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/regex.sieve
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+
+2007-11-20 16:51:03 +0100 Stephan Bosch <stephan@rename-it.nl> (71661efa)
+
+ Fixed missing require in sanjay.sieve example
+
+
+M sieve/examples/sanjay.sieve
+
+2007-11-20 16:43:53 +0100 Stephan Bosch <stephan@rename-it.nl> (9845a640)
+
+ Forgot to handle stringlists in :regex validation.
+
+
+M src/lib-sieve/plugins/regex/ext-regex.c
+
+2007-11-20 16:09:59 +0100 Stephan Bosch <stephan@rename-it.nl> (9d4dce9c)
+
+ Implemented :regex match validation.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/regex/regex-errors.sieve
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+
+2007-11-20 14:26:33 +0100 Stephan Bosch <stephan@rename-it.nl> (05545fa1)
+
+ Implemented detection of duplicate optional arguments.
+
+
+A sieve/errors/address-part-errors.sieve
+M sieve/errors/interesting.sieve
+A sieve/errors/match-type-errors.sieve
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-validator.c
+
+2007-11-20 12:29:58 +0100 Stephan Bosch <stephan@rename-it.nl> (f32edce2)
+
+ Made regex match complaint about comparators other than i;octet or
+ i;ascii-casemap
+
+
+M src/lib-sieve/plugins/regex/ext-regex.c
+A src/lib-sieve/plugins/regex/regex-errors.sieve
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-validator.c
+
+2007-11-20 11:57:46 +0100 Stephan Bosch <stephan@rename-it.nl> (f4a19c3d)
+
+ Added support for match-type argument context validation.
+
+
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+
+2007-11-20 11:42:10 +0100 Stephan Bosch <stephan@rename-it.nl> (f8ecf182)
+
+ Added support for argument context validation.
+
+
+M src/lib-sieve/sieve-validator.c
+
+2007-11-20 11:27:17 +0100 Stephan Bosch <stephan@rename-it.nl> (fcc318e3)
+
+ Added validat_context method to command arguments for the to-be-implemented
+ argument context validation.
+
+
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/tst-size.c
+
+2007-11-20 11:14:22 +0100 Stephan Bosch <stephan@rename-it.nl> (2f2a00b7)
+
+ Changed argument generator function prototype to assign responsibility of
+ advancing to the next argument to the generator itself.
+
+
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-match-types.c
+
+2007-11-20 11:01:03 +0100 Stephan Bosch <stephan@rename-it.nl> (8884f55d)
+
+ Removed i_unreached() at inappropriate location.
+
+
+M src/lib-sieve/sieve-commands.c
+
+2007-11-20 10:57:46 +0100 Stephan Bosch <stephan@rename-it.nl> (8cfba719)
+
+ Removed code duplication in validator: merged command and test validation in
+ one function.
+
+
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-validator.c
+
+2007-11-20 10:29:40 +0100 Stephan Bosch <stephan@rename-it.nl> (422a8f7b)
+
+ Fixed bug in the command validation.
+
+
+M src/lib-sieve/sieve-validator.c
+
+2007-11-20 10:23:42 +0100 Stephan Bosch <stephan@rename-it.nl> (2c111bd4)
+
+ Improved validation of command placement for if and require commands.
+
+
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/sieve-commands.h
+
+2007-11-20 01:22:22 +0100 Stephan Bosch <stephan@rename-it.nl> (523c5df3)
+
+ Changed validator's command syntax validation such that command
+ implementations don't have to call the argument, test and block validation
+ functions explicitly.
+
+
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-commands-private.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+
+2007-11-19 22:54:21 +0100 Stephan Bosch <stephan@rename-it.nl> (8065de38)
+
+ Changed argument validation to record the first positional argument into the
+ command context by default. Also furter improved validator's error handling.
+
+
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-not.c
+M src/lib-sieve/tst-size.c
+
+2007-11-19 21:21:27 +0100 Stephan Bosch <stephan@rename-it.nl> (fd8b7199)
+
+ Revised positional argument checking and fixed the validator's error
+ handling.
+
+
+M sieve/errors/address-errors.sieve
+M sieve/errors/header-errors.sieve
+M src/lib-sieve/cmd-redirect.c
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/subaddress/subaddress.sieve
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+
+2007-11-19 18:50:55 +0100 Stephan Bosch <stephan@rename-it.nl> (689e982a)
+
+ Prevent unimplemented match type from causing a segfault.
+
+
+M src/lib-sieve/sieve-match-types.c
+
+2007-11-19 01:36:23 +0100 Stephan Bosch <stephan@rename-it.nl> (3c0b20dd)
+
+ Implemented match type execution and activated match types :is and
+ :contains.
+
+
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+
+2007-11-17 16:25:53 +0100 Stephan Bosch <stephan@rename-it.nl> (b7e09b56)
+
+ Minor updates to the documentation.
+
+
+M README
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+
+2007-11-17 16:19:24 +0100 Stephan Bosch <stephan@rename-it.nl> (4fc3387f)
+
+ Fixed code generation for relational extension.
+
+
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/plugins/relational/relational.sieve
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+
+2007-11-17 15:24:41 +0100 Stephan Bosch <stephan@rename-it.nl> (7b940591)
+
+ Implemented support for additional parameters to match-types and implemented
+ validation for the relational extension.
+
+
+M src/lib-sieve/plugins/regex/ext-regex.c
+M src/lib-sieve/plugins/relational/ext-relational.c
+M src/lib-sieve/sieve-match-types.c
+M src/lib-sieve/sieve-match-types.h
+
+2007-11-17 14:14:19 +0100 Stephan Bosch <stephan@rename-it.nl> (72477bab)
+
+ Created skeletons for regex and relational extensions. These are to be
+ developed simultaneously with the match-type support in general.
+
+
+M configure.in
+M sieve/tests/match-type.sieve
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/regex/Makefile.am
+A src/lib-sieve/plugins/regex/draft-murchison-sieve-regex-07.txt
+A src/lib-sieve/plugins/regex/ext-regex.c
+A src/lib-sieve/plugins/regex/regex.sieve
+A src/lib-sieve/plugins/relational/Makefile.am
+A src/lib-sieve/plugins/relational/ext-relational.c
+A src/lib-sieve/plugins/relational/relational.sieve
+A src/lib-sieve/plugins/relational/rfc3431.txt
+M src/lib-sieve/sieve-extensions.c
+M src/sieve-bin/Makefile.am
+
+2007-11-17 12:57:36 +0100 Stephan Bosch <stephan@rename-it.nl> (aaa72172)
+
+ Started implementation of match-type support and fixed compilation error.
+
+
+M README
+A sieve/tests/match-type.sieve
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-interpreter.c
+A src/lib-sieve/sieve-match-types.c
+A src/lib-sieve/sieve-match-types.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+
+2007-11-17 11:50:15 +0100 Stephan Bosch <stephan@rename-it.nl> (30c80502)
+
+ Updated README and a few minor cosmetic changes to the code.
+
+
+M README
+M src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-comparators.c
+
+2007-11-17 03:38:50 +0100 Stephan Bosch <stephan@rename-it.nl> (d2ea3b30)
+
+ Implemented comparator-i;ascii-numeric extension and activated comparator
+ extension support.
+
+
+M configure.in
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile.am
+A src/lib-sieve/plugins/comparator-i-ascii-numeric/cmp-i-ascii-numeric.sieve
+A src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+A src/lib-sieve/plugins/comparator-i-ascii-numeric/rfc2244.txt
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+M src/sieve-bin/Makefile.am
+
+2007-11-17 00:14:30 +0100 Stephan Bosch <stephan@rename-it.nl> (332ee54f)
+
+ Added dummy extensions for core comparators.
+
+
+M src/lib-sieve/sieve-extensions.c
+
+2007-11-17 00:07:37 +0100 Stephan Bosch <stephan@rename-it.nl> (fc6b817e)
+
+ A few small cosmetic changes in addr-part code and generic extension
+ support.
+
+
+M sieve/tests/extensions.sieve
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/sieve-address-parts.c
+
+2007-11-16 23:36:03 +0100 Stephan Bosch <stephan@rename-it.nl> (3bd3f8c4)
+
+ Finished implementation of subaddress extension.
+
+
+M src/lib-sieve/plugins/subaddress/ext-subaddress.c
+M src/lib-sieve/plugins/subaddress/subaddress.sieve
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-common.h
+
+2007-11-16 19:35:58 +0100 Stephan Bosch <stephan@rename-it.nl> (2fbe78be)
+
+ Implemented support for the subaddress extension and fixed extension support
+ to work properly.
+
+
+M configure.in
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/subaddress/Makefile.am
+A src/lib-sieve/plugins/subaddress/ext-subaddress.c
+A src/lib-sieve/plugins/subaddress/rfc3598.txt
+A src/lib-sieve/plugins/subaddress/subaddress.sieve
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-size.c
+M src/sieve-bin/Makefile.am
+
+2007-11-14 00:47:06 +0100 Stephan Bosch <stephan@rename-it.nl> (f940ef27)
+
+ Implemented address part execution support.
+
+
+M sieve/tests/address-part.sieve
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/tst-address.c
+
+2007-11-13 22:28:04 +0100 Stephan Bosch <stephan@rename-it.nl> (0b1a8c86)
+
+ Activated address-part code generation support.
+
+
+A sieve/tests/address-part.sieve
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/tst-address.c
+
+2007-11-13 20:26:03 +0100 Stephan Bosch <stephan@rename-it.nl> (b00f75d9)
+
+ Lots of cosmetic changes
+
+
+M src/lib-sieve/sieve-address-parts.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands-private.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-error.c
+M src/lib-sieve/sieve-error.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-lexer.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-validator.h
+
+2007-11-13 16:49:23 +0100 Stephan Bosch <stephan@rename-it.nl> (c1013f0d)
+
+ Added a little documentation to the README file.
+
+
+M INSTALL
+M README
+
+2007-11-13 00:39:35 +0100 Stephan Bosch <stephan@rename-it.nl> (1f797b35)
+
+ Removed unused static pre-declaration from validator.
+
+
+M src/lib-sieve/sieve-validator.c
+
+2007-11-13 00:09:18 +0100 Stephan Bosch <stephan@rename-it.nl> (2a192d0d)
+
+ Rewrote large parts of the extension support and added partial address-part
+ implementation.
+
+
+M sieve/tests/comparator.sieve
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+A src/lib-sieve/sieve-address-parts.c
+A src/lib-sieve/sieve-address-parts.h
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+M src/sieve-bin/sieve_test.c
+M src/sieve-bin/sievec.c
+
+2007-11-11 21:11:54 +0100 Stephan Bosch <stephan@rename-it.nl> (85e7a741)
+
+ Upgraded sieve_test to 1.1.beta8
+
+
+M src/sieve-bin/Makefile.am
+M src/sieve-bin/sieve_test.c
+
+2007-11-11 18:01:57 +0100 Stephan Bosch <stephan@rename-it.nl> (acc9246f)
+
+ Enabled comparator execution support.
+
+
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+
+2007-11-11 17:19:01 +0100 Stephan Bosch <stephan@rename-it.nl> (e25f3baf)
+
+ Added support for optional operators to the byte code implementation.
+
+
+M sieve/tests/comparator.sieve
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+
+2007-11-09 01:23:12 +0100 Stephan Bosch <stephan@rename-it.nl> (4e793fea)
+
+ Started implementation of comparator execution support.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+
+2007-11-08 19:33:00 +0100 Stephan Bosch <stephan@rename-it.nl> (9ac7cd5d)
+
+ Changed string-list single-string handling for coded list.
+
+
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+
+2007-11-08 17:34:37 +0100 Stephan Bosch <stephan@rename-it.nl> (95b2627e)
+
+ Properly implemented opcode and operand handing and moved code to more
+ appropriate units.
+
+
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+
+2007-11-01 10:23:03 +0100 Stephan Bosch <stephan@rename-it.nl> (d5819c6a)
+
+ A few minor changes
+
+
+M sieve/examples/sieve_examples.sieve
+D sieve/examples/stephan.sieve
+D sieve/examples/unparsed-elvey.sieve
+M src/lib-sieve/sieve-code.h
+
+2007-11-01 10:10:36 +0100 Stephan Bosch <stephan@rename-it.nl> (320022d2)
+
+ Added sieve example and documented the others with author and the url where
+ I found them.
+
+
+M sieve/examples/elvey.sieve
+A sieve/examples/jerry.sieve
+M sieve/examples/mjohnson.sieve
+M sieve/examples/mklose.sieve
+M sieve/examples/sanjay.sieve
+M sieve/examples/vivil.sieve
+
+2007-10-27 04:25:17 +0200 Stephan Bosch <stephan@rename-it.nl> (5135e910)
+
+ Moved literall access functions from interpreter to binary.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+
+2007-10-27 03:15:31 +0200 Stephan Bosch <stephan@rename-it.nl> (8c99880d)
+
+ Implemented comparator support towards code generation, interpretation is
+ not possible yet.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-comparators.c
+M src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+
+2007-10-27 02:31:18 +0200 Stephan Bosch <stephan@rename-it.nl> (286046df)
+
+ Changed argument to operand processing to be much more flexible.
+
+
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+
+2007-10-26 22:43:55 +0200 Stephan Bosch <stephan@rename-it.nl> (c5d1b547)
+
+ Moved literal emission functions from generator to binary source.
+
+
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+
+2007-10-26 22:13:41 +0200 Stephan Bosch <stephan@rename-it.nl> (b0868f2e)
+
+ First steps towards implementing code generation and interpretation for
+ proper comperators.
+
+
+A sieve/tests/comparator.sieve
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-ast.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.h
+M src/lib-sieve/sieve-common.h
+A src/lib-sieve/sieve-comparators.c
+A src/lib-sieve/sieve-comparators.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/tst-size.c
+
+2007-10-26 01:29:34 +0200 Stephan Bosch <stephan@rename-it.nl> (685d4195)
+
+ Extremely minor cosmetic change.
+
+
+M src/lib-sieve/tst-exists.c
+
+2007-10-26 01:24:07 +0200 Stephan Bosch <stephan@rename-it.nl> (57cdd9b8)
+
+ Removed files with intermittent compilation results from the repository
+ (oops)
+
+
+D src/lib-sieve/plugins/Makefile
+D src/lib-sieve/plugins/Makefile.in
+
+2007-10-26 01:20:31 +0200 Stephan Bosch <stephan@rename-it.nl> (d039e98e)
+
+ Made header and exists tests executable.
+
+
+M sieve/tests/basic.sieve
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+
+2007-10-25 22:43:53 +0200 Stephan Bosch <stephan@rename-it.nl> (cc7a4672)
+
+ Made address and size tests executable and fixed minor bug regarding the
+ lexer.
+
+
+M sieve/tests/basic.sieve
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve.c
+M src/lib-sieve/sieve.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-size.c
+M src/sieve-bin/Makefile.am
+M src/sieve-bin/sieve_test.c
+M src/sieve-bin/sievec.c
+
+2007-10-25 12:26:52 +0200 Stephan Bosch <stephan@rename-it.nl> (34b986f5)
+
+ Created libsieve interface and started the sieve_test binary.
+
+
+M .hgignore
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-parser.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+A src/lib-sieve/sieve.c
+A src/lib-sieve/sieve.h
+D src/sieve-bin/Makefile
+M src/sieve-bin/Makefile.am
+D src/sieve-bin/Makefile.in
+A src/sieve-bin/sieve_test.c
+D src/sieve-bin/sievec
+M src/sieve-bin/sievec.c
+D src/sieve-bin/sievec.o
+
+2007-10-24 22:48:57 +0200 Stephan Bosch <stephan@rename-it.nl> (58177948)
+
+ Upgraded from dovecot-1.0 to dovecot-1.1 (array changes and various _unref
+ differences)
+
+
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/Makefile
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-ast.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-lexer.c
+M src/lib-sieve/sieve-parser.c
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-size.c
+M src/sieve-bin/Makefile
+M src/sieve-bin/Makefile.am
+M src/sieve-bin/Makefile.in
+M src/sieve-bin/sievec
+M src/sieve-bin/sievec.o
+
+2007-10-24 19:24:42 +0200 Stephan Bosch <stephan@rename-it.nl> (580d9522)
+
+ Exported sievec binary to separate directory called sieve-bin.
+
+
+M configure.in
+R100 src/lib-sieve/scripts/errors/address-errors.sieve sieve/errors/address-errors.sieve
+R100 src/lib-sieve/scripts/errors/header-errors.sieve sieve/errors/header-errors.sieve
+R100 src/lib-sieve/scripts/errors/if-errors.sieve sieve/errors/if-errors.sieve
+R100 src/lib-sieve/scripts/errors/interesting.sieve sieve/errors/interesting.sieve
+R100 src/lib-sieve/scripts/errors/keep-errors.sieve sieve/errors/keep-errors.sieve
+R100 src/lib-sieve/scripts/errors/parse-errors.sieve sieve/errors/parse-errors.sieve
+R100 src/lib-sieve/scripts/errors/require-errors.sieve sieve/errors/require-errors.sieve
+R100 src/lib-sieve/scripts/errors/size-errors.sieve sieve/errors/size-errors.sieve
+R100 src/lib-sieve/scripts/errors/stop-errors.sieve sieve/errors/stop-errors.sieve
+R100 src/lib-sieve/scripts/errors/tag-errors.sieve sieve/errors/tag-errors.sieve
+R100 src/lib-sieve/scripts/examples/elvey.sieve sieve/examples/elvey.sieve
+R100 src/lib-sieve/scripts/examples/mjohnson.sieve sieve/examples/mjohnson.sieve
+R100 src/lib-sieve/scripts/examples/mklose.sieve sieve/examples/mklose.sieve
+R100 src/lib-sieve/scripts/examples/rfc3028.sieve sieve/examples/rfc3028.sieve
+R100 src/lib-sieve/scripts/examples/sanjay.sieve sieve/examples/sanjay.sieve
+R100 src/lib-sieve/scripts/examples/sieve_examples.sieve sieve/examples/sieve_examples.sieve
+R100 src/lib-sieve/scripts/examples/stephan.sieve sieve/examples/stephan.sieve
+R100 src/lib-sieve/scripts/examples/unparsed-elvey.sieve sieve/examples/unparsed-elvey.sieve
+R100 src/lib-sieve/scripts/examples/vacation.sieve sieve/examples/vacation.sieve
+R100 src/lib-sieve/scripts/examples/vivil.sieve sieve/examples/vivil.sieve
+A sieve/tests/basic.sieve
+R100 src/lib-sieve/scripts/tests/extensions.sieve sieve/tests/extensions.sieve
+R100 src/lib-sieve/scripts/tests/if.sieve sieve/tests/if.sieve
+M src/Makefile.am
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-result.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+A src/sieve-bin/Makefile
+A src/sieve-bin/Makefile.am
+A src/sieve-bin/Makefile.in
+A src/sieve-bin/sievec
+R096 src/lib-sieve/sievec.c src/sieve-bin/sievec.c
+A src/sieve-bin/sievec.o
+
+2007-10-23 23:19:33 +0200 Stephan Bosch <stephan@rename-it.nl> (205c43b3)
+
+ Started first support for actual execution of sieve script.
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/plugins/vacation/Makefile.am
+M src/lib-sieve/plugins/vacation/ext-vacation.c
+M src/lib-sieve/sieve-binary.c
+M src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-common.h
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+A src/lib-sieve/sieve-result.c
+A src/lib-sieve/sieve-result.h
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+
+2007-10-23 19:32:31 +0200 Stephan Bosch <stephan@rename-it.nl> (639b71a3)
+
+ * Minor changes to the extension implementation * Started the lda plugin
+ source
+
+
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/sieve-interpreter.h
+A src/plugins/Makefile.am
+A src/plugins/lda-sieve/Makefile.am
+A src/plugins/lda-sieve/lda-sieve-plugin.c
+A src/plugins/lda-sieve/lda-sieve-plugin.h
+
+2007-10-22 14:40:01 +0200 Stephan Bosch <stephan@rename-it.nl> (06b238a1)
+
+ Changed (currently unused) sieve-address.c to use dovecot rfc822 parser.
+
+
+M src/lib-sieve/sieve-address.c
+
+2007-10-22 12:54:02 +0200 Stephan Bosch <stephan@rename-it.nl> (b2bf1705)
+
+ Added draft RFC for vacation extension.
+
+
+A src/lib-sieve/plugins/vacation/draft-ietf-sieve-vacation-07.txt
+
+2007-10-22 12:32:53 +0200 Stephan Bosch <stephan@rename-it.nl> (1b2660d2)
+
+ * Further developed the extension support * Added plugins as static
+ libraries (for now)
+
+
+M configure.in
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+A src/lib-sieve/plugins/Makefile
+A src/lib-sieve/plugins/Makefile.am
+A src/lib-sieve/plugins/Makefile.in
+D src/lib-sieve/plugins/comparator-i;ascii-numeric.c
+D src/lib-sieve/plugins/copy.c
+A src/lib-sieve/plugins/vacation/Makefile.am
+A src/lib-sieve/plugins/vacation/ext-vacation.c
+A src/lib-sieve/plugins/vacation/vacation.sieve
+M src/lib-sieve/scripts/tests/extensions.sieve
+M src/lib-sieve/sieve-extensions.c
+
+2007-10-22 01:04:14 +0200 Stephan Bosch <stephan@rename-it.nl> (a5bb7080)
+
+ Renamed reject.sieve to extensions.sieve for generic extensions testing.
+
+
+A src/lib-sieve/scripts/tests/extensions.sieve
+D src/lib-sieve/scripts/tests/reject.sieve
+
+2007-10-22 01:02:02 +0200 Stephan Bosch <stephan@rename-it.nl> (468f75b2)
+
+ * Added generation support to the fileinto extension. * Fixed a bug in the
+ require command generation.
+
+
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/ext-fileinto.c
+
+2007-10-22 00:38:55 +0200 Stephan Bosch <stephan@rename-it.nl> (a3f9de83)
+
+ Added basic extension support to generator and interpreter.
+
+
+M .hgignore
+M src/lib-sieve/Makefile.am
+M src/lib-sieve/cmd-require.c
+M src/lib-sieve/ext-envelope.c
+M src/lib-sieve/ext-fileinto.c
+M src/lib-sieve/ext-reject.c
+A src/lib-sieve/scripts/tests/reject.sieve
+M src/lib-sieve/sieve-ast.h
+A src/lib-sieve/sieve-binary.c
+A src/lib-sieve/sieve-binary.h
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-extensions.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/sieve-interpreter.h
+M src/lib-sieve/sieve-validator.c
+M src/lib-sieve/sieve-validator.h
+M src/lib-sieve/sievec.c
+
+2007-10-21 18:55:38 +0200 Stephan Bosch <stephan@rename-it.nl> (36338359)
+
+ Initial commit didn't compile because it was comitted in the middle of a new
+ feature.
+
+
+M src/lib-sieve/cmd-if.c
+M src/lib-sieve/ext-reject.c
+M src/lib-sieve/sieve-code.c
+M src/lib-sieve/sieve-code.h
+M src/lib-sieve/sieve-commands-private.h
+M src/lib-sieve/sieve-commands.c
+M src/lib-sieve/sieve-extensions.h
+M src/lib-sieve/sieve-generator.c
+M src/lib-sieve/sieve-generator.h
+M src/lib-sieve/sieve-interpreter.c
+M src/lib-sieve/tst-address.c
+M src/lib-sieve/tst-allof.c
+M src/lib-sieve/tst-anyof.c
+M src/lib-sieve/tst-exists.c
+M src/lib-sieve/tst-header.c
+M src/lib-sieve/tst-size.c
+
+2007-10-21 16:49:08 +0200 Stephan Bosch <stephan@rename-it.nl> (5775c74c)
+
+ Added autogen.sh from the dovecot project (removed doc/wiki code)
+
+
+A autogen.sh
+
+2007-10-21 16:31:24 +0200 stephan <stephan@flappie> (d9ba5172)
+
+ Added -config files to the hgignore and removed them from the repository
+
+
+M .hgignore
+D libsieve-config.h.in
+
+2007-10-21 16:23:07 +0200 stephan <stephan@flappie> (ef67ede6)
+
+ First entered libsieve into new Hg repository
+
+
+A .hgignore
+A AUTHORS
+A COPYING.LGPL
+A INSTALL
+A Makefile.am
+A NEWS
+A README
+A configure.in
+A libsieve-config.h.in
+A src/Makefile.am
+A src/lib-sieve/Makefile.am
+A src/lib-sieve/cmd-if.c
+A src/lib-sieve/cmd-redirect.c
+A src/lib-sieve/cmd-require.c
+A src/lib-sieve/ext-envelope.c
+A src/lib-sieve/ext-fileinto.c
+A src/lib-sieve/ext-reject.c
+A src/lib-sieve/plugins/comparator-i;ascii-numeric.c
+A src/lib-sieve/plugins/copy.c
+A src/lib-sieve/scripts/errors/address-errors.sieve
+A src/lib-sieve/scripts/errors/header-errors.sieve
+A src/lib-sieve/scripts/errors/if-errors.sieve
+A src/lib-sieve/scripts/errors/interesting.sieve
+A src/lib-sieve/scripts/errors/keep-errors.sieve
+A src/lib-sieve/scripts/errors/parse-errors.sieve
+A src/lib-sieve/scripts/errors/require-errors.sieve
+A src/lib-sieve/scripts/errors/size-errors.sieve
+A src/lib-sieve/scripts/errors/stop-errors.sieve
+A src/lib-sieve/scripts/errors/tag-errors.sieve
+A src/lib-sieve/scripts/examples/elvey.sieve
+A src/lib-sieve/scripts/examples/mjohnson.sieve
+A src/lib-sieve/scripts/examples/mklose.sieve
+A src/lib-sieve/scripts/examples/rfc3028.sieve
+A src/lib-sieve/scripts/examples/sanjay.sieve
+A src/lib-sieve/scripts/examples/sieve_examples.sieve
+A src/lib-sieve/scripts/examples/stephan.sieve
+A src/lib-sieve/scripts/examples/unparsed-elvey.sieve
+A src/lib-sieve/scripts/examples/vacation.sieve
+A src/lib-sieve/scripts/examples/vivil.sieve
+A src/lib-sieve/scripts/tests/if.sieve
+A src/lib-sieve/sieve-address.c
+A src/lib-sieve/sieve-ast.c
+A src/lib-sieve/sieve-ast.h
+A src/lib-sieve/sieve-code.c
+A src/lib-sieve/sieve-code.h
+A src/lib-sieve/sieve-commands-private.h
+A src/lib-sieve/sieve-commands.c
+A src/lib-sieve/sieve-commands.h
+A src/lib-sieve/sieve-common.h
+A src/lib-sieve/sieve-error.c
+A src/lib-sieve/sieve-error.h
+A src/lib-sieve/sieve-extensions.c
+A src/lib-sieve/sieve-extensions.h
+A src/lib-sieve/sieve-generator.c
+A src/lib-sieve/sieve-generator.h
+A src/lib-sieve/sieve-interpreter.c
+A src/lib-sieve/sieve-interpreter.h
+A src/lib-sieve/sieve-lexer.c
+A src/lib-sieve/sieve-lexer.h
+A src/lib-sieve/sieve-parser.c
+A src/lib-sieve/sieve-parser.h
+A src/lib-sieve/sieve-validator.c
+A src/lib-sieve/sieve-validator.h
+A src/lib-sieve/sievec.c
+A src/lib-sieve/tst-address.c
+A src/lib-sieve/tst-allof.c
+A src/lib-sieve/tst-anyof.c
+A src/lib-sieve/tst-exists.c
+A src/lib-sieve/tst-header.c
+A src/lib-sieve/tst-not.c
+A src/lib-sieve/tst-size.c
+A stamp.h.in
diff --git a/pigeonhole/INSTALL b/pigeonhole/INSTALL
new file mode 100644
index 0000000..eca1360
--- /dev/null
+++ b/pigeonhole/INSTALL
@@ -0,0 +1,903 @@
+Compiling
+=========
+
+If you downloaded the sources using Mercurial, you will need to execute
+./autogen.sh first to build the automake structure in your source tree. This
+process requires autotools and libtool to be installed.
+
+If you installed Dovecot from sources, Pigeonhole's configure script should be
+able to find the installed dovecot-config automatically:
+
+./configure
+make
+sudo make install
+
+If your system uses a $prefix different than the default /usr/local, the
+configure script can still find the installed dovecot-config automatically when
+supplied with the proper --prefix argument:
+
+./configure --prefix=/usr
+make
+sudo make install
+
+If this doesn't work, you can use --with-dovecot=<path> configure option, where
+the path points to a directory containing dovecot-config file. This can point to
+an installed file:
+
+./configure --with-dovecot=/usr/local/lib/dovecot
+make
+sudo make install
+
+or to a Dovecot source directory that is already compiled:
+
+./configure --with-dovecot=../dovecot-2.1.0
+make
+sudo make install
+
+The following additional parameters may be of interest for the configuration of
+the Pigeonhole build:
+
+ --with-managesieve=yes
+ Controls whether Pigeonhole ManageSieve is compiled and installed, which is
+ the default.
+
+ --with-unfinished-features=no
+ Controls whether unfinished features and extensions are built. Enabling this
+ will enable the compilation of code that is considered unfinished and highly
+ experimental and may therefore introduce bugs and unexpected behavior.
+ In fact, it may not compile at all. Enable this only when you are eager to
+ test some of the new development functionality.
+
+ --with-ldap=no
+ Controls wether Sieve LDAP support is built. This allows retrieving Sieve
+ scripts from an LDAP database. When set to `yes', support is built in. When
+ set to `plugin', LDAP support is compiled into a Sieve plugin called
+ `sieve_storage_ldap'.
+
+Configuration
+=============
+
+The Pigeonhole package provides the following items:
+
+ - The Sieve interpreter plugin for Dovecot's Local Delivery Agent (LDA): This
+ facilitates the actual Sieve filtering upon delivery.
+
+ - The ManageSieve Service: This implements the ManageSieve protocol through
+ which users can remotely manage Sieve scripts on the server.
+
+The functionality of these items is described in more detail in the README file.
+In this file and in this section their configuration is described. Example
+configuration files are provided in the doc/example-config directory of this
+package.
+
+Sieve Interpreter - Script Locations
+------------------------------------
+
+The Sieve interpreter can retrieve Sieve scripts from several types of
+locations. The default `file' location type is a local filesystem path pointing
+to a Sieve script file or a directory containing multiple Sieve script files.
+More complex setups can use other location types such as `ldap' or `dict' to
+fetch Sieve scripts from remote databases.
+
+All settings that specify the location of one ore more Sieve scripts accept the
+following syntax:
+
+location = [<type>:]path[;<option>[=<value>][;...]]
+
+The following script location types are implemented by default:
+
+ file - The location path is a file system path pointing to the script file
+ or a directory containing script files with names structured as
+ `<script-name>.sieve'. Read doc/locations/file.txt for more
+ information and examples.
+
+ dict - The location path is a Dovecot dict uri. Read doc/locations/dict.txt
+ for more information and examples.
+
+ ldap - LDAP database lookup. The location path is a configuration file with
+ LDAP options. Read doc/locations/ldap.txt for more information
+ and examples.
+
+If the type prefix is omitted, the script location type is 'file' and the
+location is interpreted as a local filesystem path pointing to a Sieve script
+file or directory.
+
+The following options are defined for all location types:
+
+ name=<script-name>
+ Set the name of the Sieve script that this location points to. If the name
+ of the Sieve script is not contained in the location path and the
+ location of a single script is specified, this option is required
+ (e.g. for dict locations that must point to a particular script).
+ If the name of the script is contained in the location path, the value of
+ the name option overrides the name retrieved from the location. If the Sieve
+ interpreter explicitly queries for a specific name (e.g. to let the Sieve
+ "include" extension retrieve a script from the sieve_global= location),
+ this option has no effect.
+
+ bindir=<dirpath>
+ Points to the directory where the compiled binaries for this script location
+ are stored. This directory is created automatically if possible. If this
+ option is omitted, the behavior depends on the location type. For `file'
+ type locations, the binary is then stored in the same directory as where the
+ script file was found if possible. For `dict' type locations, the binary is
+ not stored at all in that case. Don't specify the same directory for
+ different script locations, as this will result in undefined behavior.
+ Multiple mail users can share a single script directory if the script
+ location is the same and all users share the same system credentials (uid,
+ gid).
+
+Sieve Interpreter - Basic Configuration
+---------------------------------------
+
+To use Sieve, you will first need to make sure you are using Dovecot LDA
+or Dovecot LMTP for delivering incoming mail to users' mailboxes. Then, you need
+to enable the Sieve interpreter plugin for LDA/LMTP in your dovecot.conf:
+
+protocol lda {
+..
+ mail_plugins = sieve # ... other plugins like quota
+}
+
+protocol lmtp {
+..
+ mail_plugins = sieve # ... other plugins like quota
+}
+
+The Sieve interpreter recognizes the following configuration options in the
+plugin section of the config file (default values are shown if applicable):
+
+ sieve = file:~/sieve;active=~/.dovecot.sieve
+ The location of the user's main Sieve script or script storage. The LDA
+ Sieve plugin uses this to find the active script for Sieve filtering at
+ delivery. The "include" extension uses this location for retrieving
+ :personal" scripts.
+
+ This location is also where the ManageSieve service will store the user's
+ scripts, if supported by the location type. For the 'file' location type, the
+ location will then be the path to the storage directory for all the user's
+ personal Sieve scripts. ManageSieve maintains a symbolic link pointing to
+ the currently active script (the script executed at delivery). The location
+ of this symbolic link can be configured using the `;active=<path>' option.
+
+ sieve_default =
+ The location of the default personal sieve script file, which gets executed
+ ONLY if user's private Sieve script does not exist, e.g.
+ /var/lib/dovecot/default.sieve. This is usually a global script, so be sure
+ to pre-compile this script manually using the sievec command line tool, as
+ explained in the README file. This setting used to be called
+ `sieve_global_path', but that name is now deprecated.
+
+ sieve_default_name =
+ The name by which the default Sieve script is visible to ManageSieve
+ clients. Normally, it is not visible at all. See "Visible Default Script"
+ section below for more information.
+
+ sieve_global =
+ Location for :global include scripts for the Sieve include extension. This
+ setting used to be called `sieve_global_dir', but that name is now
+ deprecated.
+
+ sieve_discard =
+ The location of a Sieve script that is run for any message that is about to
+ be discarded; i.e., it is not delivered anywhere by the normal Sieve
+ execution. This only happens when the "implicit keep" is canceled, by e.g.
+ the "discard" action, and no actions that deliver the message are executed.
+ This "discard script" can prevent discarding the message, by executing
+ alternative actions. If the discard script does nothing, the message is still
+ discarded as it would be when no discard script is configured.
+
+ sieve_extensions =
+ Which Sieve language extensions are available to users. By default, all
+ supported extensions are available, except for deprecated extensions or those
+ that are still under development. Some system administrators may want to
+ disable certain Sieve extensions or enable those that are not available by
+ default. This setting can use '+' and '-' to specify differences relative to
+ the default. For example `sieve_extensions = +imapflags' will enable the
+ deprecated imapflags extension in addition to all extensions were already
+ enabled by default.
+
+ sieve_global_extensions =
+ Which Sieve language extensions are ONLY avalable in global scripts. This can
+ be used to restrict the use of certain Sieve extensions to administrator
+ control, for instance when these extensions can cause security concerns. This
+ setting has higher precedence than the `sieve_extensions' setting (above),
+ meaning that the extensions enabled with this setting are never available to
+ the user's personal script no matter what is specified for the
+ `sieve_extensions' setting. The syntax of this setting is similar to
+ the `sieve_extensions' setting, with the difference that extensions are
+ enabled or disabled for exclusive use in global scripts. Currently, no
+ extensions are marked as such by default.
+
+ sieve_implicit_extensions =
+ Which Sieve language extensions are implicitly available to users. The
+ extensions listed in this setting do not need to be enabled explicitly using
+ the Sieve "require" command. This behavior directly violates the Sieve
+ standard, but can be necessary for compatibility with some existing
+ implementations of Sieve (notably jSieve). Do not use this setting unless you
+ really need to! The syntax and semantics of this setting are otherwise
+ identical to the `sieve_extensions' setting
+
+ sieve_plugins =
+ The Pigeonhole Sieve interpreter can have plugins of its own. Using this
+ setting, the used plugins can be specified. Check the Dovecot wiki
+ (wiki2.dovecot.org) or the pigeonhole website (http://pigeonhole.dovecot.org)
+ for available plugins. The `sieve_extprograms' plugin is included in this
+ release. LDAP support may also be compiled as a plugin called
+ `sieve_storage_ldap'.
+
+ sieve_user_email =
+ The primary e-mail address for the user. This is used as a default when no
+ other appropriate address is available for sending messages. If this setting
+ is not configured, either the postmaster or null "<>" address is used as a
+ sender, depending on the action involved. This setting is important when
+ there is no message envelope to extract addresses from, such as when the
+ script is executed in IMAP.
+
+ sieve_user_log =
+ The path to the file where the user log file is written. If not configured, a
+ default location is used. If the main user's personal Sieve (as configured
+ with sieve=) is a file, the logfile is set to <filename>.log by default. If
+ it is not a file, the default user log file is ~/.dovecot.sieve.log.
+
+ recipient_delimiter = +
+ The separator that is expected between the :user and :detail address parts
+ introduced by the subaddress extension. This may also be a sequence of
+ characters (e.g. '--'). The current implementation looks for the separator
+ from the left of the localpart and uses the first one encountered. The :user
+ part is left of the separator and the :detail part is right. This setting is
+ also used by Dovecot's LMTP service.
+
+ sieve_redirect_envelope_from = sender
+ Specifies what envelope sender address is used for redirected messages.
+ Normally, the Sieve "redirect" command copies the sender address for the
+ redirected message from the processed message. So, the redirected message
+ appears to originate from the original sender. The following values are
+ supported for this setting:
+
+ "sender" - The sender address is used (default).
+ "recipient" - The final recipient address is used.
+ "orig_recipient" - The original recipient is used.
+ "user_email" - The user's primary address is used. This is
+ configured with the "sieve_user_email" setting. If
+ that setting is unconfigured, "user_mail" is equal to
+ "sender" (the default).
+ "postmaster" - The postmaster_address configured for the LDA.
+ "<user@domain>" - Redirected messages are always sent from user@domain.
+ The angle brackets are mandatory. The null "<>" address
+ is also supported.
+
+ When the envelope sender of the processed message is the null address "<>",
+ the envelope sender of the redirected message is also always "<>",
+ irrespective of what is configured for this setting.
+
+ sieve_redirect_duplicate_period = 12h
+ In an effort to halt potential mail loops, the Sieve redirect action records
+ identifying information for messages it has forwarded. If a duplicate message
+ is seen, it is not redirected and the message is discarded; i.e., the
+ implicit keep is canceled. This setting configures the period during which
+ the identifying information is recorded. If an account forwards many
+ messages, it may be necessary to lower this setting to prevent the
+ ~/.dovecot.lda-dupes database file (in which these are recorded) from growing
+ to an impractical size.
+
+For example:
+
+plugin {
+...
+ # The include extension fetches the :personal scripts from this
+ # directory. When ManageSieve is used, this is also where scripts
+ # are uploaded.
+ sieve = file:~/sieve
+
+ # If the user has no personal active script (i.e. if the location
+ # indicated in sieve= settings does have and active script or does not exist),
+ # use this one:
+ sieve_default = /var/lib/dovecot/sieve/default.sieve
+
+ # The include extension fetches the :global scripts from this
+ # directory.
+ sieve_global = /var/lib/dovecot/sieve/global/
+}
+
+Sieve Interpreter - Configurable Limits
+---------------------------------------
+
+The settings that specify a period are specified in s(econds), unless followed
+by a d(ay), h(our), or m(inute) specifier character.
+
+ sieve_max_script_size = 1M
+ The maximum size of a Sieve script. The compiler will refuse to compile any
+ script larger than this limit. If set to 0, no limit on the script size is
+ enforced.
+
+ sieve_max_actions = 32
+ The maximum number of actions that can be performed during a single script
+ execution. If set to 0, no limit on the total number of actions is enforced.
+
+ sieve_max_redirects = 4
+ The maximum number of redirect actions that can be performed during a single
+ script execution. If set to 0, no redirect actions are allowed.
+
+ sieve_max_cpu_time = 30s
+ The maximum amount of CPU time that a Sieve script is allowed to use while
+ executing. If the execution exceeds this resource limit, the script ends with
+ an error, causing the implicit "keep" action to be executed. This limit is
+ not only enforced for a single script execution, but also cumulatively for
+ the last executions within a configurable timeout
+ (see sieve_resource_usage_timeout).
+
+ sieve_resource_usage_timeout = 1h
+ To prevent abuse, the Sieve interpreter can record resource usage of a Sieve
+ script execution in the compiled binary if it is significant. Currently, this
+ happens when CPU system + user time exceeds 1.5 seconds for one execution.
+ Such high resource usage is summed over time in the binary and once that
+ cumulative resource usage exceeds the limits (sieve_max_cpu_time), the Sieve
+ script is disabled in the binary for future execution, even if an individual
+ execution exceeded no limits. If the last time high resource usage was
+ recorded is older than sieve_resource_usage_timeout, the resource usage in
+ the binary is reset. This means that the Sieve script is only disabled when
+ the limits are cumulatively exceeded within this timeout. With the default
+ configuration this means that the Sieve script is only disabled when the
+ total CPU time of Sieve executions that lasted more than 1.5 seconds exceeds
+ 30 seconds in the last hour. A disabled Sieve script can be reactivated by
+ the user by uploading a new version of the Sieve script after the excessive
+ resource usage times out. An administrator can force reactivation by forcing
+ a script compile (e.g. using the sievec command line tool).
+
+Sieve Interpreter - Per-user Sieve Script Location
+--------------------------------------------------
+
+By default, the Pigeonhole LDA Sieve plugin looks for the user's Sieve script
+file in the user's home directory (~/.dovecot.sieve). This requires that the
+home directory is set for the user.
+
+If you want to store the script elsewhere, you can override the default using
+the sieve= setting, which specifies the location of the user's script file. This
+can be done in two ways:
+
+ 1. Define the sieve setting in the plugin section of dovecot.conf.
+ 2. Return sieve extra field from userdb extra fields.
+
+For example, to use a Sieve script file named <username>.sieve in
+/var/sieve-scripts, use:
+
+plugin {
+...
+
+ sieve = /var/sieve-scripts/%u.sieve
+}
+
+You may use templates like %u, as shown in the example. Refer to
+http://wiki.dovecot.org/Variables for more information.
+
+A relative path (or just a filename) will be interpreted to point under the
+user's home directory.
+
+Sieve Interpreter - Executing Multiple Scripts Sequentially
+-----------------------------------------------------------
+
+Pigeonhole's Sieve interpreter allows executing multiple Sieve scripts
+sequentially. The extra scripts can be executed before and after the user's
+private script. For example, this allows executing global Sieve policies before
+the user's script. The following settings in the plugin section of the Dovecot
+config file control the execution sequence:
+
+ sieve_before =
+ sieve_before2 =
+ sieve_before3 = (etc..)
+ Location Sieve of scripts that need to be executed before the user's personal
+ script. If a 'file' location path points to a directory, all the Sieve
+ scripts contained therein (with the proper `.sieve' extension) are executed.
+ The order of execution within that directory is determined by the file names,
+ using a normal 8bit per-character comparison.
+
+ Multiple script locations can be specified by appending an increasing number
+ to the setting name. The Sieve scripts found from these locations are added
+ to the script execution sequence in the specified order. Reading the numbered
+ sieve_before settings stops at the first missing setting, so no numbers may
+ be skipped.
+
+ sieve_after =
+ sieve_after2 =
+ sieve_after3 = (etc..)
+ Identical to sieve_before, but the specified scripts are executed after the
+ user's script (only when keep is still in effect, as explained below).
+
+The script execution ends when the currently executing script in the sequence
+does not yield a "keep" result: when the script terminates, the next script is
+only executed if an implicit or explicit "keep" is in effect. Thus, to end all
+script execution, a script must not execute keep and it must cancel the implicit
+keep, e.g. by executing "discard; stop;". This means that the command "keep;"
+has different semantics when used in a sequence of scripts. For normal Sieve
+execution, "keep;" is equivalent to "fileinto "INBOX";", because both cause the
+message to be stored in INBOX. However, in sequential script execution, it only
+controls whether the next script is executed. Storing the message into INBOX
+(the default folder) is not done until the last script in the sequence executes
+(implicit) keep. To force storing the message into INBOX earlier in the
+sequence, the fileinto command can be used (with ":copy" or together with
+"keep;").
+
+Apart from the keep action, all actions triggered in a script in the sequence
+are executed before continuing to the next script. This means that when a script
+in the sequence encounters an error, actions from earlier executed scripts are
+not affected. The sequence is broken however, meaning that the script execution
+of the offending script is aborted and no further scripts are executed. An
+implicit keep is executed instead if necessary, meaning that the interpreter
+makes sure that the message is at least stored in the default folder (INBOX).
+
+Just as for executing a single script the normal way, the Pigeonhole LDA Sieve
+plugin takes care never to duplicate deliveries, forwards or responses. When
+vacation actions are executed multiple times in different scripts, the usual
+error is not triggered: the subsequent duplicate vacation actions are simply
+discarded.
+
+For example:
+
+plugin {
+...
+ # Global scripts executed before the user's personal script.
+ # E.g. handling messages marked as dangerous
+ sieve_before = /var/lib/dovecot/sieve/discard-virusses.sieve
+
+ # Domain-level scripts retrieved from LDAP
+ sieve_before2 = ldap:/etc/dovecot/sieve-ldap.conf;name=ldap-domain
+
+ # User-specific scripts executed before the user's personal script.
+ # E.g. a vacation script managed through a non-ManageSieve GUI.
+ sieve_before3 = /var/vmail/%d/%n/sieve-before
+
+ # User-specific scripts executed after the user's personal script.
+ # (if keep is still in effect)
+ # E.g. user-specific default mail filing rules
+ sieve_after = /var/vmail/%d/%n/sieve-after
+
+ # Global scripts executed after the user's personal script
+ # (if keep is still in effect)
+ # E.g. default mail filing rules.
+ sieve_after2 = /var/lib/dovecot/sieve/after.d/
+}
+
+IMPORTANT: The scripts specified by sieve_before and sieve_after are often
+located in global locations to which the Sieve interpreter has no write access
+to store the compiled binaries. In that case, be sure to manually pre-compile
+those scripts using the sievec tool, as explained in the README file.
+
+Sieve Interpreter - Visible Default Script
+------------------------------------------
+
+The `sieve_default=' setting specifies the location of a default script that
+is executed when the user has no active personal script. Normally, this
+default script is invisible to the user; i.e., it is not listed in ManageSieve.
+To give the user the ability to see and read the default script, it is possible
+to make it visible under a specific configurable name using the
+`sieve_default_name' setting.
+
+ManageSieve will magically list the default script under that name, even though
+it does not actually exist in the user's normal script storage location. This
+way, the ManageSieve client can see that it exists and it can retrieve its
+contents. If no normal script is active, the default is always listed as active.
+The user can replace the default with a custom script, by uploading it under the
+default script's name. If that custom script is ever deleted, the default script
+will reappear from the shadows implicitly.
+
+This way, ManageSieve clients will not need any special handling for this
+feature. If the name of the default script is equal to the name the client uses
+for the main script, it will initially see and read the default script when the
+user account is freshly created. The user can edit the script, and when the
+edited script is saved through the ManageSieve client, it will will override the
+default script. If the user ever wants to revert to the default, the user only
+needs to delete the edited script and the default will reappear.
+
+The name by which the default script will be known is configured using the
+`sieve_default_name' setting. Of course, the `sieve_default' setting needs to
+point to a valid script location as well for this to work. If the default script
+does not exist at the indicated location, it is not shown.
+
+For example:
+
+plugin {
+...
+ sieve = file:~/sieve;active=~/.dovecot.sieve
+
+ sieve_default = /var/lib/dovecot/sieve/default.sieve
+ sieve_default_name = roundcube
+}
+
+Sieve Interpreter - Extension Configuration
+-------------------------------------------
+
+- Editheader extension:
+
+ The editheader extension [RFC5293] enables sieve scripts to interact with
+ other components that consume or produce header fields by allowing the script
+ to delete and add header fields.
+
+ The editheader extension requires explicit configuration and is not enabled
+ for use by default. Refer to doc/extensions/editheader.txt for configuration
+ information.
+
+- Vacation extension:
+
+ The Sieve vacation extension [RFC5230] defines a mechanism to generate
+ automatic replies to incoming email messages.
+
+ The vacation extension is available by default, but it has its own specific
+ configuration options. Refer to doc/extensions/vacation.txt for settings
+ specific to the vacation extension.
+
+- Variables extension:
+
+ The Sieve variables extension [RFC5229] adds the concept of variables to the
+ Sieve language.
+
+ The variables extension is available by default, but it has its own specific
+ configuration options. Refer to doc/extensions/variables.txt for settings
+ specific to the variables extension.
+
+- Include extension:
+
+ The Sieve include extension (draft) permits users to include one Sieve script
+ into another.
+
+ The include extension is available by default, but it has its own specific
+ configuration options. Refer to doc/extensions/include.txt for settings
+ specific to the include extension.
+
+- Spamtest and virustest extensions:
+
+ Using the spamtest and virustest extensions (RFC 5235), the Sieve language
+ provides a uniform and standardized command interface for evaluating spam and
+ virus tests performed on the message. Users no longer need to know what headers
+ need to be checked and how the scanner's verdict is represented in the header
+ field value. They only need to know how to use the spamtest (spamtestplus) and
+ virustest extensions. This also gives GUI-based Sieve editors the means to
+ provide a portable and easy to install interface for spam and virus filter
+ configuration.
+
+ The spamtest, spamtestplus and virustest extensions require explicit
+ configuration and are not enabled for use by default. Refer to
+ doc/extensions/spamtest-virustest.txt for configuration information.
+
+- Duplicate extension:
+
+ The duplicate extension augments the Sieve filtering implementation with a
+ test that facilitates detecting and handling duplicate message deliveries,
+ e.g. as caused by mailinglists when people reply both to the mailinglist and
+ the user directly.
+
+ Refer to doc/extensions/vnd.dovecot.duplicate.txt for configuration
+ information.
+
+- Dovecot environment extension:
+
+ The vnd.dovecot.environment extension builds on the standard environment
+ extension. It adds a few extra environment items that are useful for Sieve
+ scripts used by Dovecot.
+
+ Refer to doc/extensions/vnd.dovecot.environment.txt for more information.
+
+- Extprograms plugin;
+ vnd.dovovecot.pipe, vnd.dovecot.filter, vnd.dovecot.execute extensions:
+
+ The "sieve_extprograms" plugin provides extensions to the Sieve filtering
+ language adding new action commands for invoking a predefined set of external
+ programs. Messages can be piped to or filtered through those programs and
+ string data can be input to and retrieved from those programs.
+
+ This plugin and the extensions it provides require explicit configuration and
+ are not enabled for use by default. Refer to doc/plugins/sieve_extprograms.txt
+ for more information.
+
+- Imapsieve plugins
+
+ The "sieve_imapsieve" Sieve plugin and the "imap_sieve" IMAP plugin add Sieve
+ support to IMAP.
+
+ Refer to doc/plugins/imapsieve.txt for more information.
+
+- IMAP Filter Sieve plugin
+
+ The "imap_filter_sieve" plugin adds the ability to manually invoke Sieve
+ filtering in IMAP.
+
+ Refer to doc/plugins/imap_filter_sieve.txt for more information.
+
+Sieve Interpreter - Trace Debugging
+-----------------------------------
+
+Trace debugging provides detailed insight in the operations performed by
+the Sieve script. Messages about what the Sieve script is doing are written
+to the specified directory.
+
+WARNING: On a busy server, this functionality can quickly fill up the trace
+directory with a lot of trace files. Enable this only temporarily and as
+selective as possible.
+
+The following settings apply to both the LDA Sieve plugin and the IMAPSIEVE
+plugin:
+
+ sieve_trace_dir =
+ The directory where trace files are written. Trace debugging is disabled if
+ this setting is not configured or if the directory does not exist. If the
+ path is relative or it starts with "~/" it is interpreted relative to the
+ current user's home directory.
+
+ sieve_trace_level =
+ The verbosity level of the trace messages. Trace debugging is disabled if
+ this setting is not configured. Possible values are:
+
+ "actions" - Only print executed action commands, like keep, fileinto,
+ reject and redirect.
+ "commands" - Print any executed command, excluding test commands.
+ "tests" - Print all executed commands and performed tests.
+ "matching" - Print all executed commands, performed tests and the values
+ matched in those tests.
+
+ sieve_trace_debug = no
+ Enables highly verbose debugging messages that are usually only useful for
+ developers.
+
+ sieve_trace_addresses = no
+ Enables showing byte code addresses in the trace output, rather than only
+ the source line numbers.
+
+Sieve Interpreter - Migration from CMUSieve (Dovecot v1.0/v1.1)
+---------------------------------------------------------------
+
+For the most part, migration from CMUSieve to the Pigeonhole LDA Sieve plugin is
+just a matter of changing the used plugin name from 'cmusieve' to 'sieve' in the
+mail_plugins option in the protocol lda section of the config file (as explained
+above). However, there are a few important differences:
+
+ * The imapflags extension is now called imap4flags. The CMUSieve implementation
+ is based on an old draft specification that is not completely compatible.
+ Particularly, the mark and unmark commands were removed from the new
+ specification. For backwards compatibility, support for the old imapflags
+ extension can be enabled using the sieve_extensions setting (as explained
+ above). This is disabled by default.
+
+ * The notify extension is now called enotify. The CMUSieve implementation is
+ based on an old draft specification that is not completely compatible.
+ Particularly, the denotify command and $text$ substitutions were removed from
+ the new specification. For backwards compatibility, support for the old
+ imapflags extension can be enabled using the sieve_extensions setting (as
+ explained above). This is disabled by default.
+
+ * The include extension now requires your script file names to end with
+ ".sieve". This means that ` include :personal "myscript"; ' won't work unless
+ you rename "myscript" to "myscript.sieve"
+
+Sieve Interpreter - Migration from Dovecot Sieve v0.1.x (Dovecot v1.2)
+----------------------------------------------------------------------
+
+ * Dovecot v2.0 adds support for LMTP. Much like the Dovecot LDA, it can make
+ use of the Pigeonhole Sieve plugin. Since the LMTP service has its own
+ prototocol lmtp section in the config file, you need to add the Sieve plugin
+ to the mail_plugins setting there too when you decide to use LMTP.
+ * The 'sieve_subaddress_sep' setting for the Sieve subaddress extension is now
+ known as 'recipient_delimiter'. Although sieve_subaddress_sep is still
+ recognized for backwards compatibility, it is recommended to update the
+ setting to the new name, since the LMTP service also uses the
+ recipient_delimiter setting.
+
+ManageSieve Service - Basic Configuration
+-----------------------------------------
+
+IMPORTANT:
+
+ If you have used the LDA Sieve plugin without ManageSieve before and you have
+ .dovecot.sieve files in user directories, you are advised to make a backup
+ before installing ManageSieve. Although the ManageSieve service takes care to
+ move these files to the Sieve directory before it is substituted with a
+ symbolic link, this is not a very well tested operation, meaning that there is
+ a slim possibility that existing Sieve scripts get lost.
+
+Just like all other binaries that Dovecot uses, the managesieve and
+managesieve-login binaries are installed during make install.
+
+There are two things that have be done to activate the ManageSieve support in
+Dovecot:
+
+ * The first step is to add `sieve' to the protocols= configuration line in
+ your dovecot.conf.
+
+ * The next step is specifying an additional service type for the ManageSieve
+ service. This could be done in Dovecot's conf.d/master.conf or you can use
+ the 20-managesieve.conf file from the doc/example-config/conf.d directory of
+ this package.
+
+ For example:
+
+ service managesieve-login {
+ inet_listener sieve {
+ port = 4190
+ }
+ }
+
+Because the implementation of the ManageSieve daemon is largely based on the
+original IMAP implementation, it is very similar in terms of configuration. The
+following settings can be configured in the 'protocol sieve' section:
+
+ managesieve_max_line_length = 65536
+ The maximum ManageSieve command line length in bytes. This setting is
+ directly borrowed from IMAP. But, since long command lines are very unlikely
+ with ManageSieve, changing this will not be very useful.
+
+ managesieve_logout_format = bytes=%i/%o
+ Specifies the string pattern used to compose the logout message of an
+ authenticated session. The following substitutions are available:
+
+ %i - total number of bytes read from client
+ %o - total number of bytes sent to client
+
+ managesieve_implementation_string = Dovecot Pigeonhole
+ To fool ManageSieve clients that are focused on CMU's timesieved, you can
+ specify the IMPLEMENTATION capability that the Dovecot reports to clients
+ (e.g. 'Cyrus timsieved v2.2.13').
+
+ managesieve_max_compile_errors = 5
+ The maximum number of compile errors that are returned to the client upon
+ script upload or script verification.
+
+ managesieve_sieve_capability =
+ managesieve_notify_capability =
+ Respectively the SIEVE and NOTIFY capabilities reported by the ManageSieve
+ service before authentication. If left unassigned these will be assigned
+ dynamically according to what the Sieve interpreter supports by default
+ (after login this may differ depending on the authenticated user).
+
+Additionally, the ManageSieve service uses the following settings from the
+plugin section of the config file. These settings are the same ones used by
+the LDA Sieve plugin.
+
+ sieve = file:~/sieve;active=~/.dovecot.sieve
+ This specifies the location where the scripts that are uploaded through
+ ManageSieve are stored. During delivery, the LDA Sieve plugin uses this
+ location setting to find the active script for Sieve filtering. The Sieve
+ "include" extension uses this location for retrieving ":personal" scripts.
+ If the location type does not allow uploading scripts, the ManageSieve
+ service cannot be used. Currently, only the 'file' location type supports
+ ManageSieve.
+
+ For the 'file' location type:
+
+ * The location is the path to the storage directory for all the user's
+ personal Sieve scripts. Scripts are stored as separate files with
+ extension .sieve. All other files are ignored when scripts are listed
+ by a ManageSieve client. The storage directory is always generated
+ automatically if it does not exist (as far as the system permits the
+ user to do so; no root privileges are used). This is similar to the
+ behavior of the mail daemons regarding the mail_location configuration.
+
+ * ManageSieve maintains a symbolic link pointing to the currently active
+ script (the script executed at delivery). The location of this symbolic
+ link can be configured using the ;active=<path> option. If a regular
+ file already exists at the location specified by in the ;active=<path>
+ location option, it is moved to the storage directory before the
+ symbolic link is installed. It is renamed to dovecot.orig.sieve and
+ therefore listed as dovecot.orig by a ManageSieve client.
+
+ NOTE: It is not wise to place this active symbolic link inside your
+ mail store, as it may be mistaken for a mail folder. Inside a
+ maildir for instance, the default .dovecot.sieve would show up
+ as phantom folder /dovecot/sieve in your IMAP tree.
+
+ For Pigeonhole versions before v0.3.1, this setting can only be a
+ filesystem path pointing to a script file, or - when ManageSieve is used -
+ it is the location of the symbolic link pointing to the active script in
+ the storage directory. That storage directory is then configured using the
+ deprecated `sieve_dir' setting.
+
+The following provides an example configuration for Sieve and ManageSieve. Only
+sections and settings relevant to ManageSieve are shown. Refer to
+20-managesieve.conf in the doc/example-config/conf.d directory for a full
+example with comments, but don't forget to configure Sieve and add sieve to the
+'protocols = ...' setting if you use it.
+
+# *** conf.d/20-managesieve.conf ***
+
+service managesieve-login {
+ inet_listener sieve {
+ # Bind the daemon only to the specified address(es)
+ # (default: *, ::)
+ address = 127.0.0.1
+ # Specify an alternative port the daemon must listen on
+ # (default: 4190)
+ port = 2000
+ }
+}
+
+protocol sieve {
+ managesieve_max_compile_errors = 10
+}
+
+# *** conf.d/90-sieve.conf ***
+
+plugin {
+ sieve=file:~/sieve;active=~/.dovecot.sieve
+}
+
+# *** dovecot.conf ***
+
+# .... (other config items)
+
+# Start imap, pop3, lmtp and managesieve services
+protocols = imap pop3 lmtp sieve
+
+# .... (other config items)
+
+ManageSieve Service - Quota Support
+-----------------------------------
+
+By default, users can manage an unlimited number of Sieve scripts on the server
+through ManageSieve. However, ManageSieve can be configured to enforce limits on
+the number of personal Sieve scripts per user and/or the amount of disk storage
+used by these scripts. The maximum size of individual uploaded scripts is
+dictated by the configuration of the Sieve plugin. The limits are configured in
+the plugin section of the Dovecot configuration as follows:
+
+ sieve_max_script_size = 1M
+ The maximum size of a Sieve script. If set to 0, no limit on the script size
+ is enforced.
+
+ sieve_quota_max_scripts = 0
+ The maximum number of personal Sieve scripts a single user can have. If set
+ to 0, no limit on the number of scripts is enforced.
+
+ sieve_quota_max_storage = 0
+ The maximum amount of disk storage a single user's scripts may occupy. If set
+ to 0, no limit on the used amount of disk storage is enforced.
+
+ManageSieve Service - Proxying
+------------------------------
+
+Like Dovecot's imapd, the ManageSieve login daemon supports proxying to multiple
+backend servers. Although the underlying code is copied from the imapd sources
+for the most part, it has some ManageSieve-specifics that have not seen much
+testing.
+
+The proxy configuration wiki page for POP3 and IMAP should apply to ManageSieve
+as well:
+
+http://wiki.dovecot.org/PasswordDatabase/ExtraFields/Proxy
+
+ManageSieve Service - Migration
+-------------------------------
+
+The following has changed since the ManageSieve releases for Dovecot v1.x:
+
+ * For Dovecot v1.0 and v1.1, the sieve_dir setting used by ManageSieve was
+ called sieve_storage. Also, the sieve and sieve_storage settings were located
+ inside the 'protocol managesieve' section of the configuration. As per
+ Dovecot v1.2, these settings are shared with the Sieve plugin and located in
+ the 'plugin' section of the configuration. Make sure you have updated the
+ name of the sieve_dir setting and the location of both these settings if you
+ are upgrading from ManageSieve for Dovecot v1.0/v1.1.
+ * Pigeonhole ManageSieve does not use the mail_location configuration as a
+ fall-back anymore to determine a default location for storing Sieve scripts.
+ It always uses the sieve_dir setting, with default value ~/sieve.
+ * The Pigeonhole ManageSieve service now binds to TCP port 4190 by default due
+ to the IANA port assignment for the ManageSieve service. When upgrading from
+ v1.x, this should be taken into account. For a smooth transition, the service
+ can be configured manually to listen on both port 2000 and port 4190, as
+ demonstrated in the example above.
+ * The Dovecot configuration now calls the ManageSieve protocol 'sieve' instead
+ of 'managesieve' because it is registered as such with IANA. The binaries and
+ the services are still called 'managesieve' and 'managesieve-login'. The
+ example above demonstrates how this affects the configuration.
+
+Test Suite
+==========
+
+This package includes a test suite to verify the basic processing of the Sieve
+interpreter on your particular platform. Note that the test suite is not
+available when this package is compiled against the Dovecot headers only. The
+test suite executes a list of test cases and halts when one of them fails. If it
+executes all test cases successfully, the test suite finishes. You can execute
+the basic test suite using `make test`, which does not include the plugins. You
+can test the plugins using `make test-plugins`.
+
+A failing test case is always a bug and a report is greatly appreciated.
+
+
diff --git a/pigeonhole/Makefile.am b/pigeonhole/Makefile.am
new file mode 100644
index 0000000..1dfb0e6
--- /dev/null
+++ b/pigeonhole/Makefile.am
@@ -0,0 +1,227 @@
+aclocaldir = $(datadir)/aclocal
+
+if BUILD_DOCS
+DOCS = doc
+endif
+
+SUBDIRS = \
+ . \
+ src \
+ $(DOCS)
+
+ACLOCAL_AMFLAGS = -I m4
+
+EXTRA_DIST = \
+ tests \
+ examples \
+ COPYING.LGPL \
+ ChangeLog \
+ update-version.sh
+
+dist-hook:
+ rm -rf `find $(distdir)/tests -type f -name '*.svbin'`
+
+pkginc_libdir=$(dovecot_pkgincludedir)/sieve
+dist_pkginc_lib_HEADERS = \
+ pigeonhole-version.h
+nodist_pkginc_lib_HEADERS = \
+ pigeonhole-config.h
+
+ChangeLog:
+ git log --name-status \
+ --pretty="format:%ai %aN <%aE> (%h)%n%n%w(80,4,4)%s%n%n%b" > ChangeLog \
+ || rm -f ChangeLog
+
+dist_aclocal_DATA = dovecot-pigeonhole.m4
+
+pigeonhole-version.h: noop
+ $(SHELL) $(top_srcdir)/update-version.sh $(top_srcdir) $(top_builddir)
+
+noop:
+
+DISTCLEANFILES = \
+ $(top_builddir)/pigeonhole-version.h \
+ $(top_builddir)/run-test.sh
+
+# Testsuite tests (FIXME: ugly)
+
+TESTSUITE_BIN = $(top_builddir)/src/testsuite/testsuite $(TESTSUITE_OPTIONS)
+
+TEST_BIN = $(RUN_TEST) $(TESTSUITE_BIN)
+
+if BUILD_UNFINISHED
+test_unfinished =
+else
+test_unfinished =
+endif
+
+test_cases = \
+ tests/testsuite.svtest \
+ tests/control-if.svtest \
+ tests/control-stop.svtest \
+ tests/test-allof.svtest \
+ tests/test-anyof.svtest \
+ tests/test-exists.svtest \
+ tests/test-header.svtest \
+ tests/test-address.svtest \
+ tests/test-size.svtest \
+ tests/compile/compile.svtest \
+ tests/compile/errors.svtest \
+ tests/compile/warnings.svtest \
+ tests/compile/recover.svtest \
+ tests/execute/errors.svtest \
+ tests/execute/errors-cpu-limit.svtest \
+ tests/execute/actions.svtest \
+ tests/execute/smtp.svtest \
+ tests/execute/mailstore.svtest \
+ tests/execute/address-normalize.svtest \
+ tests/execute/examples.svtest \
+ tests/lexer.svtest \
+ tests/comparators/i-octet.svtest \
+ tests/comparators/i-ascii-casemap.svtest \
+ tests/match-types/is.svtest \
+ tests/match-types/contains.svtest \
+ tests/match-types/matches.svtest \
+ tests/multiscript/basic.svtest \
+ tests/multiscript/conflicts.svtest \
+ tests/extensions/encoded-character.svtest \
+ tests/extensions/envelope.svtest \
+ tests/extensions/variables/basic.svtest \
+ tests/extensions/variables/match.svtest \
+ tests/extensions/variables/modifiers.svtest \
+ tests/extensions/variables/quoting.svtest \
+ tests/extensions/variables/string.svtest \
+ tests/extensions/variables/errors.svtest \
+ tests/extensions/variables/regex.svtest \
+ tests/extensions/include/errors.svtest \
+ tests/extensions/include/variables.svtest \
+ tests/extensions/include/once.svtest \
+ tests/extensions/include/twice.svtest \
+ tests/extensions/include/optional.svtest \
+ tests/extensions/include/rfc.svtest \
+ tests/extensions/include/execute.svtest \
+ tests/extensions/imap4flags/basic.svtest \
+ tests/extensions/imap4flags/hasflag.svtest \
+ tests/extensions/imap4flags/execute.svtest \
+ tests/extensions/imap4flags/multiscript.svtest \
+ tests/extensions/imap4flags/flagstring.svtest \
+ tests/extensions/imap4flags/flagstore.svtest \
+ tests/extensions/body/basic.svtest \
+ tests/extensions/body/errors.svtest \
+ tests/extensions/body/raw.svtest \
+ tests/extensions/body/content.svtest \
+ tests/extensions/body/text.svtest \
+ tests/extensions/body/match-values.svtest \
+ tests/extensions/regex/basic.svtest \
+ tests/extensions/regex/match-values.svtest \
+ tests/extensions/regex/errors.svtest \
+ tests/extensions/reject/execute.svtest \
+ tests/extensions/reject/smtp.svtest \
+ tests/extensions/relational/basic.svtest \
+ tests/extensions/relational/rfc.svtest \
+ tests/extensions/relational/errors.svtest \
+ tests/extensions/relational/comparators.svtest \
+ tests/extensions/subaddress/basic.svtest \
+ tests/extensions/subaddress/rfc.svtest \
+ tests/extensions/subaddress/config.svtest \
+ tests/extensions/vacation/errors.svtest \
+ tests/extensions/vacation/execute.svtest \
+ tests/extensions/vacation/message.svtest \
+ tests/extensions/vacation/smtp.svtest \
+ tests/extensions/vacation/utf-8.svtest \
+ tests/extensions/vacation/reply.svtest \
+ tests/extensions/enotify/basic.svtest \
+ tests/extensions/enotify/encodeurl.svtest \
+ tests/extensions/enotify/valid_notify_method.svtest \
+ tests/extensions/enotify/notify_method_capability.svtest \
+ tests/extensions/enotify/errors.svtest \
+ tests/extensions/enotify/execute.svtest \
+ tests/extensions/enotify/mailto.svtest \
+ tests/extensions/environment/basic.svtest \
+ tests/extensions/environment/rfc.svtest \
+ tests/extensions/mailbox/errors.svtest \
+ tests/extensions/mailbox/execute.svtest \
+ tests/extensions/date/basic.svtest \
+ tests/extensions/date/date-parts.svtest \
+ tests/extensions/date/zones.svtest \
+ tests/extensions/index/basic.svtest \
+ tests/extensions/index/errors.svtest \
+ tests/extensions/spamvirustest/spamtest.svtest \
+ tests/extensions/spamvirustest/virustest.svtest \
+ tests/extensions/spamvirustest/spamtestplus.svtest \
+ tests/extensions/spamvirustest/errors.svtest \
+ tests/extensions/ihave/execute.svtest \
+ tests/extensions/ihave/errors.svtest \
+ tests/extensions/ihave/restrictions.svtest \
+ tests/extensions/editheader/addheader.svtest \
+ tests/extensions/editheader/deleteheader.svtest \
+ tests/extensions/editheader/alternating.svtest \
+ tests/extensions/editheader/utf8.svtest \
+ tests/extensions/editheader/protected.svtest \
+ tests/extensions/editheader/errors.svtest \
+ tests/extensions/editheader/execute.svtest \
+ tests/extensions/duplicate/errors.svtest \
+ tests/extensions/duplicate/execute.svtest \
+ tests/extensions/duplicate/execute-vnd.svtest \
+ tests/extensions/metadata/execute.svtest \
+ tests/extensions/metadata/errors.svtest \
+ tests/extensions/mime/errors.svtest \
+ tests/extensions/mime/header.svtest \
+ tests/extensions/mime/exists.svtest \
+ tests/extensions/mime/address.svtest \
+ tests/extensions/mime/execute.svtest \
+ tests/extensions/mime/content-header.svtest \
+ tests/extensions/mime/foreverypart.svtest \
+ tests/extensions/mime/extracttext.svtest \
+ tests/extensions/mime/calendar-example.svtest \
+ tests/extensions/special-use/errors.svtest \
+ tests/extensions/special-use/execute.svtest \
+ tests/extensions/vnd.dovecot/debug/execute.svtest \
+ tests/extensions/vnd.dovecot/environment/basic.svtest \
+ tests/extensions/vnd.dovecot/environment/variables.svtest \
+ tests/extensions/vnd.dovecot/report/errors.svtest \
+ tests/extensions/vnd.dovecot/report/execute.svtest \
+ tests/deprecated/notify/basic.svtest \
+ tests/deprecated/notify/mailto.svtest \
+ tests/deprecated/notify/errors.svtest \
+ tests/deprecated/notify/execute.svtest \
+ tests/deprecated/notify/denotify.svtest \
+ tests/deprecated/imapflags/execute.svtest \
+ tests/deprecated/imapflags/errors.svtest \
+ $(test_unfinished)
+
+$(test_cases):
+ @$(TEST_BIN) $(top_srcdir)/$@
+
+failure_test_cases = \
+ tests/failures/fuzz1.svtest \
+ tests/failures/fuzz2.svtest \
+ tests/failures/fuzz3.svtest \
+ tests/failures/mailbox-bad-utf8.svtest
+
+$(failure_test_cases):
+ @$(TEST_BIN) -F $(top_srcdir)/$@
+
+TEST_EXTPROGRAMS_BIN = NOCHILDREN=yes $(TEST_BIN) \
+ -P src/plugins/sieve-extprograms/.libs/sieve_extprograms
+
+extprograms_test_cases = \
+ tests/plugins/extprograms/errors.svtest \
+ tests/plugins/extprograms/pipe/command.svtest \
+ tests/plugins/extprograms/pipe/errors.svtest \
+ tests/plugins/extprograms/pipe/execute.svtest \
+ tests/plugins/extprograms/filter/command.svtest \
+ tests/plugins/extprograms/filter/errors.svtest \
+ tests/plugins/extprograms/filter/execute.svtest \
+ tests/plugins/extprograms/execute/command.svtest \
+ tests/plugins/extprograms/execute/errors.svtest \
+ tests/plugins/extprograms/execute/execute.svtest
+
+$(extprograms_test_cases):
+ @$(TEST_EXTPROGRAMS_BIN) $(top_srcdir)/$@
+
+.PHONY: test test-plugins $(test_cases) $(failure_test_cases) $(extprograms_test_cases)
+test: all-am $(test_cases) $(failure_test_cases)
+test-plugins: all-am $(extprograms_test_cases)
+
+check: check-am test
diff --git a/pigeonhole/Makefile.in b/pigeonhole/Makefile.in
new file mode 100644
index 0000000..ce81b2d
--- /dev/null
+++ b/pigeonhole/Makefile.in
@@ -0,0 +1,1233 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+ $(am__configure_deps) $(dist_aclocal_DATA) \
+ $(dist_pkginc_lib_HEADERS) $(am__DIST_COMMON)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = dummy-config.h pigeonhole-config.h
+CONFIG_CLEAN_FILES = stamp.h
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(aclocaldir)" \
+ "$(DESTDIR)$(pkginc_libdir)" "$(DESTDIR)$(pkginc_libdir)"
+DATA = $(dist_aclocal_DATA)
+HEADERS = $(dist_pkginc_lib_HEADERS) $(nodist_pkginc_lib_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ cscope distdir distdir-am dist dist-all distcheck
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \
+ dummy-config.h.in pigeonhole-config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+DIST_SUBDIRS = . src doc
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/dummy-config.h.in \
+ $(srcdir)/pigeonhole-config.h.in $(srcdir)/stamp.h.in AUTHORS \
+ COPYING ChangeLog INSTALL NEWS README TODO compile \
+ config.guess config.rpath config.sub install-sh ltmain.sh \
+ missing
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ if test -d "$(distdir)"; then \
+ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -rf "$(distdir)" \
+ || { sleep 5 && rm -rf "$(distdir)"; }; \
+ else :; fi
+am__post_remove_distdir = $(am__remove_distdir)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+DIST_TARGETS = dist-gzip
+# Exists only to be overridden by the user if desired.
+AM_DISTCHECK_DVI_TARGET = dvi
+distuninstallcheck_listfiles = find . -type f -print
+am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
+ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+aclocaldir = $(datadir)/aclocal
+@BUILD_DOCS_TRUE@DOCS = doc
+SUBDIRS = \
+ . \
+ src \
+ $(DOCS)
+
+ACLOCAL_AMFLAGS = -I m4
+EXTRA_DIST = \
+ tests \
+ examples \
+ COPYING.LGPL \
+ ChangeLog \
+ update-version.sh
+
+pkginc_libdir = $(dovecot_pkgincludedir)/sieve
+dist_pkginc_lib_HEADERS = \
+ pigeonhole-version.h
+
+nodist_pkginc_lib_HEADERS = \
+ pigeonhole-config.h
+
+dist_aclocal_DATA = dovecot-pigeonhole.m4
+DISTCLEANFILES = \
+ $(top_builddir)/pigeonhole-version.h \
+ $(top_builddir)/run-test.sh
+
+
+# Testsuite tests (FIXME: ugly)
+TESTSUITE_BIN = $(top_builddir)/src/testsuite/testsuite $(TESTSUITE_OPTIONS)
+TEST_BIN = $(RUN_TEST) $(TESTSUITE_BIN)
+@BUILD_UNFINISHED_FALSE@test_unfinished =
+@BUILD_UNFINISHED_TRUE@test_unfinished =
+test_cases = \
+ tests/testsuite.svtest \
+ tests/control-if.svtest \
+ tests/control-stop.svtest \
+ tests/test-allof.svtest \
+ tests/test-anyof.svtest \
+ tests/test-exists.svtest \
+ tests/test-header.svtest \
+ tests/test-address.svtest \
+ tests/test-size.svtest \
+ tests/compile/compile.svtest \
+ tests/compile/errors.svtest \
+ tests/compile/warnings.svtest \
+ tests/compile/recover.svtest \
+ tests/execute/errors.svtest \
+ tests/execute/errors-cpu-limit.svtest \
+ tests/execute/actions.svtest \
+ tests/execute/smtp.svtest \
+ tests/execute/mailstore.svtest \
+ tests/execute/address-normalize.svtest \
+ tests/execute/examples.svtest \
+ tests/lexer.svtest \
+ tests/comparators/i-octet.svtest \
+ tests/comparators/i-ascii-casemap.svtest \
+ tests/match-types/is.svtest \
+ tests/match-types/contains.svtest \
+ tests/match-types/matches.svtest \
+ tests/multiscript/basic.svtest \
+ tests/multiscript/conflicts.svtest \
+ tests/extensions/encoded-character.svtest \
+ tests/extensions/envelope.svtest \
+ tests/extensions/variables/basic.svtest \
+ tests/extensions/variables/match.svtest \
+ tests/extensions/variables/modifiers.svtest \
+ tests/extensions/variables/quoting.svtest \
+ tests/extensions/variables/string.svtest \
+ tests/extensions/variables/errors.svtest \
+ tests/extensions/variables/regex.svtest \
+ tests/extensions/include/errors.svtest \
+ tests/extensions/include/variables.svtest \
+ tests/extensions/include/once.svtest \
+ tests/extensions/include/twice.svtest \
+ tests/extensions/include/optional.svtest \
+ tests/extensions/include/rfc.svtest \
+ tests/extensions/include/execute.svtest \
+ tests/extensions/imap4flags/basic.svtest \
+ tests/extensions/imap4flags/hasflag.svtest \
+ tests/extensions/imap4flags/execute.svtest \
+ tests/extensions/imap4flags/multiscript.svtest \
+ tests/extensions/imap4flags/flagstring.svtest \
+ tests/extensions/imap4flags/flagstore.svtest \
+ tests/extensions/body/basic.svtest \
+ tests/extensions/body/errors.svtest \
+ tests/extensions/body/raw.svtest \
+ tests/extensions/body/content.svtest \
+ tests/extensions/body/text.svtest \
+ tests/extensions/body/match-values.svtest \
+ tests/extensions/regex/basic.svtest \
+ tests/extensions/regex/match-values.svtest \
+ tests/extensions/regex/errors.svtest \
+ tests/extensions/reject/execute.svtest \
+ tests/extensions/reject/smtp.svtest \
+ tests/extensions/relational/basic.svtest \
+ tests/extensions/relational/rfc.svtest \
+ tests/extensions/relational/errors.svtest \
+ tests/extensions/relational/comparators.svtest \
+ tests/extensions/subaddress/basic.svtest \
+ tests/extensions/subaddress/rfc.svtest \
+ tests/extensions/subaddress/config.svtest \
+ tests/extensions/vacation/errors.svtest \
+ tests/extensions/vacation/execute.svtest \
+ tests/extensions/vacation/message.svtest \
+ tests/extensions/vacation/smtp.svtest \
+ tests/extensions/vacation/utf-8.svtest \
+ tests/extensions/vacation/reply.svtest \
+ tests/extensions/enotify/basic.svtest \
+ tests/extensions/enotify/encodeurl.svtest \
+ tests/extensions/enotify/valid_notify_method.svtest \
+ tests/extensions/enotify/notify_method_capability.svtest \
+ tests/extensions/enotify/errors.svtest \
+ tests/extensions/enotify/execute.svtest \
+ tests/extensions/enotify/mailto.svtest \
+ tests/extensions/environment/basic.svtest \
+ tests/extensions/environment/rfc.svtest \
+ tests/extensions/mailbox/errors.svtest \
+ tests/extensions/mailbox/execute.svtest \
+ tests/extensions/date/basic.svtest \
+ tests/extensions/date/date-parts.svtest \
+ tests/extensions/date/zones.svtest \
+ tests/extensions/index/basic.svtest \
+ tests/extensions/index/errors.svtest \
+ tests/extensions/spamvirustest/spamtest.svtest \
+ tests/extensions/spamvirustest/virustest.svtest \
+ tests/extensions/spamvirustest/spamtestplus.svtest \
+ tests/extensions/spamvirustest/errors.svtest \
+ tests/extensions/ihave/execute.svtest \
+ tests/extensions/ihave/errors.svtest \
+ tests/extensions/ihave/restrictions.svtest \
+ tests/extensions/editheader/addheader.svtest \
+ tests/extensions/editheader/deleteheader.svtest \
+ tests/extensions/editheader/alternating.svtest \
+ tests/extensions/editheader/utf8.svtest \
+ tests/extensions/editheader/protected.svtest \
+ tests/extensions/editheader/errors.svtest \
+ tests/extensions/editheader/execute.svtest \
+ tests/extensions/duplicate/errors.svtest \
+ tests/extensions/duplicate/execute.svtest \
+ tests/extensions/duplicate/execute-vnd.svtest \
+ tests/extensions/metadata/execute.svtest \
+ tests/extensions/metadata/errors.svtest \
+ tests/extensions/mime/errors.svtest \
+ tests/extensions/mime/header.svtest \
+ tests/extensions/mime/exists.svtest \
+ tests/extensions/mime/address.svtest \
+ tests/extensions/mime/execute.svtest \
+ tests/extensions/mime/content-header.svtest \
+ tests/extensions/mime/foreverypart.svtest \
+ tests/extensions/mime/extracttext.svtest \
+ tests/extensions/mime/calendar-example.svtest \
+ tests/extensions/special-use/errors.svtest \
+ tests/extensions/special-use/execute.svtest \
+ tests/extensions/vnd.dovecot/debug/execute.svtest \
+ tests/extensions/vnd.dovecot/environment/basic.svtest \
+ tests/extensions/vnd.dovecot/environment/variables.svtest \
+ tests/extensions/vnd.dovecot/report/errors.svtest \
+ tests/extensions/vnd.dovecot/report/execute.svtest \
+ tests/deprecated/notify/basic.svtest \
+ tests/deprecated/notify/mailto.svtest \
+ tests/deprecated/notify/errors.svtest \
+ tests/deprecated/notify/execute.svtest \
+ tests/deprecated/notify/denotify.svtest \
+ tests/deprecated/imapflags/execute.svtest \
+ tests/deprecated/imapflags/errors.svtest \
+ $(test_unfinished)
+
+failure_test_cases = \
+ tests/failures/fuzz1.svtest \
+ tests/failures/fuzz2.svtest \
+ tests/failures/fuzz3.svtest \
+ tests/failures/mailbox-bad-utf8.svtest
+
+TEST_EXTPROGRAMS_BIN = NOCHILDREN=yes $(TEST_BIN) \
+ -P src/plugins/sieve-extprograms/.libs/sieve_extprograms
+
+extprograms_test_cases = \
+ tests/plugins/extprograms/errors.svtest \
+ tests/plugins/extprograms/pipe/command.svtest \
+ tests/plugins/extprograms/pipe/errors.svtest \
+ tests/plugins/extprograms/pipe/execute.svtest \
+ tests/plugins/extprograms/filter/command.svtest \
+ tests/plugins/extprograms/filter/errors.svtest \
+ tests/plugins/extprograms/filter/execute.svtest \
+ tests/plugins/extprograms/execute/command.svtest \
+ tests/plugins/extprograms/execute/errors.svtest \
+ tests/plugins/extprograms/execute/execute.svtest
+
+all: dummy-config.h pigeonhole-config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+am--refresh: Makefile
+ @:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ $(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+dummy-config.h: stamp-h1
+ @test -f $@ || rm -f stamp-h1
+ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/dummy-config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status dummy-config.h
+$(srcdir)/dummy-config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ rm -f stamp-h1
+ touch $@
+
+pigeonhole-config.h: stamp-h2
+ @test -f $@ || rm -f stamp-h2
+ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h2
+
+stamp-h2: $(srcdir)/pigeonhole-config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h2
+ cd $(top_builddir) && $(SHELL) ./config.status pigeonhole-config.h
+
+distclean-hdr:
+ -rm -f dummy-config.h stamp-h1 pigeonhole-config.h stamp-h2
+stamp.h: $(top_builddir)/config.status $(srcdir)/stamp.h.in
+ cd $(top_builddir) && $(SHELL) ./config.status $@
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool config.lt
+install-dist_aclocalDATA: $(dist_aclocal_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_aclocal_DATA)'; test -n "$(aclocaldir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(aclocaldir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(aclocaldir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(aclocaldir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(aclocaldir)" || exit $$?; \
+ done
+
+uninstall-dist_aclocalDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_aclocal_DATA)'; test -n "$(aclocaldir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(aclocaldir)'; $(am__uninstall_files_from_dir)
+install-dist_pkginc_libHEADERS: $(dist_pkginc_lib_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
+ done
+
+uninstall-dist_pkginc_libHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
+install-nodist_pkginc_libHEADERS: $(nodist_pkginc_lib_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(nodist_pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
+ done
+
+uninstall-nodist_pkginc_libHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(nodist_pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+ test ! -s cscope.files \
+ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+ -rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+ -rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ $(am__remove_distdir)
+ test -d "$(distdir)" || mkdir "$(distdir)"
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$(top_distdir)" distdir="$(distdir)" \
+ dist-hook
+ -test -n "$(am__skip_mode_fix)" \
+ || find "$(distdir)" -type d ! -perm -755 \
+ -exec chmod u+rwx,go+rx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
+ $(am__post_remove_distdir)
+
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+ $(am__post_remove_distdir)
+
+dist-lzip: distdir
+ tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
+ $(am__post_remove_distdir)
+
+dist-xz: distdir
+ tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+ $(am__post_remove_distdir)
+
+dist-zstd: distdir
+ tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst
+ $(am__post_remove_distdir)
+
+dist-tarZ: distdir
+ @echo WARNING: "Support for distribution archives compressed with" \
+ "legacy program 'compress' is deprecated." >&2
+ @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__post_remove_distdir)
+
+dist-shar: distdir
+ @echo WARNING: "Support for shar distribution archives is" \
+ "deprecated." >&2
+ @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+ shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
+ $(am__post_remove_distdir)
+
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__post_remove_distdir)
+
+dist dist-all:
+ $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
+ $(am__post_remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.lz*) \
+ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
+ *.tar.xz*) \
+ xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ *.tar.zst*) \
+ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\
+ esac
+ chmod -R a-w $(distdir)
+ chmod u+w $(distdir)
+ mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
+ chmod a-w $(distdir)
+ test -d $(distdir)/_build || exit 0; \
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && am__cwd=`pwd` \
+ && $(am__cd) $(distdir)/_build/sub \
+ && ../../configure \
+ $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ --srcdir=../.. --prefix="$$dc_install_base" \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+ && cd "$$am__cwd" \
+ || exit 1
+ $(am__post_remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+ @test -n '$(distuninstallcheck_dir)' || { \
+ echo 'ERROR: trying to run $@ with an empty' \
+ '$$(distuninstallcheck_dir)' >&2; \
+ exit 1; \
+ }; \
+ $(am__cd) '$(distuninstallcheck_dir)' || { \
+ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
+ exit 1; \
+ }; \
+ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(DATA) $(HEADERS) dummy-config.h pigeonhole-config.h
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(aclocaldir)" "$(DESTDIR)$(pkginc_libdir)" "$(DESTDIR)$(pkginc_libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-hdr \
+ distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-dist_aclocalDATA \
+ install-dist_pkginc_libHEADERS \
+ install-nodist_pkginc_libHEADERS
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-dist_aclocalDATA \
+ uninstall-dist_pkginc_libHEADERS \
+ uninstall-nodist_pkginc_libHEADERS
+
+.MAKE: $(am__recursive_targets) all install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--refresh check check-am clean clean-cscope clean-generic \
+ clean-libtool cscope cscopelist-am ctags ctags-am dist \
+ dist-all dist-bzip2 dist-gzip dist-hook dist-lzip dist-shar \
+ dist-tarZ dist-xz dist-zip dist-zstd distcheck distclean \
+ distclean-generic distclean-hdr distclean-libtool \
+ distclean-tags distcleancheck distdir distuninstallcheck dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dist_aclocalDATA \
+ install-dist_pkginc_libHEADERS install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man \
+ install-nodist_pkginc_libHEADERS install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-dist_aclocalDATA \
+ uninstall-dist_pkginc_libHEADERS \
+ uninstall-nodist_pkginc_libHEADERS
+
+.PRECIOUS: Makefile
+
+
+dist-hook:
+ rm -rf `find $(distdir)/tests -type f -name '*.svbin'`
+
+ChangeLog:
+ git log --name-status \
+ --pretty="format:%ai %aN <%aE> (%h)%n%n%w(80,4,4)%s%n%n%b" > ChangeLog \
+ || rm -f ChangeLog
+
+pigeonhole-version.h: noop
+ $(SHELL) $(top_srcdir)/update-version.sh $(top_srcdir) $(top_builddir)
+
+noop:
+
+$(test_cases):
+ @$(TEST_BIN) $(top_srcdir)/$@
+
+$(failure_test_cases):
+ @$(TEST_BIN) -F $(top_srcdir)/$@
+
+$(extprograms_test_cases):
+ @$(TEST_EXTPROGRAMS_BIN) $(top_srcdir)/$@
+
+.PHONY: test test-plugins $(test_cases) $(failure_test_cases) $(extprograms_test_cases)
+test: all-am $(test_cases) $(failure_test_cases)
+test-plugins: all-am $(extprograms_test_cases)
+
+check: check-am test
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/NEWS b/pigeonhole/NEWS
new file mode 100644
index 0000000..8c09177
--- /dev/null
+++ b/pigeonhole/NEWS
@@ -0,0 +1,1841 @@
+v0.5.21 2023-08-15 Aki Tuomi <aki.tuomi@open-xchange.com>
+
+ - sieve: Using the deleteheader action on a message with a broken/invalid
+ header can cause the Sieve interpreter to crash with an assert panic.
+ This can happen e.g. when the message is missing the empty EOH line
+ between the headers and the body of the message. Fixes:
+ Panic: file edit-mail.c: line 820 (edit_mail_headers_parse):
+ assertion failed: (body_offset > 0).
+ - sieve: Pigeonhole added an extra Message-ID header during mail
+ forwarding when the existing one was invalid. Now it adds the
+ Message-ID only if it is entirely missing. Existing Message-ID(s) are
+ left unchanged.
+
+v0.5.20 2022-12-12 Aki Tuomi <aki.tuomi@open-xchange.com>
+
+ * No changes - release done to keep version numbers synced.
+
+v0.5.19 2022-05-10 Aki Tuomi <aki.tuomi@open-xchange.com>
+
+ * No changes - release done to keep version numbers synced.
+
+v0.5.18 2022-02-03 Aki Tuomi <aki.tuomi@open-xchange.com>
+
+ - duplicate: Users without a home directory can crash with Sieve when
+ using duplicate database. v2.3.17 regression.
+ - imapsieve: When mail was expunged when processing imapsieve events, a
+ crash could occur. Fixes Panic: file mail-index-map.c:
+ line 558 (mail_index_map_lookup_seq_range): assertion failed: (first_uid > 0)
+ - managesieve-login: Proxy didn't support forwarding the forward_* passdb fields.
+ - redirect: Sieve would crash if redirect after keep-equivalent action failed.
+ - sieve: Interpreter crashes when the Sieve index extension is used with
+ index zero.
+ - vnd.dovecot.filter: Envelope sender string may become corrupted when
+ Sieve scripts are using vnd.dovecot.filter. This could end up
+ corrupting mbox's From line and return wrong envelope sender string in
+ Sieve tests.
+
+v0.5.17.1 2021-12-07 Aki Tuomi <aki.tuomi@open-xchange.com>
+
+ - managesieve: Dovecot failed to start if ssl_ca was too large.
+ - lib-sieve-tool: Binaries failed to run if ssl_ca was too large.
+
+v0.5.17 2021-10-28 Aki Tuomi <aki.tuomi@open-xchange.com>
+
+ - duplicate: The Sieve duplicate test is prone to false negatives when
+ the user receives many e-mails concurrently, meaning that duplicate
+ deliveries can still occur.
+ - fileinto: v2.3.16 regression: Sieve delivery crashes if mail is
+ delivered to non-existing and existing folder.
+ - imap-filter-sieve: v2.3.15 regression: The CPU limits on Sieve
+ execution are too easily exceeded in IMAP context (the IMAPSieve and
+ FILTER=SIEVE capabilities). Changed the default to unlimited CPU time
+ for IMAP context, since similar excessive resource usage can be caused
+ by other means as well. The CPU limits on Sieve scripts executed at
+ LDA/LMTP delivery are still enforced by default.
+ - redirect: The Sieve redirect action has protections against users
+ triggering mail loops. Unfortunately, the detection of a redirect mail
+ loop sometimes causes the message to get lost if no other Sieve action
+ is applied that delivers the message somewhere else.
+ - redirect: v2.3.16 regression: With certain Sieve scripts if redirect
+ fails due to temporary failure, the lmtp process may crash after the
+ delivery. Fixes:
+ Panic: file mail-user.c: line 229 (mail_user_deinit):
+ assertion failed: ((*user)->refcount == 1).
+
+v0.5.16 2021-08-06 Timo Sirainen <timo.sirainen@open-xchange.com>
+
+ * .dovecot.sieve.log file now includes year in the header.
+ * Change Sieve script result execution to delay definitive action
+ execution to the end of a successful Sieve script execution session.
+ This is part of an effort to solve problems with the Sieve duplicate
+ test. As a side-effect, some rare temporary-error cases yield
+ different results, in which partial failure is more likely.
+
+v0.5.15 2021-06-21 Aki Tuomi <aki.tuomi@open-xchange.com>
+
+ * CVE-2020-28200: Sieve interpreter is not protected against abusive
+ scripts that claim excessive resource usage. Fixed by limiting the
+ user CPU time per single script execution and cumulatively over
+ several script runs within a configurable timeout period. Sufficiently
+ large CPU time usage is summed in the Sieve script binary and execution
+ is blocked when the sum exceeds the limit within that time. The block
+ is lifted when the script is updated after the resource usage times out.
+ * Disconnection log messages are now more standardized across services.
+ They also always now start with "Disconnected" prefix.
+ - managesieve: Commands pipelined together with and just after the
+ authenticate command cause these commands to be executed twice.
+
+v0.5.14 2021-03-04 Aki Tuomi <aki.tuomi@open-xchange.com>
+
+ * IMAP FILTER command: cmd-filter-sieve - Do not allow NIL as
+ script name argument.
+
+v0.5.13 2021-01-04 Aki Tuomi <aki.tuomi@open-xchange.com>
+
+ - duplicate: The test was handled badly in a multiscript (sieve_before,
+ sieve_after) scenario in which an earlier script in the sequence with
+ a duplicate test succeeded, while a later script caused a runtime
+ failure. In that case, the message is recorded for duplicate tracking,
+ while the message may not actually have been delivered in the end.
+ - editheader: Sieve interpreter entered infinite loop at startup when
+ the "editheader" configuration listed an invalid header name. This
+ problem can only be triggered by the administrator.
+ - relational: The Sieve relational extension can cause a segfault at
+ compile time. This is triggered by invalid script syntax. The segfault
+ happens when this match type is the last argument of the test command.
+ This situation is not possible in a valid script; positional arguments
+ are normally present after that, which would prevent the segfault.
+ - sieve: For some Sieve commands the provided mailbox name is not
+ properly checked for UTF-8 validity, which can cause assert crashes at
+ runtime when an invalid mailbox name is encountered. This can be
+ caused by the user by writing a bad Sieve script involving the
+ affected commands ("mailboxexists", "specialuse_exists").
+ This can be triggered by the remote sender only when the user has
+ written a Sieve script that passes message content to one of the
+ affected commands.
+ - sieve: Large sequences of 8-bit octets passed to certain Sieve
+ commands that create or modify message headers that allow UTF-8 text
+ (vacation, notify and addheader) can cause the delivery or IMAP
+ process (when IMAPSieve is used) to enter a memory-consuming
+ semi-infinite loop that ends when the process exceeds its memory
+ limits. Logged in users can cause these hangs only for their own
+ processes.
+
+v0.5.11 2020-08-12 Aki Tuomi <aki.tuomi@open-xchange.com>
+
+ * managesieve: managesieve_max_line_length setting is now a "size" type
+ instead of just number of bytes. This allows using e.g. "64k" as the
+ value.
+ - lib-sieve: When folding white space is used in the Message-ID header,
+ it is not stripped away correctly before the message ID value is used,
+ causing e.g. garbled log lines at delivery.
+
+v0.5.10 2020-03-06 Aki Tuomi <aki.tuomi@open-xchange.com>
+
+ * imap_sieve_filter: Change result action logging to include IMAP UID
+ - vacation: Addresses were compared case-sensitively.
+
+v0.5.9 2019-12-04 Aki Tuomi <aki.tuomi@open-xchange.com>
+
+ + Added events for Sieve and ManageSieve, see
+ https://doc.dovecot.org/admin_manual/list_of_events/#pigeonhole
+ + Pigeonhole: Implement the Sieve "special-use" extension described in
+ RFC 8579.
+ - duplicate: Test only compared the handles which would cause
+ different values to be cached as the same duplicate test. Fix to also
+ compare the actual hashes.
+ - imap_sieve_filter: IMAP FILTER Command had various bugs in error
+ handling. Errors may have been duplicated for each email, errors
+ may have been missing entirely, command tag and ERRORS/WARNINGS
+ parameters were swapped.
+
+v0.5.8 2019-10-08 Aki Tuomi <aki.tuomi@open-xchange.com>
+
+ - Sieve may leak resources in rare cases when a redirect, vacation or
+ report action fails to send the message. This mainly applies when
+ Sieve is executed in IMAP context; i.e., for the IMAPSIEVE or
+ FILTER=SIEVE capabilities.
+
+v0.5.7.1 2019-07-23 Timo Sirainen <timo.sirainen@open-xchange.com>
+
+ - dsync: Sieve script syncing failed if mailbox attributes weren't
+ enabled.
+
+v0.5.7 2019-07-12 Aki Tuomi <aki.tuomi@open-xchange.com>
+
+ + vacation: Made the subject for the automatic response message produced
+ by the Sieve vacation action configurable. Both the default subject
+ (if the script defines none) and the subject template (e.g. used to
+ add a subject prefix) can be configured.
+ - dsync: dsync-replication does not synchronize Sieve scripts.
+ - imap_sieve_filter: Reduce FILTER=SIEVE verbosity over IMAP connection.
+ - testsuite: Pigeonhole testsuite segfaulted if it was compiled with
+ GCC 9
+
+v0.5.6 2019-04-30 Aki Tuomi <aki.tuomi@open-xchange.com>
+
+ + sieve: Redirect loop prevention is sometimes ineffective. Improve
+ existing loop detection by also recognizing the
+ X-Sieve-Redirected-From header in incoming messages and dropping
+ redirect actions when it points to the sending account. This header
+ is already added by the redirect action, so this improvement only
+ adds an additional use of this header.
+ - sieve: Prevent execution of implicit keep upon temporary failure
+ occurring at runtime.
+
+v0.5.5 2019-03-05 Stephan Bosch <stephan@rename-it.nl>
+
+ + IMAPSieve: Add new plugin/imapsieve_expunge_discarded setting which
+ causes messages discarded by an IMAPSieve script to be expunged
+ immediately, rather than only being marked as "\Deleted" (which is
+ still the default behavior).
+ - IMAPSieve: Fix panic crash occurring when a COPY command copies
+ messages from a virtual mailbox where the source messages originate
+ from more than a single real mailbox.
+ - imap4flags extension: Fix deleting all keywords. When the action
+ resulted in all keywords being removed, no changes were actually
+ applied.
+ - variables extension: Fix truncation of UTF-8 variable content. The
+ maximum size of Sieve variables was enforced by truncating the
+ variable string content bluntly at the limit, but this does not
+ consider UTF-8 code point boundaries. This resulted in broken UTF-8
+ strings. This problem also surfaced for variable modifiers, such as
+ the ":encodeurl" modifier provided by the Sieve "enotify" extension.
+ In that case, the resulting URI escaping could also be truncated
+ inappropriately.
+ - IMAPSieve, IMAP FILTER=SIEVE: Fix replacing a modified message. Sieve
+ scripts running in IMAPSIEVE or IMAP FILTER=SIEVE context that
+ modify the message, stored the message a second time, rather than
+ replacing the originally stored unmodified message.
+ - Fix segmentation fault occurring when both the sieve_extprograms
+ plugin (for the Sieve interpreter) and the imap_filter_sieve plugin
+ (for IMAP) are loaded at the same time. A symbol was defined by both
+ plugins, causing a clash when both were loaded.
+
+v0.5.4 2018-11-23 Stephan Bosch <stephan@rename-it.nl>
+
+ * Adjustments to several changes in Dovecot v2.3.4 make this Pigeonhole
+ release dependent on that Dovecot release; it will not compile against
+ older Dovecot versions. And, conversely, you need to upgrade
+ Pigeonhole when upgrading Dovecot to v2.3.4.
+ * The changes regarding the default postmaster_address in Dovecot v2.3.4
+ mainly apply to Pigeonhole. The new default should work for all
+ existing installations, thereby fixing several reported v2.3/v0.5
+ migration problems.
+ - IMAP FILTER=SIEVE capability: Fix assert crash occurring when running
+ UID FILTER on a Sieve script with errors.
+
+v0.5.3 2018-10-01 Stephan Bosch <stephan@rename-it.nl>
+
+ - Fix assertion panic occurring when managesieve service fails to open
+ INBOX while saving a Sieve script. This was caused by a lack of
+ cleanup after failure.
+ - Fix specific messages causing an assert panic with actions that
+ compose a reply (e.g. vacation). With some rather weird input from the
+ original message, the header folding algorithm (as used for composing
+ the References header for the reply) got confused, causing the panic.
+ - IMAP FILTER=SIEVE capability: Fix FILTER SIEVE SCRIPT command parsing.
+ After finishing reading the Sieve script, the command parsing
+ sometimes didn't continue with the search arguments. This is a time-
+ critical bug that likely only occurs when the Sieve script is sent in
+ the next TCP frame.
+
+v0.5.2 2018-06-29 Stephan Bosch <stephan@rename-it.nl>
+
+ + Implement plugin for the a vendor-defined IMAP capability called
+ "FILTER=SIEVE". It adds the ability to manually invoke Sieve filtering
+ in IMAP. More information can be found in
+ doc/plugins/imap_filter_sieve.txt.
+ - The Sieve addess test caused an assertion panic for invalid addresses
+ with UTF-8 codepoints in the localpart. Fixed by properly detecting
+ invalid addresses with UTF-8 codepoints in the localpart and skipping
+ these like other invalid addresses while iterating addresses for the
+ address test.
+ - Make the length of the subject header for the vacation response
+ configurable and enforce the limit in UTF-8 codepoints rather than
+ bytes. The subject header for a vacation response was statically
+ truncated to 256 bytes, which is too limited for multi-byte UTF-8
+ characters.
+ - Sieve editheader extension: Fix assertion panic occurring when it is
+ used to manipulate a message header with a very large header field.
+ - Properly abort execution of the sieve_discard script upon error.
+ Before, the LDA Sieve plugin attempted to execute the sieve_discard
+ script when an error occurs. This can lead to the message being lost.
+ - Fix the interaction between quota and the sieve_discard script. When
+ quota was used together with a sieve_discard script, the message
+ delivery did not bounce when the quota was exceeded.
+
+v0.5.1 28-03-2018 Stephan Bosch <stephan@rename-it.nl>
+
+ - Explicitly disallow UTF-8 in localpart in addresses parsed from Sieve
+ script.
+ - editheader extension: Corrected the stream position calculations
+ performed while making the modified message available as a stream.
+ Pigeonhole Sieve crashed in LMTP with an assertion panic when the
+ Sieve editheader extension was used before the message was redirected.
+ Experiments indicate that the problem occurred only with LMTP and that
+ LDA is not affected.
+ - fileinto extension: Fix assert panic occurring when fileinto is used
+ without being listed in the require line, while the copy extension is
+ listed there. This is a very old bug.
+ - imapsieve plugin: Do not assert crash or log an error for messages
+ that disappear concurrently while applying Sieve scripts. This event
+ is now logged as a debug message.
+ - Sieve extprograms plugin: Large output from "execute" command crashed
+ delivery. Fixed buffering issue in code that handles output from the
+ external program.
+
+v0.5.0.1 05-01-2018 Stephan Bosch <stephan@rename-it.nl>
+
+ - imap4flags extension: Fix binary corruption occurring when
+ setflag/addflag/removeflag flag-list is a variable.
+ - sieve-extprograms plugin: Fix segfault occurring when used in
+ IMAPSieve context.
+
+v0.5.0 24-12-2017 Stephan Bosch <stephan@rename-it.nl>
+
+ * editheader extension: The implementation of header modifications is
+ heavily updated. Although the functionality has not changed, the
+ underlying code was updated to address several static analysis
+ warnings, runtime integer arithmetic warnings (Clang), and to match
+ updates in the Dovecot stream API.
+ + variables extension: Made the maximum scope and variable size
+ configurable.
+ + subaddress: Support multiple recipient_delimiters.
+ - enotify extension: mailto method: Fixed parsing of mailto URI with
+ only a header part.
+ - enotify plugin: mailto method: Make sure the "From:" header is set to
+ a usable address and not "(null)".
+ - Fixed writing address headers to outgoing messages. Sometimes headers
+ were MIME-encoded twice, yielding invalid results.
+
+v0.4.23 20-03-2018 Stephan Bosch <stephan@rename-it.nl>
+
+ - editheader extension: Corrected the stream position calculations
+ performed while making the modified message available as a stream.
+ Pigeonhole Sieve crashed in LMTP with an assertion panic when the
+ Sieve editheader extension was used before the message was redirected.
+ Experiments indicate that the problem occurred only with LMTP and that
+ LDA is not affected.
+ - fileinto extension: Fix assert panic occurring when fileinto is used
+ without being listed in the require line, while the copy extension is
+ listed there. This is a very old bug.
+ - imapsieve plugin: Do not log an error for messages that disappear
+ concurrently while applying Sieve scripts. This is a further
+ improvement on the imapsieve fix in the previous release (which fixed
+ a panic). This event is now logged as a debug message.
+
+v0.4.22 01-03-2018 Stephan Bosch <stephan@rename-it.nl>
+
+ - Fixed filesystem path handling problem: sieve plugin could have
+ assert-crashed with specific path lengths with: "Panic: file
+ realpath.c: line 86 (path_normalize): assertion failed: (npath_pos +
+ 1 < npath + asize)".
+ - Sieve extprograms plugin: Large output from "execute" command crashed
+ delivery. Fixed buffering issue in code that handles output from the
+ external program.
+ - editheader extension: Extensively reworked the low-level
+ implementation of adding and removing headers. This solves a few
+ integer arithmetic problems reported by Clang runtime checks, but also
+ improves code structure and reliability in general.
+ - imapsieve: Fix assert crash occurring when selected messages are
+ expunged concurrently by the time Sieve filter is to be applied.
+ - imap4flags extension: Fix binary byte-code corruption occurring when
+ the setflag, addflag, or removeflag command's flag-list is a variable.
+ - enotify extension: mailto method: Fixed parsing of mailto URI with
+ only a header part.
+ - enotify extension: mailto method: Make sure "From:" header is set to a
+ usable address and not "(null)".
+ - Fixed writing address headers to outgoing messages. It sometimes
+ erroneously applied another layer of MIME header encoding.
+
+v0.4.21 12-10-2017 Stephan Bosch <stephan@rename-it.nl>
+
+ * redirect action: Always set the X-Sieve-Redirected-From header to
+ sieve_user_email if configured. Before, it would use the envelope recipient
+ instead if available, which makes no sense if the primary e-mail address is
+ available.
+ + vacation extension: Allow ignoring the envelope sender while composing the
+ "To:" header for the reply. Normally, the "To:" header is composed from
+ the address found in the "Sender", "Resent-From" or "From" headers that is
+ equal to the envelope sender. If none is then found, the bare envelope
+ sender is used. This change adds a new setting
+ "sieve_vacation_to_header_ignore_envelope". With this setting enabled, the
+ "To:" header is always composed from those headers in the source message.
+ The new setting thus allows ignoring the envelope, which is useful e.g.
+ when SRS is used.
+ + vacation extension: Compose the "To:" header from the full sender address
+ found in the first "Sender:", "From:" or "Resent-From:" header. Before, it
+ would create a "To:" header without a phrase part. The new behavior is
+ nicer, since the reply will be addressed to the sender by name if possible.
+ - LDA Sieve plugin: Fixed sequential execution of LDAP-based scripts. A
+ missing LDAP-based script could cause the script sequence to exit earlier.
+ - sieve-filter: Removed the (now) duplicate utf8 to mutf7 mailbox name
+ conversion. This caused problems with mailbox names containing UTF-8
+ characters. The Dovecot API was changed years ago, but apparently
+ sieve-filter was never updated.
+
+v0.4.20 27-08-2017 Stephan Bosch <stephan@rename-it.nl>
+
+ + Made the retention period for redirect duplicate identifiers configurable.
+ For accounts that perform many redirects, the lda-dupes database could grow
+ to impractical sizes. Changed the default retention period from 24 to 12
+ hours.
+ - sieve-filter: Fixed memory leak: forgot to clean up script binary at end of
+ execution. Normally, this would merely be an inconsequential memory leak.
+ However, when the script comes from an LDAP storage, this would cause io
+ leak warnings.
+ - managesieve-login: Fixed handling of AUTHENTICATE command. A second
+ authenticate command would be parsed wrong. This problem was caused by
+ changes in the previous release.
+ - LDA Sieve plugin: Fixed minor memory leak caused by not cleaning up the
+ sieve_discard script.
+
+v0.4.19 26-06-2017 Stephan Bosch <stephan@rename-it.nl>
+
+ * This release adjusts Pigeonhole to several changes in the Dovecot API,
+ making it depend on Dovecot v2.2.31. Previous versions of Pigeonhole will
+ produce compile warnings with the recent Dovecot releases (but still work
+ ok).
+ - Fixed bug in handling of implicit keep in some cases. Implicit side-effects,
+ such as assigned flags, were not always applied correctly. This is in
+ essence a very old bug, but it was exposed by recent changes.
+ - include extension: Fixed segfault that (sometimes) occurred when the global
+ script location was left unconfigured.
+
+v0.4.18 12-04-2017 Stephan Bosch <stephan@rename-it.nl>
+
+ + imapsieve plugin: Implemented the copy_source_after rule action. When this
+ is enabled for a mailbox rule, the specified Sieve script is executed for
+ the message in the source mailbox during a "COPY" event. This happens only
+ after the Sieve script that is executed for the corresponding message in the
+ destination mailbox finishes running successfully.
+ + imapsieve plugin: Added non-standard Sieve environment items for the source
+ and destination mailbox.
+ - multiscript: The execution of the discard script had an implicit "keep",
+ rather than an implicit "discard".
+
+v0.4.17 26-02-2017 Stephan Bosch <stephan@rename-it.nl>
+
+ - LDA Sieve plugin: Fixed handling of an early explicit keep during
+ multiscript execution. Action side-effects and the message snapshot would be
+ lost at the final stage where the implicit keep is evaluated. This could
+ result in the IMAP flags assigned to the message to be forgotten or that
+ headers modified by the "editheader" extension would revert to their
+ original state.
+ - file script storage: Amended the up-to-date time stamp comparison for
+ on-disk binaries to include nanoseconds. This will fix problems occurring
+ when both binary and script are saved within the same second. This fix is
+ ineffective on older systems that have no support for nanoseconds in stat()
+ timestamps, which should be pretty rare nowadays.
+ - file script storage: Improve saving and listing permission error to include
+ more details.
+ - imapsieve plugin: Make sure "INBOX" is upper case in static mailbox rules.
+ Otherwise, the mailbox name would never match, since matching is performed
+ case-sensitively and Dovecot only returns the upper-cased "INBOX".
+ - imapsieve plugin: Fixed assert failure occurring when used with virtual
+ mailboxes.
+ - doveadm sieve plugin: Fixed crash when setting Sieve script via attribute's
+ string value.
+
+v0.4.16 30-10-2016 Stephan Bosch <stephan@rename-it.nl>
+
+ * Part of the Sieve extprograms implementation was moved to Dovecot, which
+ means that this release depends on Dovecot v2.2.26+.
+ * ManageSieve: The PUTSCRIPT command now allows uploading empty Sieve scripts.
+ There was really no good reason to disallow doing that.
+ + Sieve vnd.dovecot.report extension:
+ + Added a Dovecot-Reporting-User field to the report body, which contains
+ the e-mail address of the user sending the report.
+ + Added support for configuring the "From:" address used in the report.
+ + LDA sieve plugin: Implemented support for a "discard script" that is run
+ when the message is going to be discarded. This allows doing something other
+ than throwing the message away for good.
+ + Sieve vnd.dovecot.environment extension: Added vnd.dovecot.config.*
+ environment items. These environment items map to sieve_env_* settings from
+ the plugin {} section in the configuration. Such values can of course also
+ be returned from userdb.
+ + Sieve vacation extension: Use the Microsoft X-Auto-Response-Suppress header
+ to prevent unwanted responses from and to (older) Microsoft products.
+ + ManageSieve: Added rawlog_dir setting to store ManageSieve traffic logs.
+ This replaces at least partially the rawlog plugin (mimics similar IMAP/POP3
+ change).
+ - doveadm sieve plugin: synchronization: Prevent setting file timestamps to
+ unix epoch time. This occurred when Dovecot passed the timestamp as
+ 'unknown' during synchronization.
+ - Sieve exprograms plugin: Fixed spurious '+' sometimes returned at the end
+ of socket-based program output.
+ - imapsieve plugin: Fixed crash occurring in specific situations.
+ - Performed various fixes based on static analysis and Clang warnings.
+
+v0.4.15 07-07-2016 Stephan Bosch <stephan@rename-it.nl>
+
+ * vacation extension: The sieve_user_email setting is now used in the check
+ for implicit delivery.
+ - imapsieve plugin: For any mail transaction, the mailbox was opened a second
+ time, even if no mailbox rule matched. This was unintentional, useless and
+ caused problems when the imapsieve plugin was used with other plugins like
+ acl.
+ - extprograms plugin: Significantly improved error handling. No stream errors
+ were logged.
+ - extprograms plugin: Fixed bug in handling of result code from remote program
+ (script service).
+ - extprograms plugin: Connection to remote program service was not retried.
+ - Several small fixes based on static analysis.
+ - Fixed handling of quoted string localparts in email addresses.
+
+v0.4.14 26-04-2016 Stephan Bosch <stephan@rename-it.nl>
+
+ * The address test now allows specifying the X-Original-To header.
+ + Implemented the Sieve imapsieve extension and its IMAP counterpart
+ (RFC 6785) as a set of plugins. This allows running Sieve scripts at IMAP
+ activity, rather than at delivery. There are also facilities for the
+ familiar sieve_before/sieve_after administrator scripts. A user script is
+ defined for a mailbox using an IMAP METADATA entry, whereas administrator
+ scripts are configured using mailbox matching rules defined in the plugin
+ settings.
+ + Adjusted the Sieve ihave extension to allow capability tests to be performed
+ at runtime. This way, scripts can be written that work both at delivery and
+ from IMAP.
+ + Implemented support for runtime trace debugging. This means that detailed
+ information about which commands, actions and tests are performed is written
+ to a file. That file is created in the configured directory, but only if
+ that directory exists. This way, a particular user can be easily singled out
+ for debugging. This works much like the Dovecot rawlog facility. The trace
+ output is identical to what is produced using sieve-test with its "-t"
+ command line option.
+ + Added a "sieve_user_email" setting that configures the user's primary email
+ address. This is mainly useful to have a user email address available in
+ IMAP, where envelope data is unavailable.
+ + Implemented the dovecot-specific "vnd.dovecot.report" extension. This allows
+ sending report messages in the Message Abuse Reporting Format (RFC 5965).
+ - extprograms plugin: Fixed epoll() panic caused by closing the output FD
+ before the output stream.
+ - Made sure that the local part of a mail address is encoded properly using
+ quoted string syntax when it is not a dot-atom.
+
+v0.4.13 18-03-2016 Stephan Bosch <stephan@rename-it.nl>
+
+ * redirect action: Added the list-id header to the duplicate ID for mail loop
+ prevention. This means that the message sent directly to the user and the
+ message coming through the mailing list itself are treated as different
+ messages by the loop detection of the redirect command, even though their
+ Message-ID may be identical.
+ * Changed the Sieve number type to uint64_t, which means that Sieve numbers
+ can now technically range up to 2^64. Some other Sieve implementation
+ allowed this, making this change necessary for successful migration.
+ + Implemented the sieve_implicit_extensions setting. The extensions listed in
+ this setting do not need to be enabled explicitly using the Sieve "require"
+ command. This behavior directly violates the standard, but can be necessary
+ for compatibility with some existing implementations of Sieve. Do not use
+ this setting unless you really need to!
+ - redirect action: Made mail loop detection more robust by forcibly adding a
+ Message-ID header if it is missing.
+ - Prevent logging a useless "script not found" error message for LDAP scripts
+ for which the entry exists but no attribute containing a script. This is not
+ necessarily an error.
+ - extprograms plugin: Changed the communication channel between parent and
+ child process for a directly forked program from a socketpair to a double
+ pipe. Linux does not support /dev/stdin, /dev/stdout and friends for
+ sockets. For some shell program authors this may be confusing, so that is
+ why it is changed. When using the script service, these device nodes are
+ still not usable though.
+
+v0.4.12 06-02-2016 Stephan Bosch <stephan@rename-it.nl>
+
+ + Implemented the Sieve extracttext extension (RFC 5703; Section 7). It is now
+ possible to extract body text from a message into a variable.
+ * Increased ABI version due to changes in the Sieve interpreter's object
+ definitions.
+ - multiscript: Fixed bug in handling of (implicit) keep; final keep action was
+ always executed as though there was a failure. This caused the keep action
+ to revert back to the initial message, causing editheader actions to be
+ ignored.
+ - managesieve-login: Fixed proxy to allow SASL mechanisms other than PLAIN.
+ Before, the proxy would fail if the server did not support the PLAIN
+ mechanism.
+ - ldap storage: Prevent segfault occurring when assigning certain (global)
+ configuration options.
+
+v0.4.11 08-01-2016 Stephan Bosch <stephan@rename-it.nl>
+
+ - Sieve mime extension: Fixed the header :mime :anychild test to work properly
+ outside a foreverypart loop.
+ - Several fixes in message body part handling:
+ - Fixed assert failure occurring when text extraction is attempted on a
+ empty or broken text part.
+ - Fixed assert failure in handling of body parts that are converted to text.
+ - Fixed header unfolding for (mime) headers parsed from any mime part.
+ - Fixed trimming for (mime) headers parsed from any mime part.
+ - Fixed erroneous changes to the message part tree structure performed when
+ re-parsing the message.
+ - LDA Sieve plugin: Fixed logging of actions; sometimes the configured log
+ format was not followed.
+ - LDA Sieve plugin: Fixed bug in error handling of script storage
+ initialization.
+ - Sieve Extprograms plugin: Ignored ENOTCONN error in shutdown(fd, SHUT_WR)
+ call.
+ - Fixed duplication of discard actions in the script result. Each discard was
+ counted as a separate action, which means that action limit would be crossed
+ too early.
+ - Made sure that quota errors never get logged as errors in syslog.
+ - Fixed handling of implicit keep for a partially executed transaction that
+ yielded a temporary failure.
+ - Fixed handling of global errors. If master and user error handler were
+ identical, in some cases the log message could be lost.
+ - Fixed AIX compile issue in message body parser.
+
+v0.4.10 13-12-2015 Stephan Bosch <stephan@rename-it.nl>
+
+ + Implemented the Sieve mime and foreverypart extensions (RFC 5703). These
+ are fully implemented. The interaction with the editheader extension needs
+ some work, but this should not influence most uses; i.e., changes by the
+ editheader extension are not always visible using foreverypart/mime.
+ + Sieve body extension: Properly implemented the `:text' body transform. It
+ now extracts text for HTML message parts.
+ + Sieve enotify extension: mailto method: Implemented the
+ sieve_notify_mailto_envelope_from setting. This allows configuring the
+ source of the notification sender address for e-mail notifications. This is
+ similar to what already can be configured for redirect.
+ + Added a sieve_enabled (defaults to 'yes') setting that allows explicitly
+ disabling Sieve processing for particular users. This used to be possible by
+ setting `sieve=', but ever since the sieve_before, sieve_after and
+ sieve_default settings were added, this method was not reliable anymore.
+ - variables extension: Fixed handling of empty string by the `:length' set
+ modifier. An empty string yielded an empty string rather than "0".
+ - Fixed memory leak in the Sieve script byte code dumping facility. Extension
+ contexts were never actually freed.
+ - Fixed handling of implicit keep when the last Sieve script is a global one.
+ In that case the implicit keep action was executed in global context, which
+ could mean that trivial (quota) errors ended up in the system log file,
+ rather than the user log file.
+ - doveadm sieve plugin: Fixed crashes caused by incorrect context allocation
+ in the sieve command implementations.
+
+v0.4.9 04-10-2015 Stephan Bosch <stephan@rename-it.nl>
+
+ * Properly implemented checking of ABI version for Sieve interpreter plugins,
+ much like Dovecot itself does for plugins. This will prevent plugin ABI
+ mismatches.
+ + Implemented a vnd.dovecot.environment extension. This builds upon the
+ standard environment extension and adds a few more environment items, such
+ as username and default mailbox. It also creates a variables namespace so
+ that environment items can be accessed directly. I am still thinking about
+ more environment items that can be added.
+ + Sieve extprograms plugin: Made line endings of the input passed to the
+ external programs configurable. This can be configured separately for each
+ of the three extensions.
+ + ManageSieve: Implemented proxy XCLIENT support. This allows the proxy to
+ pass client information to the back-end.
+ - ManageSieve: Fixed an assert failure occurring when a client disconnects
+ during the GETSCRIPT command.
+ - doveadm sieve plugin: Fixed incorrect initialization of mail user. This
+ caused a few memory leaks.
+ - sieve-filter command line tool: Fixed handling of failure-related implicit
+ keep when there is an explicit default destination folder. This caused
+ message duplication.
+ - lib-sieve: Fixed bug in RFC5322 header folding. Words longer than the
+ optimal line length caused empty lines in the output, which would break the
+ resulting message header. This surfaced in References: headers with very
+ long message IDs.
+
+v0.4.8 15-05-2015 Stephan Bosch <stephan@rename-it.nl>
+
+ * LDA Sieve plugin: Dovecot changed the deliver_log_format setting to include
+ %{delivery_time}. This prompted changes in Pigeonhole that make this release
+ dependent on Dovecot v2.2.17.
+ + Implemented magic to make sieve_default script visible from ManageSieve
+ under a configurable name. This way, users can see the default rules, edit
+ them and store a private adjusted version. This could also be achieved by
+ copying the default script into the user's script storage, but updates to
+ the global sieve_default script would be ignored that way.
+ + ManageSieve: Implemented support for reporting command statistics at
+ disconnect. Statistics include the number of bytes and scripts uploaded/
+ downloaded/checked and the number of scripts deleted/renamed.
+ - Fixed problem in address test: erroneously decoded mime-encoded words in
+ address headers.
+ - extprograms plugin: Fixed failure occurring when connecting to script
+ service without the need to read back the output from the external program.
+ - Fixed bug in script storage path normalization occurring with relative
+ symbolic links below root.
+ - Fixed and updated various parts of the documentation
+ - ManageSieve: Used "managesieve" rather than "sieve" as login service name,
+ which means that all managesieve-specific settings where ignored.
+ - Managesieve: Storage quota was not always enforced properly for scripts
+ uploaded as quoted string. Nobody uses that, but it is allowed in the
+ specification and we support it, so it should work properly.
+
+v0.4.7 19-03-2015 Stephan Bosch <stephan@rename-it.nl>
+
+ * editheader extension: Made protection against addition and deletion of
+ headers configurable separately. Also, the `Received' and `Auto-Submitted'
+ headers are no longer protected against addition by default.
+ * Turned message envelope address parse errors into warnings.
+ * The interpreter now accepts non-standard domain names, e.g. containing '_'.
+ + Implemented the Sieve index extension (RFC 5260).
+ + Implemented support for the mboxmetadata and servermetadata extensions
+ (RFC 5490).
+ + Implemented new sieve commands for the doveadm command line utility. These
+ commands are currently limited to ManageSieve operations, but the other
+ current sieve tools will be migrated to doveadm in the near future as well.
+ + Added more debug output about binary up-to-date checking.
+ + Added script metadata to binary dump output.
+ - Fixed Sieve script binary up-to-date checking by normalizing the script
+ location.
+ - The Sieve interpreter now flushes the duplicate database during start phase
+ of result execution rather than commit phase. This makes sure locks on the
+ duplicate database are released as soon as possible, preventing contention.
+ - Performed a few optimizations in the lexical scanner of the language.
+ - Fixed bug in `:matches' match-type that made a pattern without
+ wildcards match as if there were a '*' at the beginning.
+ - Fixed crash in validation of the string parameter of the comparator tag.
+ - extprograms extension: Made sure supplemental group privileges are also
+ dropped. This was a problem reported by Debian lintian.
+ - Fixed bug in handling of binary errors for action side-effects and message
+ overrides.
+ - file script storage: Restructured storage initialization to address
+ backwards compatibility issues.
+ - dict script storage: Fixed small memory allocation bug.
+
+v0.4.6 02-11-2014 Stephan Bosch <stephan@rename-it.nl>
+
+ - After make distclean the distributed tarball would fail to recompile.
+ This causes problems for some distribution builds.
+
+v0.4.5 30-10-2014 Stephan Bosch <stephan@rename-it.nl>
+
+ + Added a Pigeonhole version banner to doveconf output. This way, future
+ bug reports will also include Pigeonhole version information.
+ - Fixed handling of implicit keep. Last version erroneously reported that
+ implicit keep succeeded after an earlier failure, while it in fact had
+ failed. Particularly occurred for mailbox quota errors.
+ - Fixed segfault occurring on SunOS systems when there is no active script.
+
+v0.4.4 28-10-2014 Stephan Bosch <stephan@rename-it.nl>
+
+ * Added support for Japanese mail addresses with dots at non-standard places
+ in localpart.
+ * Changed handling of ENOSPACE into a normal temporary failure and added
+ handling of ENOQUOTA as a user error.
+ * Restructured result execution, so that all actions which involve mail
+ storage are always committed before all others.
+ + Implemented support for generic Sieve storages. Using alternative storages
+ now also possible for sieve_before/sieve_after.
+ + Implemented storage driver for retrieving Sieve scripts from LDAP. This
+ currently cannot be used with ManageSieve.
+ + Implemented sieve_redirect_envelope_from setting, which allows configuring
+ the envelope sender of redirected messages.
+ - Fixed handling of mail storage errors occurring while evaluating the input
+ message.
+ - managesieve-login:
+ - Removed bogus ALERT response code returned for AUTHENTICATE command.
+ - Fixed handling of invalid initial response argument to AUTHENTICATE
+ command.
+ - Fixed handling of stream errors in lexical scanner.
+ - Fixed handling of SMTP errors. Permanent and temporary errors were mixed up.
+ - Fixed several problems reported by CLang 3.4.
+ - duplicate extension: Fixed erroneous compile error about conflicting tags
+ when `:handle' argument was used last.
+ - relational extension: Fixed error handling of `:value' match.
+ - editheader extension: Fixed header unfolding and header iteration.
+ - mailbox extension: Fixed the `:create' tag, which erroneously subscribed an
+ existing folder.
+ - extprograms plugin: Fixed handling of error codes.
+ - doveadm-sieve plugin: Fixed several bugs. Synchronization of symbolic link
+ in the file storage should now also work properly.
+
+v0.4.3 12-05-2014 Stephan Bosch <stephan@rename-it.nl>
+
+ * Editheader extension: Made control characters allowed for editheader, except
+ NUL. Before, this would cause a runtime error.
+ + Upgraded Dovecot-specific Sieve "vnd.dovecot.duplicate" extension to match
+ the new draft "duplicate" extension.
+ - Fixed sieve_result_global_log_error to log only as i_info in administrator
+ log (syslog) if executed from multiscript context.
+ - Sieve redirect extension: Adjusted loop detection to show leniency to resent
+ messages.
+ - Sieve include extension: Fixed problem with handling of duplicate includes
+ with different parameters :once or :optional.
+ - Sieve spamtest/virustest extensions: Tests were erroneously performed
+ against the original message. When used together with extprograms filter to
+ add the spam headers, the changes were not being used by the spamtest and
+ virustest extensions.
+ - Deprecated Sieve notify extension: Fixed segfault problems in message string
+ substitution.
+ - ManageSieve: Fixed active link verification to handle redundant path slashes
+ correctly.
+ - Sieve vacation extension:
+ - Fixed interaction of sieve_vacation_dont_check_recipient with
+ sieve_vacation_send_from_recipient setting.
+ - Fixed log message for discarded response.
+ - Sieve extprograms plugin:
+ - Forgot to disable the alarm() timeouts set for script execution.
+ - Fixed fd leak and handling of output shutdown.
+ - Fixed 'Bad filedescriptor' error occurring when disconnecting script
+ client.
+ - Made sure that programs are never forked with root privileges.
+
+v0.4.2 26-09-2013 Stephan Bosch <stephan@rename-it.nl>
+
+ * Incompatible change in Sieve doveadm plugin: the root attribute for
+ Sieve scripts is changed. Make sure that you update both sides of a dsync
+ setup simultaneously when Sieve is involved, otherwise synchronization will
+ likely fail.
+ + Added support for sending Sieve vacation replies with an actual sender,
+ rather than the default <> sender. Check the updated
+ doc/extensions/vacation.txt for more information.
+ - Fixed a binary code read problem in the `set' command of the Sieve variables
+ extension. Using the set command with a modifier and an empty string value
+ would cause code corruption problems while running the script.
+ - Various fixes for doveadm-sieve plugin, mostly crashes. These include a fix
+ for the `Invalid value for default sieve attribute' problem.
+ - Various fixes for compiler and static analyzer warnings, e.g. as reported
+ by CLang and on 32 bit systems.
+ - Fixed the implementation of the new :options flag for the Sieve include
+ extension.
+ - Fixed potential segfault bug at deinitialization of the lda-sieve plugin.
+ - Fixed messed up hex output for sieve-dump tool.
+
+v0.4.1 03-06-2013 Stephan Bosch <stephan@rename-it.nl>
+
+ + Added support for handling temporary failures. These are passed back to
+ LDA/LTMP to produce an appropriate response towards the MTA.
+ - Sieve storage: Removed PATH_MAX limitation for active symlink. This caused
+ problems for GNU/Hurd.
+ - Fixed line endings in X-Sieve headers added by redirect command.
+ - ManageSieve: Fixed '[' ']' stupidity for response codes (only happened
+ before login).
+ - Fixed setting name in example-config/conf.d/20-managesieve.conf.
+ - Sieve extprograms plugin: Fixed interaction between pipe command and remote
+ script service. The output from the script service was never read, causing a
+ broken pipe error at the script service. Apparently, this was broken since
+ the I/O handling for extprograms was last revised.
+ - Fixed assertion failure due to datastack problem in message header
+ composition.
+
+v0.4.0 09-05-2013 Stephan Bosch <stephan@rename-it.nl>
+
+ + Added doveadm-sieve plugin that provides the possibility to synch Sieve
+ scripts using doveadm sync along with the user's mailboxes.
+ + Added the Sieve extprograms plugin to the main Pigeonhole package. It is
+ still a plugin, but it is now included so that a separate compile is no
+ longer necessary and distributors are likely to include it. The extprograms
+ plugin provides Sieve language extensions that allows executing
+ (administrator-controlled) external programs for message delivery,
+ message filtering and string manipulation. Refer to
+ doc/plugins/sieve_extprograms.txt for more information.
+ + Added debug message showing Pigeonhole version at initialization. Makes it
+ very clear that the plugin is properly loaded.
+ + Finished implementation of the Sieve include extension. It should now
+ fully conform to RFC 6609. The main addition is the new :optional tag which
+ makes the include command ignore missing included scripts without an error.
+ + Finished implementation of the Sieve environment extension as much as
+ possible. Environment items "location", "phase" and "domain" now also
+ return a usable value.
+
+v0.3.6 26-09-2013 Stephan Bosch <stephan@rename-it.nl>
+
+ - Fixed a binary code read problem in the `set' command of the Sieve variables
+ extension. Using the set command with a modifier and an empty string value
+ would cause code corruption problems while running the script.
+ - Various fixes for compiler and static analyzer warnings, as reported
+ by CLang.
+ - ManageSieve: Fixed '[' ']' stupidity for response codes (only happened
+ before login).
+ - Fixed setting name in example-config/conf.d/20-managesieve.conf.
+ - Fixed messed up hex output for sieve-dump tool.
+
+v0.3.5 09-05-2013 Stephan Bosch <stephan@rename-it.nl>
+
+ - Sieve editheader extension: fixed interaction with the Sieve body extension.
+ If used together, the deleteheader action could fail after a body test was
+ performed.
+ - Test suite: fixed a time zone dependency in the Sieve date extension tests.
+
+v0.3.4 06-04-2013 Stephan Bosch <stephan@rename-it.nl>
+
+ * Changed error handling to be less of a nuisance for administrators. Strictly
+ user-caused errors are only reported in user log. Some errors are logged as
+ info instead.
+ * Sieve: Changed behavior of redirect in case of a duplicate message delivery
+ or a mail loop. If a duplicate is detected the implicit keep is canceled,
+ as though the redirect was successful. This prevents getting local
+ deliveries. The original SMTP recipient is used when it is available to
+ augment the entry in the LDA duplicate database. This way, duplicates are
+ only detected when (initially) addressed to the same recipient.
+ + Sieve vnd.dovecot.duplicate extension: added new features to the duplicate
+ test, making it possible to manually compose the key value for duplicate
+ checking. This extension is in the process of being standardized
+ (https://tools.ietf.org/html/draft-bosch-sieve-duplicate-01).
+ + Sieve date extension: generate warning when invalid date part is specified.
+ - Sieve editheader extension: fixed crash occurring when addheader :last was
+ used.
+ - Sieve include extension: fixed missing error cleanup that caused a resource
+ leak.
+ - Sieve vacation extension: fixed determination of From: address for when
+ sieve_vacation_dont_check_recipient is active.
+ - Sieve tools: the -D option wasn't enabled and documented for all tools.
+ - Siev dict script storage: fixed potential segfault occurring when dict
+ initialization fails.
+ - ManageSieve: fixed bug in skipping of CRLF at end of AUTHENTICATE command.
+ - ManageSieve: fixed handling of unkown commands pre-login.
+ - Fixed compile on Mageia Linux.
+
+v0.3.3 18-09-2012 Stephan Bosch <stephan@rename-it.nl>
+
+ - Fixed compile against installed Dovecot headers. This was broken by the
+ ld.gold fix in the previous release.
+
+v0.3.2 18-09-2012 Stephan Bosch <stephan@rename-it.nl>
+
+ + sieve-refilter tool: improved man page documentation by explicitly
+ specifying the syntax used for mailbox arguments.
+ + Sieve: spamtest and virustest extensions: improved trace debugging of score
+ calculation.
+ + Sieve: made error messages about exceeding the maximum number of actions
+ more verbose.
+ - Sieve tools: fixed problems with running as root: sievec and sieve-dump now
+ ignore mail_uid and mail_gid settings when run as root.
+ - Sieve: fixed bug in action accounting (for limit checking): increase action
+ instance count only when an action is actually created.
+ - Sieve: include extension: fixed namespace separation of :global and
+ :personal scripts.
+ - ManageSieve: fixed segfault bug triggered by CHECKSCRIPT command.
+ - Fixed linking with ld.gold.
+ - Fixed several Clang compile warnings and a few potential bugs.
+
+v0.3.1 25-05-2012 Stephan Bosch <stephan@rename-it.nl>
+
+ * Added support for retrieving Sieve scripts from dict lookup. This means that
+ Sieve scripts can now be downloaded from a database. Compiled script
+ binaries are still put on disk somewhere if used. The INSTALL documentation
+ is updated with information on this new feature and the
+ (backwards-compatible) changes to the configuration. Note that his feature
+ is currently not supported for sieve_before/sieve_after or script management
+ through ManageSieve.
+ + Incorporated the sieve_duplicate plugin into main Pigeonhole tree as a
+ normal extension (vnd.dovecot.duplicate). This Dovecot-specific extension
+ adds the ability to check for duplicate deliveries based on message ID.
+ Specification can be found in: doc/rfc/spec-bosch-sieve-duplicate.txt
+ + Added support for specifying multiple sieve_before and sieve_after paths.
+ This adds much more flexibility to the multiscript configuration. One
+ application is to have user-specific Sieve scripts outside the user's
+ normal control through ManageSieve.
+ + Added a "session ID" string for managesieve connections, available in
+ %{session} variable (analogous to Dovecot change).
+ - Fixed several small issues, including a few potential segfault bugs, based
+ on static source code analysis.
+ - ManageSieve: changed use of EPROTO error to EIO in ManageSieve string stream
+ implementation because it is apparently not known in BSD.
+ - Gave stamp.h.in (needed for autotools) some content to prevent it from
+ disappearing in patch files.
+ - Fixed bug that caused a SunStudio CC compile failure (reported by Piotr
+ Tarnowski).
+
+v0.3.0 16-02-2012 Stephan Bosch <stephan@rename-it.nl>
+
+ * Renamed sieve_global_path setting to sieve_default for clarity. Old name is
+ still recognized for backwards compatibility. Support for the ancient (pre
+ v1.1) name for this setting "global_script_path" is now dropped.
+ * Added means to prohibit use of redirect action. Setting sieve_max_redirects
+ to 0 now means that redirect is disallowed instead of unlimited. Default
+ value remains four.
+ * Fixed interaction of Sieve include extension with ManageSieve. It is updated
+ to match new requirements in the draft include specification. Missing
+ included scripts are no longer an error at upload time.
+ * Updated RFC2822 header field body verification to exclude non-printing
+ characters (RFC5322). Only Sieve actions that can create unstructured header
+ values (currently enotify/mailto and editheader) are affected by this
+ change.
+ + Completed sieve-filter tool to a useful state. The sieve-filter tool
+ provides a means to (re)filter messages in a mailbox through a Sieve script.
+ + Implemented the Sieve editheader extension. It is now possible to add and
+ remove message headers from within Sieve.
+ + ManageSieve: added support for reading quoted and literal strings as a
+ stream. Fixes support for handing large SASL responses (analogous to similar
+ changes in Dovecot). It is now also allowed to use a quoted string for the
+ PUTSCRIPT script argument.
+ + Added code to cleanup tmp directory in Sieve storage directory (sieve_dir)
+ every once in a while.
+ + Added support for substituting the entire message during Sieve processing.
+ This is used for the filter action provided by the new sieve_extprograms
+ plugin (provided separately for now). The filter action allows passing the
+ message through an external program.
+ + Added support for restricting certain Sieve language extensions to
+ (admin-controled) global scripts. Restricted extensions can be configured
+ using the new sieve_global_extensions setting. This is particularly useful
+ for some of the Dovecot-specific (plugin-based) Sieve extensions, that can
+ be somewhat hazardous when under direct control of users (e.g.
+ sieve_extprograms).
+
+v0.2.6 13-02-2012 Stephan Bosch <stephan@rename-it.nl>
+
+ * This release fixes unintentional behavior of the include extension. Included
+ scriptnames with a name like "name.sieve" would implicitly map to a script
+ file called "name.sieve" and not "name.sieve.sieve". Keep in mind that the
+ .sieve file extension has no meaning from within the Sieve language. A Sieve
+ script is always stored with an appended .sieve file extension, also when
+ the name already ends with a .sieve suffix.
+ IMPORTANT: Some installations have relied on this unintentional feature, so
+ check your script includes for issues before upgrading.
+ * Matched changes regarding auth_verbose setting in Dovecot. This means that
+ this release will only compile against Dovecot v2.0.18.
+ - Fixed problem in ManageSieve that caused it to omit a WARNINGS response code
+ when the uploaded script compiled with warnings.
+ - Made sure that locations of Sieve error never report `line 0'.
+ - Fixed potential segfault occurring when interpreter initialization fails.
+
+v0.2.5 19-11-2011 Stephan Bosch <stephan@rename-it.nl>
+
+ + Sieve vacation extension: made discard message for implicit delivery more
+ verbose
+ - The sieve-test tool: mixed up original and final envelope recipient in
+ implementation of command line arguments.
+ - Sieve vacation extension: resolved FIXME regarding the use of variables in
+ the :handle argument. Variables are now handled correctly.
+ - Sieve body extension: fixed handling of :content "message/rfc822". This now
+ yields the headers of the embedded message as required by the specification.
+ Handling of :content "multipart" remains to be fixed.
+ - LDA Sieve plugin: fixed problem with recipient_delimiter configuration. Now
+ falls back to global recipient_delimiter setting if
+ plugin/recipient_delimiter is not set.
+
+v0.2.4 13-09-2011 Stephan Bosch <stephan@rename-it.nl>
+
+ + Vacation extension: finally added support for using the original recipient
+ in vacation address check. It is also possible to disable the recipient
+ address check entirely. Check doc/vacation.txt for configuration
+ information.
+ + Include extension: made limits on the include depth and the total number of
+ included scripts configurable. Check doc/include.txt for configuration
+ information.
+ + Implemented ihave extension. This allows checking for the availability
+ of Sieve language extensions at 'runtime'. Actually, this is checked
+ at compile time. At runtime the interpreter checks whether extensions
+ that were not previously available are still unavailable. If the situation
+ changed, the script is re-compiled and the ihave tests are evaluated again.
+ + Sieve: optimized compilation of tests that yield constant results (i.e.
+ known at compile tme), such as 'true' and 'false'. No code is produced
+ anymore for script sections that are never executed. Also, semantics
+ are not verified anymore in uncompiled script sections.
+ + Made vnd.dovecot.debug extension available to the LDA plugin instead of
+ only the command line tools.
+ + Sieve: redirect action now adds X-Sieve-Redirected-From header (mainly for
+ people using SPF/SRS).
+ - Sieve: fixed bug in handling flags and keywords; in case of error an
+ assertion was triggered.
+ - Script storage: improved handling of unconfigured user home directory.
+ Originally this would produce an unhelpful error message.
+ - Imap4flags extension: prevent forcibly enabling imap4flags when imapflags
+ is enabled.
+ - Fixed various -Wunused-but-set-variable compiler warnings.
+ - Include extension: forgot to check variable identifier syntax for 'global'
+ command.
+ - Sieve: fixed debug mode; no messages were logged in some situations.
+ - sievec tool: forgot to enable -D (debug) parameter.
+
+v0.2.3 14-04-2011 Stephan Bosch <stephan@rename-it.nl>
+
+ * Sieve filter tool: finished implementing basic functionality. It is not
+ quite ready yet, but it is available for those willing to experiment
+ with it (needs --with-unfinished-features config to compile). Also
+ includes man page.
+ + Vacation extension now inhibits replies to messages from sender listed
+ in :addresses, thus preventing replies to one of the user's other known
+ addresses.
+ + Vacation extension: implemented the (draft) vacation-seconds extension.
+ This also adds min/max period configuration settings. Refer to
+ doc/vacation.txt for configuration information.
+ - ManageSieve: fixed bug in UTF-8 checking of string values. This is done
+ by discarding the original implementation and migrating to the Dovecot
+ API's UTF-8 functionality.
+ - Sieve command line tools now avoid initializing the mail store unless
+ necessary. This prevents sievec and sieve-dump from failing when
+ executed by root for example.
+ - Enotify extension: fixed inappropriate return type in mailto URI parse
+ function, also fixing ARM compiler warning.
+ - Vacation extension: fixed handling of sendmail errors. It produced an
+ additional confusing success message in case of error.
+ - Removed header MIME-decoding to fix erroneous address parsing. Applies to
+ address test and vacation command.
+ - Fixed segfault bug in extension configuration, triggered when unknown
+ extension is mentioned in sieve_extensions setting.
+
+v0.2.2 06-12-2010 Stephan Bosch <stephan@rename-it.nl>
+
+ * LDA Sieve plugin: started using Dovecot LDA reject API for the reject
+ extension. This means that the LDA reject_reason and reject_subject
+ settings now also work for Pigeonhole's LDA Sieve plugin.
+ * Did some work on the new sieve-filter tool. It is mostly functional, but
+ it is not finished yet.
+ * Dovecot change: services' default vsz_limits weren't being enforced
+ correctly in earlier v2.0 releases. Now that they are enforced, you might
+ notice that the default limits are too low and you need to increase them.
+ This problem will show up in logs as "out of memory" errors. See
+ default_vsz_limit and service { vsz_limit } settings.
+ - Imap4flags: fixed segfault bug occurring in multiscript context.
+ - Added version checking to the ManageSieve settings plugin. This plugin was
+ forgotten when the LDA plugin was updated with this change in the previous
+ release.
+ - LDA Sieve plugin: fixed memory leak at deinitialization.
+
+v0.2.1 27-09-2010 Stephan Bosch <stephan@rename-it.nl>
+
+ + Incorporated distinction between original and final envelope recipient in
+ Sieve interpreter, as recently introduced in Dovecot.
+ + Regex extension: added support for regex keys composed from variables.
+ - LDA Sieve plugin: added _version symbol to enable Dovecot's plugin version
+ check. Without this check, people can forget to recompile the plugin, which
+ can lead to unexpected effects.
+ - LDA Sieve plugin: turned debug message about an unconfigured home directory
+ into a proper error and added script path information.
+ - Fixed unnecessary reporting of dummy extensions in ManageSieve SIEVE
+ capability; the comparator-i;octet and comparator-i;ascii-numeric
+ 'extensions' were reported explicitly.
+
+v0.2.0 10-09-2010 Stephan Bosch <stephan@rename-it.nl>
+
+ * Merged Sieve and ManageSieve packages into a single Pigeonhole package.
+ There is also no need to patch Dovecot anymore to gain ManageSieve support.
+ Version numbering of previous Sieve releases is continued as v0.2.0. The
+ sources originally branched off from Sieve v0.1.5 and ManageSieve v0.11.4,
+ but the NEWS history of much more recent releases for Dovecot v1.2 is
+ included since these changes are all included in this release as well.
+ * The ManageSieve service now binds to TCP port 4190 by default due to the
+ IANA port assignment for the ManageSieve service. When upgrading from v1.2,
+ this should be taken into account. The service can be configured manually to
+ listen on both 2000 and 4190.
+ * The Dovecot configuration now calls the ManageSieve protocol 'sieve' in
+ stead of 'managesieve' because it is registered as such with IANA. The
+ binaries and the services are still called managesieve and
+ managesieve-login.
+ * The binary representation of a compiled Sieve script is updated to include
+ source code locations of all commands and arguments. This is implemented in
+ a similar manner as such debug information is included in some system
+ executables and libraries (DWARF-like). Run-time errors can now always refer
+ to the proper line number in the Sieve source script.
+ * The Sieve plugin is adapted to work properly with the new LMTP service
+ introduced with Dovecot v2.0. The same plugin is used for both LDA and LMTP.
+ * The 'sieve_subaddress_sep' setting for the Sieve subaddress extension is now
+ known as 'recipient_delimiter'. Although the deprecated sieve_subaddress_sep
+ setting is still recognized for backwards compatibility, it is recommended
+ to update the setting to the new name, since the new LMTP service also uses
+ the recipient_delimiter setting.
+ * ManageSieve: changed default IMPLEMENTATION capability to from 'Dovecot' to
+ 'Dovecot Pigeonhole'.
+ * Renamed the sieved tool to sieve-dump. The original name was somewhat
+ confusing.
+ * Updated man pages to match style and structure of new Dovecot man pages.
+ * Made testsuite commands more uniform and cleaned up many of the testsuite
+ scripts. Some minor new tests were added in the process.
+ + Simplified string matching API to use abstract string lists as data sources.
+ This will also make implementing the index extension easier in the future.
+ + Significantly improved trace debugging with the sieve-test tool. The full
+ execution of the script can be examined, including the matched values and
+ keys of the respective Sieve test commands. The executed statements are
+ listed with their line number (and code address when requested). The level
+ of detail is configurable from the command line.
+ + The SIEVE and NOTIFY capabilities reported by the ManageSieve protocol can
+ now be configured manually. If left unconfigured, the capabilities are
+ determined from the default Sieve and ManageSieve configuration.
+ User-specific capabilities aren't reported until after authentication.
+ + Significantly improved file error handling. This means that administrators
+ get a more useful and informative log message when file operations fail. The
+ most notable example is that when the LDA Sieve plugin is trying to store a
+ binary for a global script, the resulting failure message also points the
+ administrator towards pre-compiling the script with sievec.
+ + Added runtime argument value checking for several commands (redirect, date
+ vacation). When variables are used, these checks cannot be performed at
+ compiletime. A proper runtime error now is produced when invalid data is
+ encountered.
+ + UTF8 validity of fileinto command argument is now checked either at compile
+ time or at runtime. Previously, it was not checked until the store action
+ was executed.
+ + Validity of IMAP flags for the imap4flags extension is now checked also
+ at runtime. Previously, it was not checked until the store action was
+ executed.
+ + Simplified and restructured error handling. Also made sure that user-caused
+ errors are no longer written to the Dovecot master/LDA log.
+ - Multiscript: fixed duplicate implicit keep caused by erroneous execution
+ state update.
+ - Prevented assertion failure due to currupt binary string representation.
+ If the string was missing a final \0 character an assertion was produced in
+ stead of a binary corruption error.
+ - Imap4flags: fixed bug in setflag command; when parameter was a stringlist,
+ only the last item was actually set.
+ - Variables extension: fixed :length set modifier to recognize utf8 characters
+ instead of octets.
+ - Testsuite: prevented innocent warning messages, i.e. those that are part of
+ the test, from showing up by default.
+ - ManageSieve/Sieve storage: fixed error handling of PUTSCRIPT commmand; save
+ commit errors would not make the command fail.
+ - ManageSieve: enforced protocol syntax better with some of the commands; some
+ commands allowed spurious extra arguments.
+ - Fixed Sieve script name checking to properly handle length limit and added
+ 0x00ff as invalid character.
+ - Removed spurious old stdio.h (top) includes; these caused compile issues on
+ specific systems.
+ - Fixed default Sieve capability (as reported by ManageSieve): extra
+ extensions spamtest, spamtestplus and virustest were enabled by default.
+ These should, however, only be enabled when properly configured and there
+ is no default configuration.
+
+(Fused Dovecot Sieve and ManageSieve packages into a single Pigeonhole release)
+
+Dovecot Sieve NEWS history:
+---------------------------
+
+Dovecot 1.2:
+
+v0.1.17 19-06-2010 Stephan Bosch <stephan@rename-it.nl>
+
+ - Made sure source code positions for compiler messages are recorded at start
+ of tokens.
+ - Fixed a few potential memory leaks in the Sieve compiler and the
+ spam/virustest extensions.
+ - Made command line tools return proper exit status upon failure.
+
+v0.1.16 30-04-2010 Stephan Bosch <stephan@rename-it.nl>
+
+ * Finished implementation of spamtest, spamtestplus and virustest extensions.
+ These are not enabled by default and need to be activated with the
+ sieve_extensions setting. Documentation available in
+ doc/spamtest-virustest.txt
+ + Vacation extension: the from address of the generated reply is now by
+ default equal to whatever known recipient alias matched the headers of the
+ message. If it is one of the aliases specified with :addresses, it is used
+ instead of the envelope recipient address that was used before.
+ + Restructured and optimized the lexical scanner.
+ + Added --with-docs configure option to allow disabling installation of
+ documentation.
+ - Accidentally omitted 'extern' in two declarations of global variables in
+ header files, causing compile failures on certain systems.
+ - Deprecated imapflags extension: fixed implicit assignment of flags. Turns
+ out this never really worked, but the effect of this bug was obscured by the
+ removeflag bug fixed in the previous release.
+ - Fixed various memset argument mixups in enotify extension. This caused
+ warnings on certain systems, but luckily no adverse effects at runtime.
+
+v0.1.15 25-01-2010 Stephan Bosch <stephan@rename-it.nl>
+
+ * Enotify extension:
+ - Adjusted notify method API for addition of new notification methods.
+ - Set default importance level to 'normal' (was 'high').
+ * Include extension: updated implementation towards most recent specification
+ (all should be backwards compatible):
+ - Implemented global variables namespace.
+ - Global command may now appear anywhere in a script.
+ - Implemented script name checking using the requirements specified in the
+ ManageSieve draft.
+ - One issue remains: ManageSieve currently requires included scripts to be
+ uploaded first, which is not according to specification.
+ * Changed envelope path parser to allow to and from envelope addresses that
+ have no domain part.
+ + Added preliminary support for Sieve plugins and added support for installing
+ Sieve development headers.
+ + Started work on the implementation of the spamtest, spamtestplus and
+ virustest extensions (unfinished).
+ + Deprecated notify extension: implemented denotify command.
+ + Variables extension: added support for variable namespaces.
+ + Added configurable script size limit. Compiler will refuse to compile files
+ larger than sieve_max_script_size.
+ + Testsuite changes:
+ - Added support for changing and testing an extension's configuration.
+ - Added a command line parameter for copying errors to stderr.
+ - Fixed a bug in the i;ascii-numeric comparator. If one of the strings started
+ with a non-digit character, the comparator would always yield less-than.
+ - Imap4flags extension: fixed bug in removeflag: removing a single flag failed
+ due to off-by-one error (bug report by Julian Cowley).
+ - Improved EACCES error messages for stat() and lstat() syscalls and slightly
+ improved error messages that may uccur when saving a binary.
+ - Vacation extension: fixed typo in runtime log message (patch by Julian
+ Cowley).
+ - Fixed use of minus '-' in man pages; it is now properly escaped.
+ - Fixed parser recovery. In particular cases it would trigger spurious errors
+ after an initial valid error and sometimes additional errors were
+ inappropriately ignored.
+
+v0.1.14 19-12-2009 Stephan Bosch <stephan@rename-it.nl>
+
+ * Made the imposed limits on the number of redirects and the number of
+ actions configurable. The settings are called sieve_max_actions and
+ sieve_max_redirects.
+ * Did a major rework of extension handling, making sure that no global state
+ is maintained. This change was triggered by problems that global state info
+ would cause for Dovecot v2.0, but it is also important for v1.2 as it
+ significantly cleans up the library implementation.
+ + Made LDA Sieve plugin recognize the deliver_log_format setting.
+ + Message headers produced from user-supplied data are now RFC2047-encoded if
+ necessary for outgoing messages. This is for example important for the
+ :subject argument of the vacation action.
+ + Added support for the $text$ substitution in the deprecated notify
+ extension.
+ + The subaddress extension now also accepts recipient_delimiter setting as an
+ alias for sieve_subaddress_sep setting. This anticipates the
+ recipient_delimiter setting in v2.0.
+ - Fixed logging of mailbox names. It logged the converted mUTF7 version in
+ stead of the original UTF8 version supplied by the user.
+ - Fixed a minor memory leak in the multiscript support.
+ - Fixed a bug in the recompilation of Sieve scripts. Made sure that scripts
+ are only recompiled when the script file - or the symlink pointing to it -
+ is strictly newer.
+
+v0.1.13 18-10-2009 Stephan Bosch <stephan@rename-it.nl>
+
+ + Body extension: implemented proper handling of the :raw transform and added
+ various new tests to the test suite. However, :content "multipart" and
+ :content "message/rfc822" are still not working.
+ + Fixed race condition occurring when multiple instances are saving the same
+ binary (patch by Timo Sirainen).
+ + Test suite: added support for testing multiscript execution.
+ - Made compiler more lenient towars missing CRLF at the end of the script in a
+ hash comment.
+ - Body extension: don't give SKIP_BODY_BLOCK flag to message parser, we want
+ the body! (patch by Timo Sirainen).
+ - Fixed handling of implicit side effects for multiscript execution.
+ - Fixed bugs in multiscript support; subsequent keep actions were not always
+ merged correctly and implicit side effects were not always handled
+ correctly.
+ - Fixed a segfault bug in the sieve-test tool occurring when compile fails.
+ - Fixed segfault bug in action procesing. It was triggered while merging side
+ effects in duplicate actions.
+ - Fixed bug in the Sieve plugin that caused it to try to stat() a NULL path,
+ yielding a 'Bad address' error.
+
+v0.1.12 21-08-2009 Stephan Bosch <stephan@rename-it.nl>
+
+ + Testsuite: added support for testing binaries stored on disk.
+ + Implemented the new date extension. This allows matching against date values
+ in header fields and the current date at the time of script evaluation.
+
+v0.1.11 08-08-2009 Stephan Bosch <stephan@rename-it.nl>
+
+ + Built skeleton implementation for the date extension (RFC 5260). It
+ compiles, but it does not do anything useful yet. Therefore, it is not part
+ of the default compilation.
+ - Fixed ARM portability issues caused by char type not being signed on that
+ platform. Reading optional operands from a binary would fail for action side
+ effects. Also, an accidental mixup of an int return type with bool caused
+ the interpreter to continue on ARM even though an error occured.
+ - Removed direct stdint.h includes to prevent portability issues.
+ - Fixed segfault bug in the handling of script open failures.
+ - Include: improved user error messages and system log messages.
+ - Fixed copy-paste mixup between sieve_after and sieve_before settings in the
+ LDA Sieve plugin. If only a sieve_after script was active, nothing would
+ have been executed. Patch by Mike Abbott.
+ - Include: fixed a bug in HOME substitution in the sieve_dir path. Surfaced in
+ ManageSieve.
+
+v0.1.10 03-08-2009 Stephan Bosch <stephan@rename-it.nl>
+
+ * Changed action execution of fileinto and keep. These changes depend on API
+ additions in Dovecot, making this release depend on Dovecot v1.2.2 or newer.
+ * Further developed the sieve-filter command line tool. This required a few
+ changes to the action execution of the Sieve engine. The tool was
+ successfully tested on folders with a few 100k spam messages. However, the
+ commandline options are still incomplete, a man page is missing and it needs
+ much more testing before I can recommend anyone to use this tool.
+ + Added support for the mailbox extension. This allows checking whether a
+ mailbox exists using the mailboxexists command and it adds the :create
+ argument to the fileinto command to create the mailbox when it is missing.
+ The :create feature is useless unless the Deliver LDA is run with the -n
+ option.
+ + Improved the testsuite with tests for message delivery. Messages stored
+ using keep and fileinto can be fed back into the Sieve engine for
+ verification. This includes testing of applied IMAP flags.
+ + Updated the man pages with the new method of specifying the supported
+ extensions using + and - (for the -x parameter of the sieve tools)
+ + Further developed the deprecated notify extension. A dummy for the denotify
+ command exists, meaning that its use does not cause an error anymore.
+ - Fixed a bug in the derivation of the binary path from the script path. A
+ bare filename would yield a path relative to root.
+ - Fixed a bug in the value matching code. The context data now uses a proper
+ pool instead of the data stack. Bug reported by Jan Sechser.
+ - Fixed assertion fail in the include extension caused by missing
+ initialization upon binary load. This bug surfaces only for stored
+ binaries. Bug reported by Tom Hendrikx.
+ - Fixed include error message for failed :global include. It mentioned the
+ wrong config parameter.
+ - Fixed broken wiki reference in an error message of the plugin about the
+ 'sieve' setting.
+ - Fixed behavior of fileinto when delivering into a namespace prefix.
+ Previous fix used the wrong storage.
+
+v0.1.9 22-07-2009 Stephan Bosch <stephan@rename-it.nl>
+
+ * Removed the unfinished sieve-filter tool from the default build. It is now
+ only built when the --with-unfinished-features switch is supplied during
+ configure.
+ + Started building support for the ereject version of the reject action,
+ which has a preference to use an SMTP/LMTP protocol error instead of a
+ bounce message. This is to be used to make the Sieve plugin honour Deliver's
+ -e parameter. This is not yet finished and not built by default.
+ + Improved 'Permission denied' error messages just like Dovecot does,
+ precisely specifying what permission is missing to access or create a file.
+ + Added additional headers to the list of allowed headers for the address
+ test. The restrictive nature of the address test is not always appropriate.
+ Still thinking of a better, less restrictive implementation.
+ + Made the deprecated notify extension compatible with the old CMUSieve
+ plugin. However, the denotify command and the $text$ substitution are not
+ yet supported.
+ + Made the discard action log a message to avoid confusion about disappearing
+ messages.
+ - Fixed behavior of fileinto when delivering into a namespace prefix. It now
+ uses silent delivery into INBOX as fallback.
+ - Fixed logging of folder namespace prefix upon delivery into a prefixed
+ namespace. Formerly it only logged the bare folder name.
+ - Fixed a potential segfault in the argument validation. It didn't surface
+ because no command could have a :tag followed by an associated parameter as
+ last argument.
+ - Fixed segfault bug occurring in envelope test when performed on null (<>)
+ envelope path. The fix involves a rather large restructuring of the code to
+ make sure envelope addresses are properly handled everywhere (bug reported
+ by Nikita Koshikov)
+ - Envelope: fixed bug in application of address parts; failure to obtain
+ the part would cause inappropriate match success (bug reported by Ron Lee)
+ - Fixed extension conflict checks during validation. It could sometimes
+ produce useless errormessages. This is currently only used by the
+ deprecated extensions.
+ - Forgot to remove old explicit storage library dependency (patch by
+ Arkadiusz Miskiewicz).
+ - Fixed compiler warnings on certain platforms regarding the use fwrite for
+ outgoing message construction
+
+v0.1.8 12-07-2009 Stephan Bosch <stephan@rename-it.nl>
+
+ - Fixed AIX compile problem. For portability, the typeof operator is
+ not used anymore.
+ + Added partial support for the deprecated notify extension. However, it
+ turns out that the implementation provided by cmusieve is even older (2001),
+ meaning that this is currently not backwards compatible with cmusieve.
+
+v0.1.7 05-07-2009 Stephan Bosch <stephan@rename-it.nl>
+
+ + Added support for CRLF line breaks in strbuf error handler to fix a
+ ManageSieve problem.
+ + Improved consistency of sieve tool documentation and fixed missing
+ parameters in internal tool help output.
+ + Enhanced extensions configuration, allowing to specify the enabled
+ extensions relatively to the default (patch by Steffen Kaiser).
+ - Forgot to initialize script execution status in Sieve plugin, causing
+ segfaults on compile errors in specific conditions.
+ - Fixed logging in Sieve plugin for execution of default main script (went
+ to STDERR).
+
+v0.1.6 18-06-2009 Stephan Bosch <stephan@rename-it.nl>
+
+ * Adjusted to changes in Dovecot to make it compile against v1.2.rc5
+ * Made default of sieve_dir setting match the ManageSieve implementation.
+ - Fixed a few problems in de body extension that caused assert failures in
+ specific situations.
+
+v0.1.5 18-04-2009 Stephan Bosch <stephan@rename-it.nl>
+
+ * Ported the implementation of the Sieve include extension to the latest
+ draft. This means that the import and export commands are replaced by a new
+ command called global. The import and export commands are now DEPRICATED and
+ are mere aliases for the global command. The new specification also adds the
+ :once modifier to the include command. The also newly specified global.*
+ variable namespace is not implemented yet as support for variable namespaces
+ is currently missing.
+ * Did a major rework of the multiscript support for better error handling and
+ made sure that persistent global scripts (sieve_before/sieve_after) are
+ always executed, even when the user does not have a script of his own and
+ a global default is missing.
+ + Provided basic support for the environment extension. Currenly, the name,
+ version and host items are useful. Others are pending.
+ + Improved error message that is presented when an unknown Sieve extension is
+ provided as argument to the require command. It now notifies the user that
+ Sieve core commands do not need to be specified in require.
+ - Fixed bug in includes at levels deeper than one.
+ - Fixed bug in address matching that was caused by the failure to handle group
+ specifications. In dovecot, these are marked by address items with NULL
+ elements, which causes a segfault if not considered. The group 'undisclosed-
+ recipients:;' in particular triggered this bug. Bug reported by Bernhard
+ Schmidt.
+
+v0.1.4 21-03-2009 Stephan Bosch <stephan@rename-it.nl>
+
+ * Started work on the sieve-filter tool. With this command line tool it will
+ be possible to (re-)apply Sieve filters on a mail folder. It is currently
+ undocumented and far from functional.
+ + Added a custom debug extension that provides the possibility to print debug
+ messages from scripts executed by the Sieve tools.
+ - Fixed issue with opening relative paths as a mail file. Bug reported by Ian
+ P. Christian.
+ - Fixed MAC OSX compile problem. Turns out the extern modifier was missing at
+ multiple places. Bug reported by Edgar Fuss.
+ - Fixed Solaris compile problem: removed unecessary and unportable linker
+ flags that caused compile to fail. Bug reported by Andrés Yacopino.
+
+v0.1.3 12-02-2009 Stephan Bosch <stephan@rename-it.nl>
+
+ * Adapted to changes in Dovecot, making this release dependent on Dovecot
+ >= 1.2.beta1
+ * Made mail address comparison fully case-insensitive. This is particularly
+ noticeable for the :addresses argument of the vacation command.
+ + Finished enotify extension. Currently, only the mailto notification method
+ is implemented. All still needs to be tested thoroughly.
+ + Implemented multiscript support. It is now possible to execute multiple
+ Sieve scripts sequentially. Administrator-controlled scripts can be
+ executed before and after the user's script. Still needs to be tested
+ thoroughly.
+ + Implemented support for configuring the available Sieve extensions.
+ + Made the subaddress extension (partially) configurable using the
+ sieve_subaddress_sep setting, which allows specifying a (multi-charater)
+ separator other than '+'.
+ + Compiler now warns about invalid header field names used for the header and
+ address tests.
+ + Vacation extension now properly generates a References header for the
+ response message.
+ + Added testing of basic result execution to the test suite. Also added
+ supportfor testing the outgoing messages produced by the Sieve interpreter.
+ + Included execution of the actual result in the sieve-test command line tool.
+ The undocumented sieve-exec tool that existed for this is now removed as
+ planned.
+ + Added support for the now obsolete 'imapflags' extension for backwards
+ compatibility with CMUSieve. This also implements the mark/unmark commands.
+ - Fixed bugs in the regex extension: 1) if an optional match value did not in
+ fact match, subsequent match values would get unexpected indexes. 2) fixed
+ segfault bug occurring when regex is freed.
+ - Fixed bug in the use of the :from agrument for the vacation command. If this
+ address included a phrase part, the response would not be a valid RFC822
+ message.
+ - Plugged a theoretical security hole occurring when a directory is opened as a
+ Sieve binary.
+ - Cleaned up and fixed various log messages.
+ - Fixed bug in the outgoing address verification. Addresses ending in ',' were
+ erroneously accepted.
+
+v0.1.2 26-11-2008 Stephan Bosch <stephan@rename-it.nl>
+
+ - Fixed important bug in the redirect action (and probably other actions like
+ reject and vacation that only send messages). This was a bug in the handling
+ of context information during the execution of actions. It caused the sieve
+ interpreter to crash with a segfault when redirect was executed.
+
+v0.1.1 24-11-2008 Stephan Bosch <stephan@rename-it.nl>
+
+ * Re-enabled support for compiling against dovecot headers. Much like
+ cmusieve, command line tools like sievec and sieved are not compiled in this
+ case.
+ * Started implementation of enotify extension. Not anywhere near finished
+ though.
+ * Adapted to changes in Dovecot on various occasions, making this release
+ dependent on Dovecot >= v1.2.alpa4.
+ + Improved logging of errors at specific occasions and added debug messages to
+ find script execution problems quicker.
+ + Removed code duplication between command line tools and the test suite.
+ Also restructured the sources of the tools.
+ + Added UTF-8 to UTF-7 folder name conversion for compatibility with IMAP.
+ + Created man pages for the command line tools. These are automatically
+ installed upon 'make install'
+ + Incorporated Valgrind support into the testsuite and fixed a few memory
+ leaks in the process.
+ - Fixed compile error surfacing for gcc3.4. Forgot mask argument for the
+ open() system call when the O_CREAT flag is specified. Bug found by
+ Sergey Ivanov.
+ - Fixed bug in the sievec tool. -d output was always written to stdout.
+ - Fixed important bug in the imap4flags extension. When no :flags argument is
+ specified, the previous version would always use the final value of the
+ internal variable to set the flags. This means that modifications to the
+ internal variable also affected the bare fileinto/keep actions executed
+ earlier. This does not comply to the RFC.
+ - Fixed bug in the include extension's import/export commands. Duplicate
+ import/exports caused problems.
+ - Fixed bug in the handling of non-existent scripts. Errors were sometimes
+ ignored.
+ - Dovecot omitted unfolding multi-line headers. This was added to the cmusieve
+ plugin after the code was incorporated into the new implementation. This is
+ now mplicitly fixed by concurrent change in Dovecot.
+
+v0.1.0 23-10-2008 Stephan Bosch <stephan@rename-it.nl>
+
+ * Initial release
+
+Dovecot ManageSieve NEWS history:
+---------------------------------
+
+Dovecot 1.2:
+
+v0.11.11:
+ * This release contains adjustments to match changes in the Sieve API. This
+ means that this release will only compile against Pigeonhole Sieve
+ v0.1.15.
+ + Implemented ManageSieve QUOTA enforcement.
+ + Added MAXREDIRECTS capability after login.
+ + Implemented new script name rules specified in most recent ManageSieve
+ draft.
+ - Fixed assertion failure occurring with challenge-response SASL mechanisms.
+ - Made configure complain about trying to compile against installed Dovecot
+ headers alone.
+ - Fixed compile warning for compilation against CMUSieve.
+
+v0.11.10:
+ * This release contains adjustments to match changes in the Sieve API. This
+ means that this release will only compile against Pigeonhole Sieve
+ v0.1.14.
+ - Fixed compilation of ManageSieve against CMUSieve.
+
+v0.11.9:
+ * Adjusted to changes in the Dovecot login proxy API. This release
+ therefore depends on Dovecot v1.2.4.
+ + Reintroduced ability to abort SASL with "*" response. Latest ManageSieve
+ specification includes it.
+
+v0.11.8:
+ - Fixed TLS support for proxying ManageSieve. The protocol state machine
+ was incorrect. Also added a check that disables ssl when 'starttls' is
+ not enabled for the user. This produces a proper warning in the log file.
+ There is no such thing as a managesieveS protocol which has SSL from the
+ start.
+
+v0.11.7:
+ * Adjusted to changes in the Dovecot login API. This release now depends on
+ Dovecot v1.2.1 or newer.
+ * Incorporated various small changes in IMAP into ManageSieve. This includes
+ properly enabling the generation of core dumps.
+ - The previous release implicitly resolved the FreeBSD script truncation
+ error. This release adds a small correction to the code that detects the
+ truncation.
+ - Fixed panic occurring when many errors are produced by the Sieve compiler
+ (bug found by Pascal Volk).
+ - Fixed memory leak in the PUTSCRIPT command.
+
+v0.11.6:
+ * Adjusted to changes in Dovecot regarding client idle timeout vs
+ authentication timeout. This release now depends on Dovecot v1.2.rc6 or
+ newer.
+ - Fixed CRLF line breaks in compile errors (bug reported by Pascal Volk).
+ - Corrected directory/file creation behavior with respect to mode bits
+ and gid (bug reported by Pascal Volk).
+ - Improved handling of script truncation bugs: connection is now closed and
+ an error is logged. bug itself not fixed yet).
+ - Prevented temp script name from showing up in error output.
+
+v0.11.5:
+ * Incorporated various changes from imap-login into managesieve-login. This
+ includes changes in the proxy support.
+
+v0.11.4:
+ * Adjusted to changes in the Dovecot signal handler API.
+
+v0.11.3:
+ * Changed the SASL service name from "managesieve" into "sieve" as required
+ in the protocol specification. Don't forget to adjust your configuration
+ if your authentication mechanism depends on this service name.
+ * Adapted to changes in Dovecot, making this release dependent on Dovecot
+ >= v1.2.beta1.
+ * Adapted to changes in the new Sieve implementation, making this release
+ dependent on Dovecot Sieve >= v0.1.3 if used. The old cmusieve plugin is
+ still supported.
+ + Implemented making the SIEVE and NOTIFY capability fully dynamic, meaning
+ that the sieve_extensions setting that was introduced for the new Sieve
+ plugin properly affects the ManageSieve daemon as well.
+ + Added support for the CHECKSCRIPT command. In terms of the supported
+ commands, the ManageSieve daemon now complies with protocol VERSION 1.0 as
+ listed in the CAPABILITY response.
+ - Fixed maximum permissions for uploaded scripts; was 0777. This
+ was shielded however by the default umask (not documented to be
+ configurable), so the actual permissions would never have been 0777.
+ - Fixed a segfault bug in the authentication time-out. Bug report and trace
+ provided by Wolfgang Friebel.
+ - Fixed handling of ~/ in use of mail-data for script location.
+ - Fixed small problems in the login proxy support.
+
+v0.11.2:
+ * Adapted to changes in Dovecot, making this release dependent on Dovecot
+ >= v1.2.alpa4.
+
+v0.11.1:
+ - Fixed security issue that gives virtual users the ability to read and
+ modify each other's scripts if the directory structure of the sieve
+ storage is known.
+ * Updated NOOP command to match new protocol specification
+ + Improved error handling and implemented the new response codes:
+ ACTIVE, NONEXISTENT, ALREADYEXISTS and WARNINGS
+
+v0.11.0:
+ * Upgraded to Dovecot v1.2
+ * Added support for new ManageSieve extensions RENAME and NOOP
+ * Moved sieve settings to plugin {} section of config file. Now the settings
+ `sieve` and `sieve_dir` in the plugin section are used for the Sieve plugin
+ and the ManageSieve service, avoiding the posibility of accidental
+ differences in configuration.
+
+Dovecot 1.1:
+
+v0.10.3
+ * Removed erroneous inline declarations that caused compiler warnings. GCC 4.3
+ turns out to fail entirely as reported by Joel Johnson.
+ * Fixed auto-dectection of Sieve implementation during ./configure. It now
+ produces a proper error when the directory is invalid.
+
+v0.10.2
+ * Fixed bug that caused SASL mechanisms that require more than a single client
+ response to fail. Reported by Steffen Kaiser and occured when he tried using
+ the (obsolete) LOGIN mechanism.
+ * Updated installation and configuration documentation to match the
+ information provided in the wiki
+
+v0.10.1
+ * Fixed bug introduced in v0.10.0: compiled scripts were also written to disk
+ in the sieve/tmp directory and left there. This accumulates much .sievec
+ junk in that directory over time.
+ * Fixed bug in tmp file generation for sieve-storage: errors other than EEXIST
+ would cause the daemon to sleep() loop indefinitely.
+
+ + Improved log lines to be more recognizable as being generated from
+ managesieve.
+ + Added short proxy configuration explanation to the README file
+ + Added 'Known Issues' section to the README file
+ - Fixed assert bug in sieve-storage occurring when save is canceled.
+
+v0.10.0
+ * Upgraded to Dovecot 1.1:
+ - The actual managesieve implementation is now a separate package.
+ The dovecot tree still needs to be patched though to make dovecot
+ recognize the new managesieve service.
+ - Incorporated changes to imap/imap-login into the equivalent
+ managesieve processes.
+ - Removed cmusieve implementation from managesieve sources. It is
+ now linked externally from the dovecot-sieve-1.1 package.
+ - Restructured README.managesieve file into separate README, NEWS,
+ TODO, DESIGN and INSTALL files.
+ * Added support for new libsieve implementation (to be released). This
+ package can be compiled with either the new or the old Sieve
+ implementation (autodetected). If the new Sieve becomes stable, this
+ package will be merged with it to make a single package for Dovecot
+ Sieve support.
+
+Dovecot 1.0:
+
+v9
+
++ Definitively fixed the segfault mentioned in V8. It proved to be
+ very time-constrained and thus hard to reproduce. The error turned out
+ to be related to the input handling of the login daemon during
+ authentication.
++ Checked for changes in the imap daemon that weren't propagated to the
+ managesieve implementation due to code duplication.
++ Fixed a bug in the autodetection of the sieve storage location.
++ Fixed bug in the sieve storage that failed to refresh the symlink if
+ the storage was moved.
++ Improved error handing in the sieve-storage implementation in various
+ places.
++ Fixed the situation in which the active script link is located in the
+ sieve storage.
++ Added managesieve configuration to dovecot-example.conf and made the example
+ in this file more concise.
+
+v8
+
++ Fixed a few incompatibilities with 1.0.7 version. For instance, the "Logged
+ in" message is now sent by the -login process and not by the managesieve
+ daemon anymore. This caused a segfault every once in a while.
++ Probably fixed the settings problem reported by Steffen Kaiser regarding
+ login_dir. 'dovecot -n' now reports correct results, but testing will show
+ whether the whole problem is solved.
++ The managesieve daemon now accepts the sieve_storage and sieve configuration
+ settings, so it is now possible to explicitly configure the location of the
+ sieve storage and the active script respectively. The daemon still falls back
+ to using the mail_location (MAIL) settings if nothing else is specified.
++ The cyrus timsieved does not use the + character in string literals and many
+ clients have adopted to this behaviour. The latest managesieve (08) advises to
+ accept a missing + from clients. The server should not send any + characters
+ as well. This behavior is now implemented on the server.
++ Cleaned up sieve-storage.c: split up the sieve_storage_create function in
+ various sub-functions for obtaining the various paths and directories.
++ Forced manual intervention if rescueing a non-symlink file at the active script
+ path fails somehow. Previously, this presented the admin with a log message
+ that it had just eaten the script, which is not very nice.
++ Restructured the README.managesieve file and added some more explanation with
+ regard to the configuration of the daemon.
+
+v7
+
+- Robin Breathe indicated that the regex capability was missing in the server's
+ SIEVE listing. It turns out I forgot to make arrangements for setting
+ ENABLE_REGEX in the cmu libsieve sources, so the regex extension was not
+ compiled in. I copied the configure.in section regarding ENABLE_REGEX from
+ dovecot-sieve-1.0.2 and that fixed the problem.
+
+v6
+
+- Corked the client output stream while producing the capability greeting and on
+ other some other occasions as well. Some naive client implementations expect to
+ receive this as a single tcp frame and it is a good practice to do so anyway.
+ Using this change the Thunderbird sieve extension (v0.1.1) seemed to work. However,
+ scripts larger than a tcp frame still caused failures. All these issues are fixed
+ in the latest version of the sieve add-on (currently v0.1.4).
+- Cleaned up the new proxy source. My editor made the indentation a complete mess
+ in terms of TABs vs spaces.
+- Added TRYLATER response codes to BYE and NO messages where appropriate.
+- Recopied the libsieve library into this patch to incorporate any changes that were
+ made (only sieve-cmu.c still needs to be compared to the old cmu-sieve.c). This
+ also solves the __attribute__((unused)) GCC dependencies. These were fixed long
+ ago by Timo.... the code duplication beast strikes again.
+- Removed spurious return value from void function in
+ src/lib-sieve/sieve-implementation.c as reported by Robin Breathe. GCC fails to
+ report these issues. The function involved is currently not used and serves only
+ as an example on how dovecot could support multiple sieve backends...
+
+v5
+
+- Applied patch by Uldis Pakuls to fix master_dump_settings bug
+- Added some compilation/installation info to this README
+- Moved README to source tree root as README.managesieve
+- Fixed minor error handling bug in sieve_storage.c with respect to a missing
+ root directory.
+- Now sieve capabilities are reported as they are specified by the implementing
+ library and not in forced upper case. The sieve RFC now explicitly states
+ that sieve capability identifiers are case-sensitive. This broke compatibility
+ with SquirrelMail/Avelsieve.
+- Disabled ANONYMOUS login entirely until proper support is implemented. V4
+ claimed to do so as well, but in fact it only stopped announcing it.
+- Implemented managesieve-proxy. It is not so much a clean copy of imap-proxy,
+ since the managesieve greeting is much more complex and requires parsing.
+ Configuration is identical to imap-proxy. This seems to be a little under-
+ documented however (http://wiki.dovecot.org/PasswordDatabase/ExtraFields).
+
+v4
+
+- Added managesieve_implementation_string setting to the managesieve
+ configuration. This can be used to customize the default "IMPLEMENTATION"
+ capability response.
+- Denied ANONYMOUS login until proper support is implemented
+- Fixed problem with authenticate command regarding continued responses. In
+ V3 only initial response would work. Problem was caused by rc2 -> rc28
+ upgrade. One of the clear reasons why code duplication is a very bad idea.
+- Fixed readlink bug as indicated by Timo: return value of readlink can also
+ be -1.
+- Fixed bug in the regular file rescue code, as introduced in the previous
+ version. Used stat instead of lstat. This caused the symlink to be rescued
+ subsequently in the next activation, thus still overwriting the initially
+ rescued script.
+
+v3
+
+- Updated source to compile with dovecot 1.0.rc27
+- Daemon now uses the same location for .dovecot.sieve as dovecot-lda
+ This is typically ~/.dovecot.sieve
+- If .dovecot.sieve is a regular file, it is now moved into the script storage as
+ dovecot.orig.sieve, preventing deletion of (important) active scripts
+ upon upgrade.
+- Changed error handling to yield a BYE message when the managesieve
+ daemon exits unexpectedly (upon login) before any commands are entered.
+ Horde-ingo would wait indefinitely for a response.
+
+v2
+
+- Fixed the bug (missing CRLF) in the authenticate command
+- Modified the sieve storage library making the interface much less crude.
+- The scripts put on the server using the putscript command are now
+ checked before they are accepted.
+- The reported SIEVE capability is now directly read from the sieve
+ implementation (in this case cmu), listing much more than "FILEINTO
+ VACATION".
+- Imported instance of libsieve source into this patch for implementation
+ of script checking and capability listing. THIS NEEDS TO BE CHANGED!
+- Fixed some minor bugs in the putscript command
diff --git a/pigeonhole/README b/pigeonhole/README
new file mode 100644
index 0000000..ad2ab02
--- /dev/null
+++ b/pigeonhole/README
@@ -0,0 +1,332 @@
+Pigeonhole for Dovecot v2.4
+
+Introduction
+============
+
+This package is part of the Pigeonhole project (http://pigeonhole.dovecot.org).
+It adds support for the Sieve language (RFC 5228) and the ManageSieve protocol
+(RFC 5804) to the Dovecot Secure IMAP Server. In the literal sense, a pigeonhole
+is a a hole or recess inside a dovecot for pigeons to nest in. It is, however,
+also the name for one of a series of small, open compartments in a cabinet used
+for filing or sorting mail. As a verb, it describes the act of putting an item
+into one of those pigeonholes. The name `Pigeonhole' therefore well describes an
+important part of the functionality that this project adds to Dovecot: sorting
+and filing e-mail messages.
+
+The Sieve language is used to specify how e-mail needs to be processed. By
+writing Sieve scripts, users can customize how messages are delivered, e.g.
+whether they are forwarded or stored in special folders. Unwanted messages can
+be discarded or rejected, and, when the user is not available, the Sieve
+interpreter can send an automated reply. Above all, the Sieve language is meant
+to be simple, extensible and system independent. And, unlike most other mail
+filtering script languages, it does not allow users to execute arbitrary
+programs. This is particularly useful to prevent virtual users from having full
+access to the mail store. The intention of the language is to make it impossible
+for users to do anything more complex (and dangerous) than write simple mail
+filters.
+
+Using the ManageSieve protocol, users can upload their Sieve scripts remotely,
+without needing direct filesystem access through FTP or SCP. Additionally, a
+ManageSieve server always makes sure that uploaded scripts are valid, preventing
+compile failures at mail delivery.
+
+This package provides Sieve support as a plugin to Dovecot's Local Delivery
+Agent (LDA) and Dovecot's LMTP service. The ManageSieve protocol is provided is
+an additional service, next to Dovecot's own POP3 and IMAP services.
+
+Features
+========
+
+ * The Pigeonhole Sieve implementation aims to be admin- and user-friendly.
+ Much like Dovecot itself, common error messages are made as easily
+ understandable as possible. Any crash, no matter how it happened, is
+ considered a bug that will be fixed. The compiler does not bail on the first
+ error, but it looks for more script errors to make debugging more efficient.
+
+ * The Pigeonhole Sieve implementation is, much like the Sieve language itself,
+ highly extensible with new Sieve capabilities. This includes support for
+ third-party plugins. It should eventually provide the necessary
+ infrastructure for at least all currently known relevant (proposed) Sieve
+ extensions. The goal is to keep the extension interface provided by the
+ Sieve implementation as generic as possible, i.e. without explicit support
+ for specific extensions. New similar extensions can then use the same
+ interface methods without changes to the Sieve engine code. If an extension
+ is not loaded using the require command, the compiler truly does not know of
+ its existence.
+
+ * The Pigeonhole Sieve plugin is backwards compatible with the old CMUSieve
+ plugin, which provided Sieve support for older versions of Dovecot. All
+ Sieve extensions supported by the old plugin are also supported by the
+ Pigeonhole Sieve plugin, including those that are now considered to be
+ deprecated.
+
+ * The Pigeonhole Sieve implementation supports executing multiple Sieve
+ scripts sequentially. Using this feature it is possible to execute
+ administrator-controlled Sieve scripts before and after the user's personal
+ Sieve script, guaranteeing that responses and message deliveries are never
+ duplicated. This implementation is based on a draft specification
+ (http://tools.ietf.org/html/draft-degener-sieve-multiscript-00), which
+ defines the Sieve behavior when multiple scripts are executed sequentially
+ on the same message.
+
+ * The Pigeonhole Sieve implementation includes a test suite to automatically
+ assess whether the compiled Sieve engine works correctly. The test suite is
+ an extension to the Sieve language and is therefore easily extended with new
+ tests. Currently, the test suite is mostly limited to testing script
+ processing. The performed actions are not tested fully yet.
+
+ * The Pigeonhole Sieve implementation supports the new and very useful
+ variables extension, which allows maintaining state information throughout
+ a Sieve script across subsequent rules.
+
+ * The Pigeonhole Sieve plugin is distributed with a sieve-test tool that
+ simplifies testing Sieve scripts and provides additional debugging
+ facilities.
+
+Sieve Implementation Status
+===========================
+
+The core of the language (as specified in RFC 5228) is fully supported. In
+addition to that, this Sieve implementation features various extensions. The
+following list outlines the implementation status of each supported extension:
+
+ The language extensions defined in the base specification are fully supported:
+
+ encoded-character (RFC 5228; page 10)
+ fileinto (RFC 5228; page 23)
+ envelope (RFC 5228; page 27)
+
+ The following Sieve language extensions are also supported:
+
+ copy (RFC 3894): fully supported.
+ body (RFC 5173): fully supported.
+ environment (RFC 5183): fully supported (v0.4.0+).
+ variables (RFC 5229): fully supported.
+ vacation (RFC 5230): fully supported.
+ + vacation-seconds (RFC 6131): fully supported (v0.2.3+).
+ relational (RFC 5231): fully supported.
+ imap4flags (RFC 5232): fully supported.
+ subaddress (RFC 5233): fully supported, but with limited configurability.
+ spamtest and virustest (RFC 5235): fully supported (v0.1.16+).
+ date (RFC 5260; Section 4): fully supported (v0.1.12+).
+ index (RFC 5260; Section 6): fully supported (v0.4.7+).
+ editheader (RFC 5293): fully supported (v0.3.0+).
+ reject (RFC 5429; Section 2.2): fully supported.
+ enotify (RFC 5435): fully supported (v0.1.3+).
+ mailto method (RFC 5436): fully supported (v0.1.3+).
+ xmpp method (RFC 5437): is under development and will become available
+ as a plugin.
+ ihave (RFC 5463): fully supported (v0.2.4+).
+ mailbox (RFC 5490; Section 3): fully supported (v0.1.10+), but ACL
+ permissions are not verified for mailboxexists.
+ mboxmetadata and servermetadata (RFC 5490): fully supported (v0.4.7+)
+ foreverypart (RFC 5703; Section 3): fully supported (v0.4.10+).
+ mime (RFC 5703; Section 4): fully supported (v0.4.10+).
+ extracttext (RFC 5703; Section 7): fully supported (v0.4.12+).
+ include (RFC 6609): fully supported (v0.4.0+).
+ imapsieve (RFC 6785): fully supported (v0.4.14+).
+ duplicate (RFC 7352): fully supported (v0.4.3+).
+ regex (draft v08; not latest version): almost fully supported, but
+ UTF-8 is not supported.
+
+ The following deprecated extensions are supported for backwards
+ compatibility:
+
+ imapflags (obsolete draft): fully backwards compatible (v0.1.3+)
+ notify (obsolete draft): fully backwards compatible (v0.1.15+)
+
+ The availability of these deprecated extensions is disabled by default.
+
+ The following Dovecot-specific Sieve extensions are available:
+
+ vnd.dovecot.debug (v0.3.0+):
+ Allows logging debug messages.
+ vnd.dovecot.execute (v0.4.0+; sieve_extprograms plugin):
+ Implements executing a pre-defined set of external programs with the
+ option to process string data through the external program.
+ vnd.dovecot.filter (v0.4.0+; sieve_extprograms plugin):
+ Implements filtering messages through a pre-defined set of external
+ programs.
+ vnd.dovecot.pipe (v0.4.0+; sieve_extprograms plugin):
+ Implements piping messages to a pre-defined set of external programs.
+ vnd.dovecot.report (v0.4.14):
+ Implements sending MARF reports (RFC 5965).
+
+ The following extensions are under development:
+
+ ereject (RFC 5429; page 4): implemented, but currently equal to reject.
+
+ Many more extensions to the language exist. Not all of these extensions are
+ useful for Dovecot in particular, but many of them are. Currently, the
+ author has taken notice of the following extensions:
+
+ replace (RFC 5703; Section 5): planned.
+ enclose (RFC 5703; Section 6): planned.
+ envelope-dsn, envelope-deliverby, redirect-dsn and
+ redirect-deliverby (RFC 6009): planned; depends on lib-smtp changes in
+ Dovecot.
+ extlists (RFC 6134): planned.
+ convert (RFC 6558): under consideration.
+
+ These extensions will be added as soon as the necessary infrastructure is
+ available.
+
+Check the TODO file for an up-to-date list of open issues and current
+development.
+
+Compiling and Configuring
+=========================
+
+Refer to INSTALL file.
+
+Sieve Tools
+===========
+
+To test the sieve engine outside deliver, it is useful to try the commands that
+exist in the src/sieve-tools/ directory of this package. After installation,
+these are available at your $prefix/bin directory. The following commands are
+installed:
+
+sievec - Compiles sieve scripts into a binary representation for later
+ execution. Refer to the next section on manually compiling Sieve
+ scripts.
+
+sieve-test - This is a universal Sieve test tool for testing the effect of a
+ Sieve script on a particular message. It allows compiling,
+ running and testing Sieve scripts. It can either be used to
+ display the actions that would be performed on the provided test
+ message or it can be used to test the actual delivery of the
+ message and show the messages that would normally be sent through
+ SMTP.
+
+sieve-dump - Dumps the content of a Sieve binary file for (development)
+ debugging purposes.
+
+sieve-filter - Allow running Sieve filters on messages already stored in a
+ mailbox.
+
+When installed, man pages are also available for these commands. In this package
+the man pages are present in doc/man and can be viewed before install using
+e.g.:
+
+man -l doc/man/sieve-test.1
+
+Various example scripts are bundled in the directory 'examples'. These scripts
+were downloaded from various locations. View the top comment in the scripts for
+url and author information.
+
+Compiling Sieve Scripts
+=======================
+
+When the LDA Sieve plugin executes a script for the first time (or after it has
+been changed), it is compiled into into a binary form. The Pigeonhole Sieve
+implementation uses the .svbin extension to store compiled Sieve scripts (e.g.
+.dovecot.svbin). To store the binary, the plugin needs write access in the
+directory in which the script is located.
+
+A problem occurs when a global script is encountered by the plugin. For security
+reasons, global script directories are not supposed to be writable by the user.
+Therefore, the plugin cannot store the binary when the script is first compiled.
+Note that this doesn't mean that the old compiled version of the script is used
+when the binary cannot be written: it compiles and uses the current script
+version. The only real problem is that the plugin will not be able to update
+the binary on disk, meaning that the global script needs to be recompiled each
+time it needs to be executed, i.e. for every incoming message, which is
+inefficient.
+
+To mitigate this problem, the administrator must manually pre-compile global
+scripts using the sievec command line tool. For example:
+
+sievec /var/lib/dovecot/sieve/global/
+
+This is often necessary for scripts listed in the sieve_default, sieve_before
+and sieve_after settings. For global scripts that are only included in other
+scripts using the include extension, this step is not necessary, since included
+scripts are incorporated into the binary produced for the main script located in
+a user directory.
+
+Compile and Runtime Logging
+===========================
+
+Log messages produced at runtime by the Sieve plugin are written to two
+locations:
+
+ * Messages are primarily logged to the user log. By default this log file is
+ located in the same directory as the user's main active personal script (as
+ specified by the sieve setting). This log file bears the name of that script
+ file appended with ".log", e.g. ".dovecot.sieve.log". The location of the
+ user log file can also be explicitly configured using the sieve_user_log
+ setting (e.g. for when Sieve scripts are not stored on the local file
+ system).
+
+ If there are errors or warnings in the script, the messages are appended to
+ that log file until it eventually grows too large. When that happens, the
+ old log file is rotated to a ".log.0" file and an empty log file is started.
+ Informational messages are not written to this log file and the log file is
+ not created until messages are actually logged, i.e. when an error or
+ warning is produced.
+
+ * Messages that could be of interest to the system administrator are also
+ written to the Dovecot LDA logging facility (usually syslog). This includes
+ informational messages that indicate what actions are executed on incoming
+ messages. Compile errors encountered in the user's private script are not
+ logged here.
+
+The ManageSieve service reports compile errors and warnings only back to the
+user. System and configuration-related messages are written to the Dovecot
+logging facility.
+
+Known issues
+============
+
+Sieve
+-----
+
+Most open issues are outlined in the TODO file. The more generic ones are (re-)
+listed here:
+
+* Compile errors are sometimes a bit obscure and long. This needs work.
+ Suggestions for improvement are welcome.
+
+* The documentation needs work.
+
+ManageSieve
+-----------
+
+* Although this ManageSieve server should comply with the draft specification of
+ the ManageSieve protocol, quite a few clients don't. This is particularly true
+ for the TLS support. However, now that Cyrus' Timsieved has changed its
+ behavior towards protocol compliance, all those clients will follow
+ eventually.
+
+ Clients known to have TLS issues:
+ - Thunderbird Sieve add-on: fixed as per version 0.1.5
+ - AvelSieve: patch on the wiki: http://wiki.dovecot.org/ManageSieve
+ - KMail + kio_sieve: TLS broken for old versions. This issue is fixed at
+ least in kmail 1.9.9 / kde 3.5.9.
+
+ Unfortunately, there is no reliable way to provide a workaround for this
+ problem. We will have to wait for the authors of these clients to make the
+ proper adjustments.
+
+* Other client issues:
+
+ - SmartSieve, WebSieve:
+ These clients are specifically written for Cyrus timsieved and fail on
+ multiple stages of the protocol when connected to Pigeonhole ManageSieve.
+
+Authors
+=======
+
+Refer to AUTHORS file.
+
+Contact Info
+============
+
+Stephan Bosch <stephan at rename-it dot nl>
+IRC: Freenode, #dovecot, S[r]us
+Web: http://pigeonhole.dovecot.org
+
+Please use the Dovecot mailing list <dovecot at dovecot.org> for questions about
+this package. You can post to the list without subscribing, the mail then waits
+in a moderator queue for a while. See http://dovecot.org/mailinglists.html
diff --git a/pigeonhole/TODO b/pigeonhole/TODO
new file mode 100644
index 0000000..39420b5
--- /dev/null
+++ b/pigeonhole/TODO
@@ -0,0 +1,97 @@
+Current activities:
+
+* Rework string matching:
+ - Give Sieve its own runtime string type, rather than (ab)using string_t.
+ - Add support for stream matching for handling large values, e.g. from the
+ body extension.
+ - Improve efficiency of :matches and :contains match types.
+* Build proper comparator support:
+ - Add normalize() method to comparators to normalize the string before
+ matching (for efficiency).
+ - Allow for the existence of dynamic comparators (i.e. specified by
+ variables).
+ - Implement comparator-i;unicode-casemap.
+
+Parallel plugin-based efforts (on hold at the moment):
+
+* Implement enotify xmpp method as a plugin.
+
+Next (mostly in order of descending priority/precedence):
+
+* Implement message modification and extraction API in order to:
+ - Properly implement the interaction between editheader and foreverypart/mime.
+ - Implement replace, enclose extensions.
+* Properly implement Sieve internationalization support (utf-8 handling),
+ currently it is not complete:
+ - Make this implementation fully conform section 2.7.2 of RFC5228 (Comparisons
+ Across Character Sets).
+ - Verify validity of utf8 where necessary.
+* Further develop regex extension and update it to the latest draft:
+ - Implement the :quoteregex set modifier
+ - Investigate the use of the TRE regexp library to gain UTF-8 capability
+ (posix regexes actually do support utf8, but only when locale is set
+ accordingly)
+* Finish LDAP Sieve script storage for read-only access.
+ - Consolidate LDAP connections when more than a single Sieve script must be
+ loaded from different storages linked to the same LDAP server.
+ - Adjust Sieve script API to support asynchronous script retrieval to
+ retrieve scripts in parallel when possible.
+* Improve error handling.
+ - Implement dropping errors in the user's mailbox as a mail message.
+* Finish body extension:
+ - Build test cases for decoding MIME encodings to UTF-8
+* Cleanup the test suite
+ - Restructure test scripts
+ - Add more comment on purpose of tests
+* Finish the ereject extension
+* Vacation extension improvements:
+ - Implement configurable sender exclusion list.
+ - Implement mechanism for implicitly including an account's aliases in the
+ vacation command's :addresses list.
+* Fix remaining RFC deviations:
+ - Fix issues listed in doc/rfc/RFC-questions.txt based on answers
+ - Verify outgoing mail addresses at runtime when necessary
+ (e.g. after variables substitution)
+ - Improve handling of invalid addresses in headers (requires Dovecot changes)
+* Improve sieve_extprograms plugin:
+ - Redesign (forcible) local script termination. It should use SIGCHLD and
+ a ioloop-based timeout.
+ - Add facility to trigger a temporary failure condition when a program
+ fails rather than an implicit keep.
+ - Add a method to implicitly pass environment variables such as SENDER and
+ RECIPIENT through the script socket service.
+* Make testsuite much more exhaustive:
+ - Add support for testing the content of result actions
+ - Test as many error/warning/info conditions as possible.
+ - Review the specification documents and check whether the given requirements
+ are tested at least once.
+* Fix ManageSieve proxy to recognize response codes from the backend and forward
+ them to the user if appropriate/safe. Probably means implementing a proper
+ ManageSieve client library.
+* Test ManageSieve behavior thoroughly:
+ - Test pipelined behavior
+ - Test proxy authentication
+* Code cleanup:
+ - Make address handling more uniform.
+ - Review all FIXMEs
+
+* Build a server with test mail accounts that processes lots and lots of mail
+ (e.g. spam, mailing lists etc.)
+
+Low priority items:
+
+* Implement extlists extension as a plugin
+* Enotify extension: detect use of variable values extracted from the message
+ that are used in the method argument. RFC reports this as a security issue.
+* Provide a solution for mail_get_headers_utf8 reparsing the whole message each
+ time it is called (header and address test; Timo might provide solution from
+ within Dovecot)
+* Warn during compile if using non-existent folders.
+
+* Variables extension: implement compile time evaluation of constant values
+ - Detect assignment of too large constant values to variables at compile
+ time.
+* Add development documentation, i.e. comment on library functions and document
+ the binary and byte-code format.
+* Implement sip-message notify mechanism.
+
diff --git a/pigeonhole/aclocal.m4 b/pigeonhole/aclocal.m4
new file mode 100644
index 0000000..c29cec5
--- /dev/null
+++ b/pigeonhole/aclocal.m4
@@ -0,0 +1,1174 @@
+# generated automatically by aclocal 1.16.3 -*- Autoconf -*-
+
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf. It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# Copyright (C) 2002-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.16'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version. Point them to the right macro.
+m4_if([$1], [1.16.3], [],
+ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too. Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.16.3])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+m4_if([$1], [CC], [depcc="$CC" am_compiler_list=],
+ [$1], [CXX], [depcc="$CXX" am_compiler_list=],
+ [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
+ [$1], [UPC], [depcc="$UPC" am_compiler_list=],
+ [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ am__universal=false
+ m4_case([$1], [CC],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac],
+ [CXX],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac])
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE([dependency-tracking], [dnl
+AS_HELP_STRING(
+ [--enable-dependency-tracking],
+ [do not reject slow dependency extractors])
+AS_HELP_STRING(
+ [--disable-dependency-tracking],
+ [speeds up one-time build])])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+ # Older Autoconf quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ # TODO: see whether this extra hack can be removed once we start
+ # requiring Autoconf 2.70 or later.
+ AS_CASE([$CONFIG_FILES],
+ [*\'*], [eval set x "$CONFIG_FILES"],
+ [*], [set x $CONFIG_FILES])
+ shift
+ # Used to flag and report bootstrapping failures.
+ am_rc=0
+ for am_mf
+ do
+ # Strip MF so we end up with the name of the file.
+ am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile which includes
+ # dependency-tracking related rules and includes.
+ # Grep'ing the whole file directly is not great: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \
+ || continue
+ am_dirpart=`AS_DIRNAME(["$am_mf"])`
+ am_filepart=`AS_BASENAME(["$am_mf"])`
+ AM_RUN_LOG([cd "$am_dirpart" \
+ && sed -e '/# am--include-marker/d' "$am_filepart" \
+ | $MAKE -f - am--depfiles]) || am_rc=$?
+ done
+ if test $am_rc -ne 0; then
+ AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments
+ for automatic dependency tracking. If GNU make was not used, consider
+ re-running the configure script with MAKE="gmake" (or whatever is
+ necessary). You can also try re-running configure with the
+ '--disable-dependency-tracking' option to at least be able to build
+ the package (albeit without support for automatic dependency tracking).])
+ fi
+ AS_UNSET([am_dirpart])
+ AS_UNSET([am_filepart])
+ AS_UNSET([am_mf])
+ AS_UNSET([am_rc])
+ rm -f conftest-deps.mk
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking is enabled.
+# This creates each '.Po' and '.Plo' makefile fragment that we'll need in
+# order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
+m4_define([AC_PROG_CC],
+m4_defn([AC_PROG_CC])
+[_AM_PROG_CC_C_O
+])
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+ [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+ m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+ [ok:ok],,
+ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility. To be removed once Automake 1.9.x
+# dies out for good. For more background, see:
+# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target (and possibly the TAP driver). The
+# system "awk" is bad on some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES([CC])],
+ [m4_define([AC_PROG_CC],
+ m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES([CXX])],
+ [m4_define([AC_PROG_CXX],
+ m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+ [_AM_DEPENDENCIES([OBJC])],
+ [m4_define([AC_PROG_OBJC],
+ m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+ [_AM_DEPENDENCIES([OBJCXX])],
+ [m4_define([AC_PROG_OBJCXX],
+ m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+ [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes. So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+ cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present. This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message. This
+can help us improve future automake versions.
+
+END
+ if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+ echo 'Configuration will proceed anyway, since you have set the' >&2
+ echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+ echo >&2
+ else
+ cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <https://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+ AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
+ fi
+fi
+dnl The trailing newline in this macro's definition is deliberate, for
+dnl backward compatibility and to allow trailing 'dnl'-style comments
+dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
+])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+AC_SUBST([install_sh])])
+
+# Copyright (C) 2003-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAINTAINER_MODE([DEFAULT-MODE])
+# ----------------------------------
+# Control maintainer-specific portions of Makefiles.
+# Default is to disable them, unless 'enable' is passed literally.
+# For symmetry, 'disable' may be passed as well. Anyway, the user
+# can override the default with the --enable/--disable switch.
+AC_DEFUN([AM_MAINTAINER_MODE],
+[m4_case(m4_default([$1], [disable]),
+ [enable], [m4_define([am_maintainer_other], [disable])],
+ [disable], [m4_define([am_maintainer_other], [enable])],
+ [m4_define([am_maintainer_other], [enable])
+ m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
+AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+ dnl maintainer-mode's default is 'disable' unless 'enable' is passed
+ AC_ARG_ENABLE([maintainer-mode],
+ [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode],
+ am_maintainer_other[ make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer])],
+ [USE_MAINTAINER_MODE=$enableval],
+ [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
+ AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+ AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST([MAINT])dnl
+]
+)
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check whether make has an 'include' directive that can support all
+# the idioms we need for our automatic dependency tracking code.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive])
+cat > confinc.mk << 'END'
+am__doit:
+ @echo this is the am__doit target >confinc.out
+.PHONY: am__doit
+END
+am__include="#"
+am__quote=
+# BSD make does it like this.
+echo '.include "confinc.mk" # ignored' > confmf.BSD
+# Other make implementations (GNU, Solaris 10, AIX) do it like this.
+echo 'include confinc.mk # ignored' > confmf.GNU
+_am_result=no
+for s in GNU BSD; do
+ AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out])
+ AS_CASE([$?:`cat confinc.out 2>/dev/null`],
+ ['0:this is the am__doit target'],
+ [AS_CASE([$s],
+ [BSD], [am__include='.include' am__quote='"'],
+ [am__include='include' am__quote=''])])
+ if test "$am__include" != "#"; then
+ _am_result="yes ($s style)"
+ break
+ fi
+done
+rm -f confinc.* confmf.*
+AC_MSG_RESULT([${_am_result}])
+AC_SUBST([am__include])])
+AC_SUBST([am__quote])])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+ MISSING="\${SHELL} '$am_aux_dir/missing'"
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+ am_missing_run="$MISSING "
+else
+ am_missing_run=
+ AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_CC_C_O
+# ---------------
+# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC
+# to automatically call this.
+AC_DEFUN([_AM_PROG_CC_C_O],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+AC_LANG_PUSH([C])dnl
+AC_CACHE_CHECK(
+ [whether $CC understands -c and -o together],
+ [am_cv_prog_cc_c_o],
+ [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
+ # Make sure it works both with $CC and with simple cc.
+ # Following AC_PROG_CC_C_O, we do the test twice because some
+ # compilers refuse to overwrite an existing .o file with -o,
+ # though they will create one.
+ am_cv_prog_cc_c_o=yes
+ for am_i in 1 2; do
+ if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
+ && test -f conftest2.$ac_objext; then
+ : OK
+ else
+ am_cv_prog_cc_c_o=no
+ break
+ fi
+ done
+ rm -f core conftest*
+ unset am_i])
+if test "$am_cv_prog_cc_c_o" != yes; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+AC_LANG_POP([C])])
+
+# For backward compatibility.
+AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+ ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[[\\\"\#\$\&\'\`$am_lf]]*)
+ AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+ *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
+ AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ am_has_slept=no
+ for am_try in 1 2; do
+ echo "timestamp, slept: $am_has_slept" > conftest.file
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+ alias in your environment])
+ fi
+ if test "$[2]" = conftest.file || test $am_try -eq 2; then
+ break
+ fi
+ # Just in case.
+ sleep 1
+ am_has_slept=yes
+ done
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+ ( sleep 1 ) &
+ am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+ [AC_MSG_CHECKING([that generated files are newer than configure])
+ if test -n "$am_sleep_pid"; then
+ # Hide warnings about reused PIDs.
+ wait $am_sleep_pid 2>/dev/null
+ fi
+ AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+ [--enable-silent-rules],
+ [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+ [--disable-silent-rules],
+ [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+ [am_cv_make_support_nested_variables],
+ [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+ dnl Using '$V' instead of '$(V)' breaks IRIX make.
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip". However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility. Yes, it's still used
+# in the wild :-( We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+ [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+ [m4_case([$1],
+ [ustar],
+ [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+ # There is notably a 21 bits limit for the UID and the GID. In fact,
+ # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+ # and bug#13588).
+ am_max_uid=2097151 # 2^21 - 1
+ am_max_gid=$am_max_uid
+ # The $UID and $GID variables are not portable, so we need to resort
+ # to the POSIX-mandated id(1) utility. Errors in the 'id' calls
+ # below are definitely unexpected, so allow the users to see them
+ # (that is, avoid stderr redirection).
+ am_uid=`id -u || echo unknown`
+ am_gid=`id -g || echo unknown`
+ AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+ if test $am_uid -le $am_max_uid; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ _am_tools=none
+ fi
+ AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+ if test $am_gid -le $am_max_gid; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ _am_tools=none
+ fi],
+
+ [pax],
+ [],
+
+ [m4_fatal([Unknown tar format])])
+
+ AC_MSG_CHECKING([how to create a $1 tar archive])
+
+ # Go ahead even if we have the value already cached. We do so because we
+ # need to set the values for the 'am__tar' and 'am__untar' variables.
+ _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+ for _am_tool in $_am_tools; do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar; do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works.
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ AM_RUN_LOG([cat conftest.dir/file])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+ done
+ rm -rf conftest.dir
+
+ AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+ AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([m4/dovecot.m4])
+m4_include([m4/libtool.m4])
+m4_include([m4/ltoptions.m4])
+m4_include([m4/ltsugar.m4])
+m4_include([m4/ltversion.m4])
+m4_include([m4/lt~obsolete.m4])
diff --git a/pigeonhole/compile b/pigeonhole/compile
new file mode 100755
index 0000000..23fcba0
--- /dev/null
+++ b/pigeonhole/compile
@@ -0,0 +1,348 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" "" $nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+ file=$1
+ case $file in
+ / | /[!/]*) # absolute file, and not a UNC file
+ if test -z "$file_conv"; then
+ # lazily determine how to convert abs files
+ case `uname -s` in
+ MINGW*)
+ file_conv=mingw
+ ;;
+ CYGWIN* | MSYS*)
+ file_conv=cygwin
+ ;;
+ *)
+ file_conv=wine
+ ;;
+ esac
+ fi
+ case $file_conv/,$2, in
+ *,$file_conv,*)
+ ;;
+ mingw/*)
+ file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+ ;;
+ cygwin/* | msys/*)
+ file=`cygpath -m "$file" || echo "$file"`
+ ;;
+ wine/*)
+ file=`winepath -w "$file" || echo "$file"`
+ ;;
+ esac
+ ;;
+ esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+ func_file_conv "$1"
+ if test -z "$lib_path"; then
+ lib_path=$file
+ else
+ lib_path="$lib_path;$file"
+ fi
+ linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+ lib=$1
+ found=no
+ save_IFS=$IFS
+ IFS=';'
+ for dir in $lib_path $LIB
+ do
+ IFS=$save_IFS
+ if $shared && test -f "$dir/$lib.dll.lib"; then
+ found=yes
+ lib=$dir/$lib.dll.lib
+ break
+ fi
+ if test -f "$dir/$lib.lib"; then
+ found=yes
+ lib=$dir/$lib.lib
+ break
+ fi
+ if test -f "$dir/lib$lib.a"; then
+ found=yes
+ lib=$dir/lib$lib.a
+ break
+ fi
+ done
+ IFS=$save_IFS
+
+ if test "$found" != yes; then
+ lib=$lib.lib
+ fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+ # Assume a capable shell
+ lib_path=
+ shared=:
+ linker_opts=
+ for arg
+ do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ eat=1
+ case $2 in
+ *.o | *.[oO][bB][jJ])
+ func_file_conv "$2"
+ set x "$@" -Fo"$file"
+ shift
+ ;;
+ *)
+ func_file_conv "$2"
+ set x "$@" -Fe"$file"
+ shift
+ ;;
+ esac
+ ;;
+ -I)
+ eat=1
+ func_file_conv "$2" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -I*)
+ func_file_conv "${1#-I}" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -l)
+ eat=1
+ func_cl_dashl "$2"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -l*)
+ func_cl_dashl "${1#-l}"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -L)
+ eat=1
+ func_cl_dashL "$2"
+ ;;
+ -L*)
+ func_cl_dashL "${1#-L}"
+ ;;
+ -static)
+ shared=false
+ ;;
+ -Wl,*)
+ arg=${1#-Wl,}
+ save_ifs="$IFS"; IFS=','
+ for flag in $arg; do
+ IFS="$save_ifs"
+ linker_opts="$linker_opts $flag"
+ done
+ IFS="$save_ifs"
+ ;;
+ -Xlinker)
+ eat=1
+ linker_opts="$linker_opts $2"
+ ;;
+ -*)
+ set x "$@" "$1"
+ shift
+ ;;
+ *.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+ func_file_conv "$1"
+ set x "$@" -Tp"$file"
+ shift
+ ;;
+ *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+ func_file_conv "$1" mingw
+ set x "$@" "$file"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+ done
+ if test -n "$linker_opts"; then
+ linker_opts="-link$linker_opts"
+ fi
+ exec "$@" $linker_opts
+ exit 1
+}
+
+eat=
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "compile $scriptversion"
+ exit $?
+ ;;
+ cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
+ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
+ func_cl_wrapper "$@" # Doesn't return...
+ ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ # So we strip '-o arg' only if arg is an object.
+ eat=1
+ case $2 in
+ *.o | *.obj)
+ ofile=$2
+ ;;
+ *)
+ set x "$@" -o "$2"
+ shift
+ ;;
+ esac
+ ;;
+ *.c)
+ cfile=$1
+ set x "$@" "$1"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+ # If no '-o' option was seen then we might have been invoked from a
+ # pattern rule where we don't need one. That is ok -- this is a
+ # normal compilation that the losing compiler can handle. If no
+ # '.c' file was seen then we are probably linking. That is also
+ # ok.
+ exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file. Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+ if mkdir "$lockdir" >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+ test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+ test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/pigeonhole/config.guess b/pigeonhole/config.guess
new file mode 100755
index 0000000..f50dcdb
--- /dev/null
+++ b/pigeonhole/config.guess
@@ -0,0 +1,1480 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright 1992-2018 Free Software Foundation, Inc.
+
+timestamp='2018-02-24'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
+#
+# You can get the latest version of this script from:
+# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+#
+# Please send patches to <config-patches@gnu.org>.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Options:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2018 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > "$dummy.c" ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "$UNAME_SYSTEM" in
+Linux|GNU|GNU/*)
+ # If the system lacks a compiler, then just pick glibc.
+ # We could probably try harder.
+ LIBC=gnu
+
+ eval "$set_cc_for_build"
+ cat <<-EOF > "$dummy.c"
+ #include <features.h>
+ #if defined(__UCLIBC__)
+ LIBC=uclibc
+ #elif defined(__dietlibc__)
+ LIBC=dietlibc
+ #else
+ LIBC=gnu
+ #endif
+ EOF
+ eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`"
+
+ # If ldd exists, use it to detect musl libc.
+ if command -v ldd >/dev/null && \
+ ldd --version 2>&1 | grep -q ^musl
+ then
+ LIBC=musl
+ fi
+ ;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+ "/sbin/$sysctl" 2>/dev/null || \
+ "/usr/sbin/$sysctl" 2>/dev/null || \
+ echo unknown)`
+ case "$UNAME_MACHINE_ARCH" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ earmv*)
+ arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+ endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'`
+ machine="${arch}${endian}"-unknown
+ ;;
+ *) machine="$UNAME_MACHINE_ARCH"-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently (or will in the future) and ABI.
+ case "$UNAME_MACHINE_ARCH" in
+ earm*)
+ os=netbsdelf
+ ;;
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval "$set_cc_for_build"
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # Determine ABI tags.
+ case "$UNAME_MACHINE_ARCH" in
+ earm*)
+ expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+ abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "$UNAME_VERSION" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "$machine-${os}${release}${abi}"
+ exit ;;
+ *:Bitrig:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+ echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
+ exit ;;
+ *:LibertyBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+ echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
+ exit ;;
+ *:MidnightBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE"
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE"
+ exit ;;
+ *:SolidBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE"
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd"$UNAME_RELEASE"
+ exit ;;
+ *:MirBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE"
+ exit ;;
+ *:Sortix:*:*)
+ echo "$UNAME_MACHINE"-unknown-sortix
+ exit ;;
+ *:Redox:*:*)
+ echo "$UNAME_MACHINE"-unknown-redox
+ exit ;;
+ mips:OSF1:*.*)
+ echo mips-dec-osf1
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE=alpha ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE=alpha ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE=alpha ;;
+ "EV5 (21164)")
+ UNAME_MACHINE=alphaev5 ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE=alphaev56 ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE=alphapca56 ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE=alphapca57 ;;
+ "EV6 (21264)")
+ UNAME_MACHINE=alphaev6 ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE=alphaev67 ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE=alphaev69 ;;
+ "EV7 (21364)")
+ UNAME_MACHINE=alphaev7 ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE=alphaev79 ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`"
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ exitcode=$?
+ trap '' 0
+ exit $exitcode ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo "$UNAME_MACHINE"-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo "$UNAME_MACHINE"-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix"$UNAME_RELEASE"
+ exit ;;
+ arm*:riscos:*:*|arm*:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux"$UNAME_RELEASE"
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval "$set_cc_for_build"
+ SUN_ARCH=i386
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH=x86_64
+ fi
+ fi
+ echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`"
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos"$UNAME_RELEASE"
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos"$UNAME_RELEASE"
+ ;;
+ sun4)
+ echo sparc-sun-sunos"$UNAME_RELEASE"
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos"$UNAME_RELEASE"
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint"$UNAME_RELEASE"
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint"$UNAME_RELEASE"
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint"$UNAME_RELEASE"
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint"$UNAME_RELEASE"
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint"$UNAME_RELEASE"
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint"$UNAME_RELEASE"
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten"$UNAME_RELEASE"
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten"$UNAME_RELEASE"
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix"$UNAME_RELEASE"
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix"$UNAME_RELEASE"
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix"$UNAME_RELEASE"
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval "$set_cc_for_build"
+ sed 's/^ //' << EOF > "$dummy.c"
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o "$dummy" "$dummy.c" &&
+ dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos"$UNAME_RELEASE"
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ]
+ then
+ if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \
+ [ "$TARGET_BINARY_INTERFACE"x = x ]
+ then
+ echo m88k-dg-dgux"$UNAME_RELEASE"
+ else
+ echo m88k-dg-dguxbcs"$UNAME_RELEASE"
+ fi
+ else
+ echo i586-dg-dgux"$UNAME_RELEASE"
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`"
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+ fi
+ echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV"
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval "$set_cc_for_build"
+ sed 's/^ //' << EOF > "$dummy.c"
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[4567])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/lslpp ] ; then
+ IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+ else
+ IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+ fi
+ echo "$IBM_ARCH"-ibm-aix"$IBM_REV"
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+ case "$UNAME_MACHINE" in
+ 9000/31?) HP_ARCH=m68000 ;;
+ 9000/[34]??) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "$sc_cpu_version" in
+ 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "$sc_kernel_bits" in
+ 32) HP_ARCH=hppa2.0n ;;
+ 64) HP_ARCH=hppa2.0w ;;
+ '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "$HP_ARCH" = "" ]; then
+ eval "$set_cc_for_build"
+ sed 's/^ //' << EOF > "$dummy.c"
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ "$HP_ARCH" = hppa2.0w ]
+ then
+ eval "$set_cc_for_build"
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH=hppa2.0w
+ else
+ HP_ARCH=hppa64
+ fi
+ fi
+ echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux"$HPUX_REV"
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval "$set_cc_for_build"
+ sed 's/^ //' << EOF > "$dummy.c"
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*)
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*)
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo "$UNAME_MACHINE"-unknown-osf1mk
+ else
+ echo "$UNAME_MACHINE"-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE"
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi"$UNAME_RELEASE"
+ exit ;;
+ *:BSD/OS:*:*)
+ echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
+ exit ;;
+ *:FreeBSD:*:*)
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ case "$UNAME_PROCESSOR" in
+ amd64)
+ UNAME_PROCESSOR=x86_64 ;;
+ i386)
+ UNAME_PROCESSOR=i586 ;;
+ esac
+ echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
+ exit ;;
+ i*:CYGWIN*:*)
+ echo "$UNAME_MACHINE"-pc-cygwin
+ exit ;;
+ *:MINGW64*:*)
+ echo "$UNAME_MACHINE"-pc-mingw64
+ exit ;;
+ *:MINGW*:*)
+ echo "$UNAME_MACHINE"-pc-mingw32
+ exit ;;
+ *:MSYS*:*)
+ echo "$UNAME_MACHINE"-pc-msys
+ exit ;;
+ i*:PW*:*)
+ echo "$UNAME_MACHINE"-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case "$UNAME_MACHINE" in
+ x86)
+ echo i586-pc-interix"$UNAME_RELEASE"
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix"$UNAME_RELEASE"
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix"$UNAME_RELEASE"
+ exit ;;
+ esac ;;
+ i*:UWIN*:*)
+ echo "$UNAME_MACHINE"-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`"
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC"
+ exit ;;
+ i*86:Minix:*:*)
+ echo "$UNAME_MACHINE"-pc-minix
+ exit ;;
+ aarch64:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ aarch64_be:Linux:*:*)
+ UNAME_MACHINE=aarch64_be
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ arc:Linux:*:* | arceb:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ arm*:Linux:*:*)
+ eval "$set_cc_for_build"
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ else
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi
+ else
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf
+ fi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ cris:Linux:*:*)
+ echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
+ exit ;;
+ crisv32:Linux:*:*)
+ echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
+ exit ;;
+ e2k:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ frv:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ hexagon:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ i*86:Linux:*:*)
+ echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
+ exit ;;
+ ia64:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ k1om:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ m32r*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ m68*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval "$set_cc_for_build"
+ sed 's/^ //' << EOF > "$dummy.c"
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU'`"
+ test "x$CPU" != x && { echo "$CPU-unknown-linux-$LIBC"; exit; }
+ ;;
+ mips64el:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ openrisc*:Linux:*:*)
+ echo or1k-unknown-linux-"$LIBC"
+ exit ;;
+ or32:Linux:*:* | or1k*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-"$LIBC"
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-"$LIBC"
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
+ PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
+ *) echo hppa-unknown-linux-"$LIBC" ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-"$LIBC"
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-"$LIBC"
+ exit ;;
+ ppc64le:Linux:*:*)
+ echo powerpc64le-unknown-linux-"$LIBC"
+ exit ;;
+ ppcle:Linux:*:*)
+ echo powerpcle-unknown-linux-"$LIBC"
+ exit ;;
+ riscv32:Linux:*:* | riscv64:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo "$UNAME_MACHINE"-ibm-linux-"$LIBC"
+ exit ;;
+ sh64*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ sh*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ tile*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ vax:Linux:*:*)
+ echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
+ exit ;;
+ x86_64:Linux:*:*)
+ if objdump -f /bin/sh | grep -q elf32-x86-64; then
+ echo "$UNAME_MACHINE"-pc-linux-"$LIBC"x32
+ else
+ echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
+ fi
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION"
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo "$UNAME_MACHINE"-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo "$UNAME_MACHINE"-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo "$UNAME_MACHINE"-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo "$UNAME_MACHINE"-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ i*86:*DOS:*:*)
+ echo "$UNAME_MACHINE"-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:*)
+ UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
+ else
+ echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL"
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}"
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL"
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL"
+ else
+ echo "$UNAME_MACHINE"-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configure will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv"$UNAME_RELEASE"
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo "$UNAME_MACHINE"-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo "$UNAME_MACHINE"-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux"$UNAME_RELEASE"
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv"$UNAME_RELEASE"
+ else
+ echo mips-unknown-sysv"$UNAME_RELEASE"
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ x86_64:Haiku:*:*)
+ echo x86_64-unknown-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-ACE:SUPER-UX:*:*)
+ echo sxace-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody"$UNAME_RELEASE"
+ exit ;;
+ *:Rhapsody:*:*)
+ echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE"
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ eval "$set_cc_for_build"
+ if test "$UNAME_PROCESSOR" = unknown ; then
+ UNAME_PROCESSOR=powerpc
+ fi
+ if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then
+ if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ case $UNAME_PROCESSOR in
+ i386) UNAME_PROCESSOR=x86_64 ;;
+ powerpc) UNAME_PROCESSOR=powerpc64 ;;
+ esac
+ fi
+ # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
+ if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_PPC >/dev/null
+ then
+ UNAME_PROCESSOR=powerpc
+ fi
+ fi
+ elif test "$UNAME_PROCESSOR" = i386 ; then
+ # Avoid executing cc on OS X 10.9, as it ships with a stub
+ # that puts up a graphical alert prompting to install
+ # developer tools. Any system running Mac OS X 10.7 or
+ # later (Darwin 11 and later) is required to have a 64-bit
+ # processor. This is not true of the ARM version of Darwin
+ # that Apple uses in portable devices.
+ UNAME_PROCESSOR=x86_64
+ fi
+ echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = x86; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE"
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NEO-*:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSE-*:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSR-*:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSV-*:NONSTOP_KERNEL:*:*)
+ echo nsv-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSX-*:NONSTOP_KERNEL:*:*)
+ echo nsx-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE"
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = 386; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo "$UNAME_MACHINE"-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux"$UNAME_RELEASE"
+ exit ;;
+ *:DragonFly:*:*)
+ echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "$UNAME_MACHINE" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`"
+ exit ;;
+ i*86:rdos:*:*)
+ echo "$UNAME_MACHINE"-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo "$UNAME_MACHINE"-pc-aros
+ exit ;;
+ x86_64:VMkernel:*:*)
+ echo "$UNAME_MACHINE"-unknown-esx
+ exit ;;
+ amd64:Isilon\ OneFS:*:*)
+ echo x86_64-unknown-onefs
+ exit ;;
+esac
+
+echo "$0: unable to guess system type" >&2
+
+case "$UNAME_MACHINE:$UNAME_SYSTEM" in
+ mips:Linux | mips64:Linux)
+ # If we got here on MIPS GNU/Linux, output extra information.
+ cat >&2 <<EOF
+
+NOTE: MIPS GNU/Linux systems require a C compiler to fully recognize
+the system type. Please install a C compiler and try again.
+EOF
+ ;;
+esac
+
+cat >&2 <<EOF
+
+This script (version $timestamp), has failed to recognize the
+operating system you are using. If your script is old, overwrite *all*
+copies of config.guess and config.sub with the latest versions from:
+
+ https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+and
+ https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+If $0 has already been updated, send the following data and any
+information you think might be pertinent to config-patches@gnu.org to
+provide the necessary information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = "$UNAME_MACHINE"
+UNAME_RELEASE = "$UNAME_RELEASE"
+UNAME_SYSTEM = "$UNAME_SYSTEM"
+UNAME_VERSION = "$UNAME_VERSION"
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-functions 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/pigeonhole/config.rpath b/pigeonhole/config.rpath
new file mode 100755
index 0000000..24be79c
--- /dev/null
+++ b/pigeonhole/config.rpath
@@ -0,0 +1,684 @@
+#! /bin/sh
+# Output a system dependent set of variables, describing how to set the
+# run time search path of shared libraries in an executable.
+#
+# Copyright 1996-2020 Free Software Foundation, Inc.
+# Taken from GNU libtool, 2001
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# The first argument passed to this file is the canonical host specification,
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld
+# should be set by the caller.
+#
+# The set of defined variables is at the end of this script.
+
+# Known limitations:
+# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer
+# than 256 bytes, otherwise the compiler driver will dump core. The only
+# known workaround is to choose shorter directory names for the build
+# directory and/or the installation directory.
+
+# All known linkers require a '.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+shrext=.so
+
+host="$1"
+host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+# Code taken from libtool.m4's _LT_CC_BASENAME.
+
+for cc_temp in $CC""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'`
+
+# Code taken from libtool.m4's _LT_COMPILER_PIC.
+
+wl=
+if test "$GCC" = yes; then
+ wl='-Wl,'
+else
+ case "$host_os" in
+ aix*)
+ wl='-Wl,'
+ ;;
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ wl='-Wl,'
+ ;;
+ irix5* | irix6* | nonstopux*)
+ wl='-Wl,'
+ ;;
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ ecc*)
+ wl='-Wl,'
+ ;;
+ icc* | ifort*)
+ wl='-Wl,'
+ ;;
+ lf95*)
+ wl='-Wl,'
+ ;;
+ nagfor*)
+ wl='-Wl,-Wl,,'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ wl='-Wl,'
+ ;;
+ ccc*)
+ wl='-Wl,'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ wl='-Wl,'
+ ;;
+ como)
+ wl='-lopt='
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ F* | *Sun*Fortran*)
+ wl=
+ ;;
+ *Sun\ C*)
+ wl='-Wl,'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ newsos6)
+ ;;
+ *nto* | *qnx*)
+ ;;
+ osf3* | osf4* | osf5*)
+ wl='-Wl,'
+ ;;
+ rdos*)
+ ;;
+ solaris*)
+ case $cc_basename in
+ f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+ wl='-Qoption ld '
+ ;;
+ *)
+ wl='-Wl,'
+ ;;
+ esac
+ ;;
+ sunos4*)
+ wl='-Qoption ld '
+ ;;
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ wl='-Wl,'
+ ;;
+ sysv4*MP*)
+ ;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ wl='-Wl,'
+ ;;
+ unicos*)
+ wl='-Wl,'
+ ;;
+ uts4*)
+ ;;
+ esac
+fi
+
+# Code taken from libtool.m4's _LT_LINKER_SHLIBS.
+
+hardcode_libdir_flag_spec=
+hardcode_libdir_separator=
+hardcode_direct=no
+hardcode_minus_L=no
+
+case "$host_os" in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+esac
+
+ld_shlibs=yes
+if test "$with_gnu_ld" = yes; then
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ # Unlike libtool, we use -rpath here, not --rpath, since the documented
+ # option of GNU ld is called -rpath, not --rpath.
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ case "$host_os" in
+ aix[3-9]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ fi
+ ;;
+ amigaos*)
+ case "$host_cpu" in
+ powerpc)
+ ;;
+ m68k)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+ beos*)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ cygwin* | mingw* | pw32* | cegcc*)
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ haiku*)
+ ;;
+ interix[3-9]*)
+ hardcode_direct=no
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ netbsd*)
+ ;;
+ solaris*)
+ if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs=no
+ ;;
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+ sunos4*)
+ hardcode_direct=yes
+ ;;
+ *)
+ if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ if test "$ld_shlibs" = no; then
+ hardcode_libdir_flag_spec=
+ fi
+else
+ case "$host_os" in
+ aix3*)
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$GCC" = yes; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+ aix[4-9]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ else
+ aix_use_runtimelinking=no
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+ fi
+ hardcode_direct=yes
+ hardcode_libdir_separator=':'
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" && \
+ strings "$collect2name" | grep resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ ;;
+ esac
+ fi
+ # Begin _LT_AC_SYS_LIBPATH_AIX.
+ echo 'int main () { return 0; }' > conftest.c
+ ${CC} ${LDFLAGS} conftest.c -o conftest
+ aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+ if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
+}'`
+ fi
+ if test -z "$aix_libpath"; then
+ aix_libpath="/usr/lib:/lib"
+ fi
+ rm -f conftest.c conftest
+ # End _LT_AC_SYS_LIBPATH_AIX.
+ if test "$aix_use_runtimelinking" = yes; then
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ else
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ fi
+ fi
+ ;;
+ amigaos*)
+ case "$host_cpu" in
+ powerpc)
+ ;;
+ m68k)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+ bsdi[45]*)
+ ;;
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec=' '
+ libext=lib
+ ;;
+ darwin* | rhapsody*)
+ hardcode_direct=no
+ if { case $cc_basename in ifort*) true;; *) test "$GCC" = yes;; esac; }; then
+ :
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ dgux*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ ;;
+ freebsd2.[01]*)
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ ;;
+ freebsd* | dragonfly*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ ;;
+ hpux9*)
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ hpux10*)
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ fi
+ ;;
+ hpux11*)
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct=no
+ ;;
+ *)
+ hardcode_direct=yes
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+ irix5* | irix6* | nonstopux*)
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+ netbsd*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ ;;
+ newsos6)
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+ *nto* | *qnx*)
+ ;;
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ hardcode_direct=yes
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ else
+ case "$host_os" in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ *)
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ osf3*)
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+ osf4* | osf5*)
+ if test "$GCC" = yes; then
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ else
+ # Both cc and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ hardcode_libdir_separator=:
+ ;;
+ solaris*)
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ sunos4*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ ;;
+ sysv4)
+ case $host_vendor in
+ sni)
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ hardcode_direct=no
+ ;;
+ motorola)
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ ;;
+ sysv4.3*)
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ ld_shlibs=yes
+ fi
+ ;;
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ ;;
+ sysv5* | sco3.2v5* | sco5v6*)
+ hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+ hardcode_libdir_separator=':'
+ ;;
+ uts4*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ ;;
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+fi
+
+# Check dynamic linker characteristics
+# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER.
+# Unlike libtool.m4, here we don't care about _all_ names of the library, but
+# only about the one the linker finds when passed -lNAME. This is the last
+# element of library_names_spec in libtool.m4, or possibly two of them if the
+# linker has special search rules.
+library_names_spec= # the last element of library_names_spec in libtool.m4
+libname_spec='lib$name'
+case "$host_os" in
+ aix3*)
+ library_names_spec='$libname.a'
+ ;;
+ aix[4-9]*)
+ library_names_spec='$libname$shrext'
+ ;;
+ amigaos*)
+ case "$host_cpu" in
+ powerpc*)
+ library_names_spec='$libname$shrext' ;;
+ m68k)
+ library_names_spec='$libname.a' ;;
+ esac
+ ;;
+ beos*)
+ library_names_spec='$libname$shrext'
+ ;;
+ bsdi[45]*)
+ library_names_spec='$libname$shrext'
+ ;;
+ cygwin* | mingw* | pw32* | cegcc*)
+ shrext=.dll
+ library_names_spec='$libname.dll.a $libname.lib'
+ ;;
+ darwin* | rhapsody*)
+ shrext=.dylib
+ library_names_spec='$libname$shrext'
+ ;;
+ dgux*)
+ library_names_spec='$libname$shrext'
+ ;;
+ freebsd[23].*)
+ library_names_spec='$libname$shrext$versuffix'
+ ;;
+ freebsd* | dragonfly*)
+ library_names_spec='$libname$shrext'
+ ;;
+ gnu*)
+ library_names_spec='$libname$shrext'
+ ;;
+ haiku*)
+ library_names_spec='$libname$shrext'
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $host_cpu in
+ ia64*)
+ shrext=.so
+ ;;
+ hppa*64*)
+ shrext=.sl
+ ;;
+ *)
+ shrext=.sl
+ ;;
+ esac
+ library_names_spec='$libname$shrext'
+ ;;
+ interix[3-9]*)
+ library_names_spec='$libname$shrext'
+ ;;
+ irix5* | irix6* | nonstopux*)
+ library_names_spec='$libname$shrext'
+ case "$host_os" in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;;
+ *) libsuff= shlibsuff= ;;
+ esac
+ ;;
+ esac
+ ;;
+ linux*oldld* | linux*aout* | linux*coff*)
+ ;;
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ library_names_spec='$libname$shrext'
+ ;;
+ knetbsd*-gnu)
+ library_names_spec='$libname$shrext'
+ ;;
+ netbsd*)
+ library_names_spec='$libname$shrext'
+ ;;
+ newsos6)
+ library_names_spec='$libname$shrext'
+ ;;
+ *nto* | *qnx*)
+ library_names_spec='$libname$shrext'
+ ;;
+ openbsd*)
+ library_names_spec='$libname$shrext$versuffix'
+ ;;
+ os2*)
+ libname_spec='$name'
+ shrext=.dll
+ library_names_spec='$libname.a'
+ ;;
+ osf3* | osf4* | osf5*)
+ library_names_spec='$libname$shrext'
+ ;;
+ rdos*)
+ ;;
+ solaris*)
+ library_names_spec='$libname$shrext'
+ ;;
+ sunos4*)
+ library_names_spec='$libname$shrext$versuffix'
+ ;;
+ sysv4 | sysv4.3*)
+ library_names_spec='$libname$shrext'
+ ;;
+ sysv4*MP*)
+ library_names_spec='$libname$shrext'
+ ;;
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ library_names_spec='$libname$shrext'
+ ;;
+ tpf*)
+ library_names_spec='$libname$shrext'
+ ;;
+ uts4*)
+ library_names_spec='$libname$shrext'
+ ;;
+esac
+
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"`
+shlibext=`echo "$shrext" | sed -e 's,^\.,,'`
+escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
+escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
+escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
+
+LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF
+
+# How to pass a linker flag through the compiler.
+wl="$escaped_wl"
+
+# Static library suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally "so").
+shlibext="$shlibext"
+
+# Format of library name prefix.
+libname_spec="$escaped_libname_spec"
+
+# Library names that the linker finds when passed -lNAME.
+library_names_spec="$escaped_library_names_spec"
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec"
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator="$hardcode_libdir_separator"
+
+# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct="$hardcode_direct"
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L="$hardcode_minus_L"
+
+EOF
diff --git a/pigeonhole/config.sub b/pigeonhole/config.sub
new file mode 100755
index 0000000..1d8e98b
--- /dev/null
+++ b/pigeonhole/config.sub
@@ -0,0 +1,1801 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright 1992-2018 Free Software Foundation, Inc.
+
+timestamp='2018-02-22'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
+
+Canonicalize a configuration name.
+
+Options:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2018 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo "$1"
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
+ kopensolaris*-gnu* | cloudabi*-eabi* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ android-linux)
+ os=-linux-android
+ basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+ ;;
+ *)
+ basic_machine=`echo "$1" | sed 's/-[^-]*$//'`
+ if [ "$basic_machine" != "$1" ]
+ then os=`echo "$1" | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray | -microblaze*)
+ os=
+ basic_machine=$1
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*178)
+ os=-lynxos178
+ ;;
+ -lynx*5)
+ os=-lynxos5
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | aarch64 | aarch64_be \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arceb \
+ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+ | avr | avr32 \
+ | ba \
+ | be32 | be64 \
+ | bfin \
+ | c4x | c8051 | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | e2k | epiphany \
+ | fido | fr30 | frv | ft32 \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
+ | i370 | i860 | i960 | ia16 | ia64 \
+ | ip2k | iq2000 \
+ | k1om \
+ | le32 | le64 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa32r6 | mipsisa32r6el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64r6 | mipsisa64r6el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipsr5900 | mipsr5900el \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nds32 | nds32le | nds32be \
+ | nios | nios2 | nios2eb | nios2el \
+ | ns16k | ns32k \
+ | open8 | or1k | or1knd | or32 \
+ | pdp10 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle \
+ | pru \
+ | pyramid \
+ | riscv32 | riscv64 \
+ | rl78 | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu \
+ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+ | visium \
+ | wasm32 \
+ | x86 | xc16x | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+ c54x)
+ basic_machine=tic54x-unknown
+ ;;
+ c55x)
+ basic_machine=tic55x-unknown
+ ;;
+ c6x)
+ basic_machine=tic6x-unknown
+ ;;
+ leon|leon[3-9])
+ basic_machine=sparc-$basic_machine
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ strongarm | thumb | xscale)
+ basic_machine=arm-unknown
+ ;;
+ xgate)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ xscaleeb)
+ basic_machine=armeb-unknown
+ ;;
+
+ xscaleel)
+ basic_machine=armel-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | aarch64-* | aarch64_be-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | ba-* \
+ | be32-* | be64-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* \
+ | c8051-* | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | e2k-* | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | hexagon-* \
+ | i*86-* | i860-* | i960-* | ia16-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | k1om-* \
+ | le32-* | le64-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+ | microblaze-* | microblazeel-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa32r6-* | mipsisa32r6el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64r6-* | mipsisa64r6el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipsr5900-* | mipsr5900el-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nds32-* | nds32le-* | nds32be-* \
+ | nios-* | nios2-* | nios2eb-* | nios2el-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | open8-* \
+ | or1k*-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+ | pru-* \
+ | pyramid-* \
+ | riscv32-* | riscv64-* \
+ | rl78-* | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
+ | tahoe-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tile*-* \
+ | tron-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+ | vax-* \
+ | visium-* \
+ | wasm32-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-pc
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ asmjs)
+ basic_machine=asmjs-unknown
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c54x-*)
+ basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ c55x-*)
+ basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ c6x-*)
+ basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16 | cr16-*)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2*)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ e500v[12])
+ basic_machine=powerpc-unknown
+ os=$os"spe"
+ ;;
+ e500v[12]-*)
+ basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ os=$os"spe"
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+ i*86v32)
+ basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ leon-*|leon[3-9]-*)
+ basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'`
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ microblaze*)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw64)
+ basic_machine=x86_64-pc
+ os=-mingw64
+ ;;
+ mingw32)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ moxiebox)
+ basic_machine=moxie-unknown
+ os=-moxiebox
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'`
+ ;;
+ msys)
+ basic_machine=i686-pc
+ os=-msys
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ nacl)
+ basic_machine=le32-unknown
+ os=-nacl
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next)
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ neo-tandem)
+ basic_machine=neo-tandem
+ ;;
+ nse-tandem)
+ basic_machine=nse-tandem
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ nsv-tandem)
+ basic_machine=nsv-tandem
+ ;;
+ nsx-tandem)
+ basic_machine=nsx-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc | ppcbe) basic_machine=powerpc-unknown
+ ;;
+ ppc-* | ppcbe-*)
+ basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos | rdos64)
+ basic_machine=x86_64-pc
+ os=-rdos
+ ;;
+ rdos32)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ strongarm-* | thumb-*)
+ basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tile*)
+ basic_machine=$basic_machine-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ x64)
+ basic_machine=x86_64-pc
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ xscale-* | xscalee[bl]-*)
+ basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'`
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases that might get confused
+ # with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # es1800 is here to avoid being matched by es* (a different OS)
+ -es1800*)
+ os=-ose
+ ;;
+ # Now accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST end in a * to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* | -plan9* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* | -cloudabi* | -sortix* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \
+ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+ | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
+ | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme* \
+ | -midnightbsd*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -xray | -os68k* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo "$os" | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2)
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -pikeos*)
+ # Until real need of OS specific support for
+ # particular features comes up, bare metal
+ # configurations are quite functional.
+ case $basic_machine in
+ arm*)
+ os=-eabi
+ ;;
+ *)
+ os=-elf
+ ;;
+ esac
+ ;;
+ -nacl*)
+ ;;
+ -ios)
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ c8051-*)
+ os=-elf
+ ;;
+ hexagon-*)
+ os=-elf
+ ;;
+ tic54x-*)
+ os=-coff
+ ;;
+ tic55x-*)
+ os=-coff
+ ;;
+ tic6x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ pru-*)
+ os=-elf
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next)
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo "$basic_machine$os"
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-functions 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/pigeonhole/configure b/pigeonhole/configure
new file mode 100755
index 0000000..7c1f0ff
--- /dev/null
+++ b/pigeonhole/configure
@@ -0,0 +1,16069 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for Pigeonhole 0.5.21.
+#
+# Report bugs to <dovecot@dovecot.org>.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+
+ test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+ PATH=/empty FPATH=/empty; export PATH FPATH
+ test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org and
+$0: dovecot@dovecot.org about your system, including any
+$0: error possibly output before this message. Then install
+$0: a modern shell, or manually run the script under such a
+$0: shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='Pigeonhole'
+PACKAGE_TARNAME='dovecot-2.3-pigeonhole'
+PACKAGE_VERSION='0.5.21'
+PACKAGE_STRING='Pigeonhole 0.5.21'
+PACKAGE_BUGREPORT='dovecot@dovecot.org'
+PACKAGE_URL=''
+
+ac_unique_file="src"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+LDAP_PLUGIN_FALSE
+LDAP_PLUGIN_TRUE
+LDAP_LIBS
+BUILD_MANAGESIEVE_FALSE
+BUILD_MANAGESIEVE_TRUE
+BUILD_DOCS_FALSE
+BUILD_DOCS_TRUE
+BUILD_UNFINISHED_FALSE
+BUILD_UNFINISHED_TRUE
+sieve_docdir
+BINARY_LDFLAGS
+BINARY_CFLAGS
+moduledir
+RUN_TEST
+VALGRIND
+DOVECOT_PLUGIN_DEPS_FALSE
+DOVECOT_PLUGIN_DEPS_TRUE
+DOVECOT_INSTALLED_FALSE
+DOVECOT_INSTALLED_TRUE
+LIBDOVECOT_LUA_DEPS
+LIBDOVECOT_LUA
+DOVECOT_LUA_CFLAGS
+DOVECOT_LUA_LIBS
+LIBDOVECOT_LUA_INCLUDE
+LIBDOVECOT_LIBFTS_INCLUDE
+LIBDOVECOT_ACL_INCLUDE
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE
+LIBDOVECOT_NOTIFY_INCLUDE
+LIBDOVECOT_FTS_INCLUDE
+LIBDOVECOT_IMAPC_INCLUDE
+LIBDOVECOT_DSYNC_INCLUDE
+LIBDOVECOT_LMTP_INCLUDE
+LIBDOVECOT_SUBMISSION_INCLUDE
+LIBDOVECOT_POP3_INCLUDE
+LIBDOVECOT_IMAP_INCLUDE
+LIBDOVECOT_CONFIG_INCLUDE
+LIBDOVECOT_IMAP_LOGIN_INCLUDE
+LIBDOVECOT_SQL_INCLUDE
+LIBDOVECOT_LOGIN_INCLUDE
+LIBDOVECOT_STORAGE_INCLUDE
+LIBDOVECOT_SERVICE_INCLUDE
+LIBDOVECOT_DOVEADM_INCLUDE
+LIBDOVECOT_AUTH_INCLUDE
+LIBDOVECOT_LDA_INCLUDE
+LIBDOVECOT_INCLUDE
+LIBDOVECOT_LIBFTS_DEPS
+LIBDOVECOT_DSYNC_DEPS
+LIBDOVECOT_STORAGE_DEPS
+LIBDOVECOT_LDA_DEPS
+LIBDOVECOT_COMPRESS_DEPS
+LIBDOVECOT_SSL_DEPS
+LIBDOVECOT_SQL_DEPS
+LIBDOVECOT_LOGIN_DEPS
+LIBDOVECOT_DEPS
+LIBDOVECOT_LIBFTS
+LIBDOVECOT_DSYNC
+LIBDOVECOT_STORAGE
+LIBDOVECOT_LDA
+LIBDOVECOT_COMPRESS
+LIBDOVECOT_SSL
+LIBDOVECOT_SQL
+LIBDOVECOT_LOGIN
+LIBDOVECOT
+DOVECOT_BINARY_LDFLAGS
+DOVECOT_BINARY_CFLAGS
+DOVECOT_COMPRESS_LIBS
+DOVECOT_SQL_LIBS
+DOVECOT_SSL_LIBS
+DOVECOT_LIBS
+DOVECOT_CFLAGS
+DOVECOT_INSTALLED
+dovecot_statedir
+dovecot_docdir
+dovecot_pkglibdir
+dovecot_pkglibexecdir
+dovecot_pkgincludedir
+dovecot_installed_moduledir
+dovecot_moduledir
+dovecotdir
+DISTCHECK_CONFIGURE_FLAGS
+RELRO_LDFLAGS
+PIE_LDFLAGS
+PIE_CFLAGS
+LT_SYS_LIBRARY_PATH
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+MANIFEST_TOOL
+RANLIB
+ac_ct_AR
+AR
+DLLTOOL
+OBJDUMP
+LN_S
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LD
+FGREP
+EGREP
+GREP
+SED
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+LIBTOOL
+CPP
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+am__nodep
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+MAINT
+MAINTAINER_MODE_FALSE
+MAINTAINER_MODE_TRUE
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+AM_DEFAULT_V
+AM_V
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL
+am__quote'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_silent_rules
+enable_maintainer_mode
+enable_dependency_tracking
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+with_aix_soname
+with_gnu_ld
+with_sysroot
+enable_libtool_lock
+with_dovecot
+with_dovecot_install_dirs
+enable_hardening
+with_retpoline
+enable_ubsan
+with_moduledir
+with_unfinished_features
+with_docs
+with_managesieve
+with_ldap
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+LT_SYS_LIBRARY_PATH
+VALGRIND'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures Pigeonhole 0.5.21 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root
+ [DATAROOTDIR/doc/dovecot-2.3-pigeonhole]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of Pigeonhole 0.5.21:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-silent-rules less verbose build output (undo: "make V=1")
+ --disable-silent-rules verbose build output (undo: "make V=0")
+ --enable-maintainer-mode
+ enable make rules and dependencies not useful (and
+ sometimes confusing) to the casual installer
+ --enable-dependency-tracking
+ do not reject slow dependency extractors
+ --disable-dependency-tracking
+ speeds up one-time build
+ --enable-shared[=PKGS] build shared libraries [default=yes]
+ --enable-static[=PKGS] build static libraries [default=yes]
+ --enable-fast-install[=PKGS]
+ optimize for fast installation [default=yes]
+ --disable-libtool-lock avoid locking (might break parallel builds)
+ --enable-hardening=yes Enable various hardenings (default: yes)
+ --enable-ubsan Enable undefined behaviour sanitizes (default=no)
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use
+ both]
+ --with-aix-soname=aix|svr4|both
+ shared library versioning (aka "SONAME") variant to
+ provide on AIX, [default=aix].
+ --with-gnu-ld assume the C compiler uses GNU ld [default=no]
+ --with-sysroot[=DIR] Search for dependent libraries within DIR (or the
+ compiler's sysroot if not specified).
+ --with-dovecot=DIR Dovecot base directory
+ --with-dovecot-install-dirs
+ Use install directories configured for Dovecot
+ (default)
+ --with-retpoline=<choice>
+ Retpoline mitigation choice (default: keep)
+ --with-moduledir=DIR Base directory for dynamically loadable modules
+ --with-unfinished-features
+ Build unfinished new features/extensions
+ [default=no]
+ --with-docs Install documentation (default)
+ --with-managesieve Build ManageSieve service [default=yes]
+ --with-ldap=yes|plugin Build with LDAP support
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+ LT_SYS_LIBRARY_PATH
+ User-defined run-time library search path.
+ VALGRIND Path to valgrind
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <dovecot@dovecot.org>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+Pigeonhole configure 0.5.21
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval \${$3+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( $as_echo "## ---------------------------------- ##
+## Report this to dovecot@dovecot.org ##
+## ---------------------------------- ##"
+ ) | sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by Pigeonhole $as_me 0.5.21, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define PIGEONHOLE_ABI_VERSION "0.5.ABIv21($PACKAGE_VERSION)"
+_ACEOF
+
+
+ac_aux_dir=
+for ac_dir in . "$srcdir"/.; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in . \"$srcdir\"/." "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+
+
+
+# Autoheader is not needed and does more harm than good for this package. However, it is
+# tightly integrated in autoconf/automake and therefore it is difficult not to use it. As
+# a workaround we give autoheader a dummy config header to chew on and we handle the
+# real config header ourselves.
+ac_config_headers="$ac_config_headers dummy-config.h pigeonhole-config.h"
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define PIGEONHOLE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PIGEONHOLE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+am__api_version='1.16'
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+ ./ | .// | /[cC]/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ rm -rf conftest.one conftest.two conftest.dir
+ echo one > conftest.one
+ echo two > conftest.two
+ mkdir conftest.dir
+ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ test -s conftest.one && test -s conftest.two &&
+ test -s conftest.dir/conftest.one &&
+ test -s conftest.dir/conftest.two
+ then
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+
+ done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ INSTALL=$ac_install_sh
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[\\\"\#\$\&\'\`$am_lf]*)
+ as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+ *[\\\"\#\$\&\'\`$am_lf\ \ ]*)
+ as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ am_has_slept=no
+ for am_try in 1 2; do
+ echo "timestamp, slept: $am_has_slept" > conftest.file
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ as_fn_error $? "ls -t appears to fail. Make sure there is not a broken
+ alias in your environment" "$LINENO" 5
+ fi
+ if test "$2" = conftest.file || test $am_try -eq 2; then
+ break
+ fi
+ # Just in case.
+ sleep 1
+ am_has_slept=yes
+ done
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+ ( sleep 1 ) &
+ am_sleep_pid=$!
+fi
+
+rm -f conftest.file
+
+test "$program_prefix" != NONE &&
+ program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+
+if test x"${MISSING+set}" != xset; then
+ MISSING="\${SHELL} '$am_aux_dir/missing'"
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+ am_missing_run="$MISSING "
+else
+ am_missing_run=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip". However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+ if ${ac_cv_path_mkdir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in mkdir gmkdir; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
+ case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+ 'mkdir (GNU coreutils) '* | \
+ 'mkdir (coreutils) '* | \
+ 'mkdir (fileutils) '4.1*)
+ ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+ break 3;;
+ esac
+ done
+ done
+ done
+IFS=$as_save_IFS
+
+fi
+
+ test -d ./--version && rmdir ./--version
+ if test "${ac_cv_path_mkdir+set}" = set; then
+ MKDIR_P="$ac_cv_path_mkdir -p"
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for MKDIR_P within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ MKDIR_P="$ac_install_sh -d"
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AWK="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+ enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=1;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ am__isrc=' -I$(srcdir)'
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='dovecot-2.3-pigeonhole'
+ VERSION='0.5.21'
+
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# For better backward compatibility. To be removed once Automake 1.9.x
+# dies out for good. For more background, see:
+# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+mkdir_p='$(MKDIR_P)'
+
+# We need awk for the "check" target (and possibly the TAP driver). The
+# system "awk" is bad on some platforms.
+# Always define AMTAR for backward compatibility. Yes, it's still used
+# in the wild :-( We should find a proper way to deprecate it ...
+AMTAR='$${TAR-tar}'
+
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar plaintar pax cpio none'
+
+# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+ # There is notably a 21 bits limit for the UID and the GID. In fact,
+ # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+ # and bug#13588).
+ am_max_uid=2097151 # 2^21 - 1
+ am_max_gid=$am_max_uid
+ # The $UID and $GID variables are not portable, so we need to resort
+ # to the POSIX-mandated id(1) utility. Errors in the 'id' calls
+ # below are definitely unexpected, so allow the users to see them
+ # (that is, avoid stderr redirection).
+ am_uid=`id -u || echo unknown`
+ am_gid=`id -g || echo unknown`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether UID '$am_uid' is supported by ustar format" >&5
+$as_echo_n "checking whether UID '$am_uid' is supported by ustar format... " >&6; }
+ if test $am_uid -le $am_max_uid; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ _am_tools=none
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether GID '$am_gid' is supported by ustar format" >&5
+$as_echo_n "checking whether GID '$am_gid' is supported by ustar format... " >&6; }
+ if test $am_gid -le $am_max_gid; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ _am_tools=none
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to create a ustar tar archive" >&5
+$as_echo_n "checking how to create a ustar tar archive... " >&6; }
+
+ # Go ahead even if we have the value already cached. We do so because we
+ # need to set the values for the 'am__tar' and 'am__untar' variables.
+ _am_tools=${am_cv_prog_tar_ustar-$_am_tools}
+
+ for _am_tool in $_am_tools; do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar; do
+ { echo "$as_me:$LINENO: $_am_tar --version" >&5
+ ($_am_tar --version) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && break
+ done
+ am__tar="$_am_tar --format=ustar -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=ustar -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x ustar -w "$$tardir"'
+ am__tar_='pax -L -x ustar -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H ustar -L'
+ am__tar_='find "$tardir" -print | cpio -o -H ustar -L'
+ am__untar='cpio -i -H ustar -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_ustar}" && break
+
+ # tar/untar a dummy directory, and stop if the command works.
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5
+ (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ { echo "$as_me:$LINENO: $am__untar <conftest.tar" >&5
+ ($am__untar <conftest.tar) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ { echo "$as_me:$LINENO: cat conftest.dir/file" >&5
+ (cat conftest.dir/file) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+ done
+ rm -rf conftest.dir
+
+ if ${am_cv_prog_tar_ustar+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ am_cv_prog_tar_ustar=$_am_tool
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5
+$as_echo "$am_cv_prog_tar_ustar" >&6; }
+
+
+
+
+
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes. So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+ cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present. This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message. This
+can help us improve future automake versions.
+
+END
+ if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+ echo 'Configuration will proceed anyway, since you have set the' >&2
+ echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+ echo >&2
+ else
+ cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <https://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+ as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
+ fi
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5
+$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; }
+ # Check whether --enable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then :
+ enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval
+else
+ USE_MAINTAINER_MODE=no
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5
+$as_echo "$USE_MAINTAINER_MODE" >&6; }
+ if test $USE_MAINTAINER_MODE = yes; then
+ MAINTAINER_MODE_TRUE=
+ MAINTAINER_MODE_FALSE='#'
+else
+ MAINTAINER_MODE_TRUE='#'
+ MAINTAINER_MODE_FALSE=
+fi
+
+ MAINT=$MAINTAINER_MODE_TRUE
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
+if ${am_cv_prog_cc_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ # Make sure it works both with $CC and with simple cc.
+ # Following AC_PROG_CC_C_O, we do the test twice because some
+ # compilers refuse to overwrite an existing .o file with -o,
+ # though they will create one.
+ am_cv_prog_cc_c_o=yes
+ for am_i in 1 2; do
+ if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
+ ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } \
+ && test -f conftest2.$ac_objext; then
+ : OK
+ else
+ am_cv_prog_cc_c_o=no
+ break
+ fi
+ done
+ rm -f core conftest*
+ unset am_i
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
+$as_echo "$am_cv_prog_cc_c_o" >&6; }
+if test "$am_cv_prog_cc_c_o" != yes; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5
+$as_echo_n "checking whether ${MAKE-make} supports the include directive... " >&6; }
+cat > confinc.mk << 'END'
+am__doit:
+ @echo this is the am__doit target >confinc.out
+.PHONY: am__doit
+END
+am__include="#"
+am__quote=
+# BSD make does it like this.
+echo '.include "confinc.mk" # ignored' > confmf.BSD
+# Other make implementations (GNU, Solaris 10, AIX) do it like this.
+echo 'include confinc.mk # ignored' > confmf.GNU
+_am_result=no
+for s in GNU BSD; do
+ { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5
+ (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ case $?:`cat confinc.out 2>/dev/null` in #(
+ '0:this is the am__doit target') :
+ case $s in #(
+ BSD) :
+ am__include='.include' am__quote='"' ;; #(
+ *) :
+ am__include='include' am__quote='' ;;
+esac ;; #(
+ *) :
+ ;;
+esac
+ if test "$am__include" != "#"; then
+ _am_result="yes ($s style)"
+ break
+ fi
+done
+rm -f confinc.* confmf.*
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5
+$as_echo "${_am_result}" >&6; }
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+ enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+
+depcc="$CC" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+case `pwd` in
+ *\ * | *\ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.4.6'
+macro_revision='2.4.6'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain=$ac_aux_dir/ltmain.sh
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO ""
+}
+
+case $ECHO in
+ printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+ print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+ *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for ac_i in 1 2 3 4 5 6 7; do
+ ac_script="$ac_script$as_nl$ac_script"
+ done
+ echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+ { ac_script=; unset ac_script;}
+ if test -z "$SED"; then
+ ac_path_SED_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+ # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+ ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo '' >> "conftest.nl"
+ "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_SED_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_SED="$ac_path_SED"
+ ac_path_SED_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_SED_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_SED"; then
+ as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+ fi
+else
+ ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+ rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if ${ac_cv_path_FGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+ then ac_cv_path_FGREP="$GREP -F"
+ else
+ if test -z "$FGREP"; then
+ ac_path_FGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in fgrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_FGREP" || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+ # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'FGREP' >> "conftest.nl"
+ "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_FGREP="$ac_path_FGREP"
+ ac_path_FGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_FGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_FGREP"; then
+ as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_FGREP=$FGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+ withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test yes = "$GCC"; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return, which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD=$ac_prog
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test yes = "$with_gnu_ld"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD=$ac_dir/$ac_prog
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test no != "$with_gnu_ld" && break
+ ;;
+ *)
+ test yes != "$with_gnu_ld" && break
+ ;;
+ esac
+ fi
+ done
+ IFS=$lt_save_ifs
+else
+ lt_cv_path_LD=$LD # Let the user override the test with a path.
+fi
+fi
+
+LD=$lt_cv_path_LD
+if test -n "$LD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if ${lt_cv_path_NM+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM=$NM
+else
+ lt_nm_to_check=${ac_tool_prefix}nm
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm=$ac_dir/$lt_tmp_nm
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the 'sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
+ case $build_os in
+ mingw*) lt_bad_file=conftest.nm/nofile ;;
+ *) lt_bad_file=/dev/null ;;
+ esac
+ case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+ *$lt_bad_file* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break 2
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break 2
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS=$lt_save_ifs
+ done
+ : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test no != "$lt_cv_path_NM"; then
+ NM=$lt_cv_path_NM
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$DUMPBIN"; then :
+ # Let the user override the test.
+ else
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in dumpbin "link -dump"
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DUMPBIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DUMPBIN"; then
+ ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$DUMPBIN" && break
+ done
+fi
+if test -z "$DUMPBIN"; then
+ ac_ct_DUMPBIN=$DUMPBIN
+ for ac_prog in dumpbin "link -dump"
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DUMPBIN"; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_DUMPBIN" && break
+done
+
+ if test "x$ac_ct_DUMPBIN" = x; then
+ DUMPBIN=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DUMPBIN=$ac_ct_DUMPBIN
+ fi
+fi
+
+ case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
+ *COFF*)
+ DUMPBIN="$DUMPBIN -symbols -headers"
+ ;;
+ *)
+ DUMPBIN=:
+ ;;
+ esac
+ fi
+
+ if test : != "$DUMPBIN"; then
+ NM=$DUMPBIN
+ fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if ${lt_cv_nm_interface+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+ cat conftest.out >&5
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if ${lt_cv_sys_max_cmd_len+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ i=0
+ teststring=ABCD
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ os2*)
+ # The test takes a long time on OS/2.
+ lt_cv_sys_max_cmd_len=8192
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len" && \
+ test undefined != "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test X`env echo "$teststring$teststring" 2>/dev/null` \
+ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+ test 17 != "$i" # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+
+fi
+
+if test -n "$lt_cv_sys_max_cmd_len"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
+$as_echo_n "checking how to convert $build file names to $host format... " >&6; }
+if ${lt_cv_to_host_file_cmd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+ ;;
+ esac
+ ;;
+ *-*-cygwin* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+ ;;
+ esac
+ ;;
+ * ) # unhandled hosts (and "normal" native builds)
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+esac
+
+fi
+
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
+$as_echo "$lt_cv_to_host_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
+$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; }
+if ${lt_cv_to_tool_file_cmd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ #assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ esac
+ ;;
+esac
+
+fi
+
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
+$as_echo "$lt_cv_to_tool_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if ${lt_cv_ld_reload_flag+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ if test yes != "$GCC"; then
+ reload_cmds=false
+ fi
+ ;;
+ darwin*)
+ if test yes = "$GCC"; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OBJDUMP"; then
+ ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+ ac_ct_OBJDUMP=$OBJDUMP
+ # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OBJDUMP"; then
+ ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_OBJDUMP="objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OBJDUMP" = x; then
+ OBJDUMP="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OBJDUMP=$ac_ct_OBJDUMP
+ fi
+else
+ OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if ${lt_cv_deplibs_check_method+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# 'unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# that responds to the $file_magic_cmd with a given extended regex.
+# If you have 'file' or equivalent on your system and you're not sure
+# whether 'pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[45]*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ if ( file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ # Keep this pattern in sync with the one in func_win32_libid.
+ lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc*)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+haiku*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[3-9]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd* | bitrig*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+os2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+ case $host_os in
+ mingw* | pw32*)
+ if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+ want_nocaseglob=yes
+ else
+ file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"`
+ fi
+ ;;
+ esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DLLTOOL"; then
+ ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+ ac_ct_DLLTOOL=$DLLTOOL
+ # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DLLTOOL"; then
+ ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DLLTOOL" = x; then
+ DLLTOOL="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DLLTOOL=$ac_ct_DLLTOOL
+ fi
+else
+ DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
+$as_echo_n "checking how to associate runtime and link libraries... " >&6; }
+if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+ # two different shell functions defined in ltmain.sh;
+ # decide which one to use based on capabilities of $DLLTOOL
+ case `$DLLTOOL --help 2>&1` in
+ *--identify-strict*)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+ ;;
+ *)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+ ;;
+ esac
+ ;;
+*)
+ # fallback: assume linklib IS sharedlib
+ lt_cv_sharedlib_from_linklib_cmd=$ECHO
+ ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
+$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ for ac_prog in ar
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AR" && break
+ done
+fi
+if test -z "$AR"; then
+ ac_ct_AR=$AR
+ for ac_prog in ar
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AR="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_AR" && break
+done
+
+ if test "x$ac_ct_AR" = x; then
+ AR="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AR=$ac_ct_AR
+ fi
+fi
+
+: ${AR=ar}
+: ${AR_FLAGS=cr}
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
+$as_echo_n "checking for archiver @FILE support... " >&6; }
+if ${lt_cv_ar_at_file+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ar_at_file=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ echo conftest.$ac_objext > conftest.lst
+ lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+ (eval $lt_ar_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if test 0 -eq "$ac_status"; then
+ # Ensure the archiver fails upon bogus file names.
+ rm -f conftest.$ac_objext libconftest.a
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+ (eval $lt_ar_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if test 0 -ne "$ac_status"; then
+ lt_cv_ar_at_file=@
+ fi
+ fi
+ rm -f conftest.* libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
+$as_echo "$lt_cv_ar_at_file" >&6; }
+
+if test no = "$lt_cv_ar_at_file"; then
+ archiver_list_spec=
+else
+ archiver_list_spec=$lt_cv_ar_at_file
+fi
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ bitrig* | openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+ darwin*)
+ lock_old_archive_extraction=yes ;;
+ *)
+ lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if ${lt_cv_sys_global_symbol_pipe+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[BCDT]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[ABCDGISTW]'
+ ;;
+hpux*)
+ if test ia64 = "$host_cpu"; then
+ symcode='[ABCDEGRST]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[BCDEGRST]'
+ ;;
+osf*)
+ symcode='[BCDEGQRST]'
+ ;;
+solaris*)
+ symcode='[BDRT]'
+ ;;
+sco3.2v5*)
+ symcode='[DT]'
+ ;;
+sysv4.2uw2*)
+ symcode='[DT]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[ABDT]'
+ ;;
+sysv4)
+ symcode='[DFNSTU]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[ABCDGIRSTW]' ;;
+esac
+
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Gets list of data symbols to import.
+ lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
+ # Adjust the below global symbol transforms to fixup imported variables.
+ lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
+ lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'"
+ lt_c_name_lib_hook="\
+ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\
+ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'"
+else
+ # Disable hooks by default.
+ lt_cv_sys_global_symbol_to_import=
+ lt_cdecl_hook=
+ lt_c_name_hook=
+ lt_c_name_lib_hook=
+fi
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n"\
+$lt_cdecl_hook\
+" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
+$lt_c_name_hook\
+" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'"
+
+# Transform an extracted symbol line into symbol name with lib prefix and
+# symbol address.
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
+$lt_c_name_lib_hook\
+" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function,
+ # D for any global variable and I for any imported variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK '"\
+" {last_section=section; section=\$ 3};"\
+" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
+" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
+" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
+" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
+" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+ lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5
+ if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
+ relocations are performed -- see ld's documentation on pseudo-relocs. */
+# define LT_DLSYM_CONST
+#elif defined __osf__
+/* This system does not cope well with relocations in const data. */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+LT_DLSYM_CONST struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_globsym_save_LIBS=$LIBS
+ lt_globsym_save_CFLAGS=$CFLAGS
+ LIBS=conftstm.$ac_objext
+ CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest$ac_exeext; then
+ pipe_works=yes
+ fi
+ LIBS=$lt_globsym_save_LIBS
+ CFLAGS=$lt_globsym_save_CFLAGS
+ else
+ echo "cannot find nm_test_func in $nlist" >&5
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&5
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+ fi
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test yes = "$pipe_works"; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then
+ nm_file_list_spec='@'
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
+$as_echo_n "checking for sysroot... " >&6; }
+
+# Check whether --with-sysroot was given.
+if test "${with_sysroot+set}" = set; then :
+ withval=$with_sysroot;
+else
+ with_sysroot=no
+fi
+
+
+lt_sysroot=
+case $with_sysroot in #(
+ yes)
+ if test yes = "$GCC"; then
+ lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+ fi
+ ;; #(
+ /*)
+ lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+ ;; #(
+ no|'')
+ ;; #(
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5
+$as_echo "$with_sysroot" >&6; }
+ as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
+ ;;
+esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
+$as_echo "${lt_sysroot:-no}" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5
+$as_echo_n "checking for a working dd... " >&6; }
+if ${ac_cv_path_lt_DD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+: ${lt_DD:=$DD}
+if test -z "$lt_DD"; then
+ ac_path_lt_DD_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in dd; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_lt_DD" || continue
+if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+ cmp -s conftest.i conftest.out \
+ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
+fi
+ $ac_path_lt_DD_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_lt_DD"; then
+ :
+ fi
+else
+ ac_cv_path_lt_DD=$lt_DD
+fi
+
+rm -f conftest.i conftest2.i conftest.out
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5
+$as_echo "$ac_cv_path_lt_DD" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5
+$as_echo_n "checking how to truncate binary pipes... " >&6; }
+if ${lt_cv_truncate_bin+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+lt_cv_truncate_bin=
+if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+ cmp -s conftest.i conftest.out \
+ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
+fi
+rm -f conftest.i conftest2.i conftest.out
+test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5
+$as_echo "$lt_cv_truncate_bin" >&6; }
+
+
+
+
+
+
+
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+ for cc_temp in $*""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+ done
+ func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+ enableval=$enable_libtool_lock;
+fi
+
+test no = "$enable_libtool_lock" || enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out what ABI is being produced by ac_compile, and set mode
+ # options accordingly.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE=32
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE=64
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ if test yes = "$lt_cv_prog_gnu_ld"; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+mips64*-*linux*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ emul=elf
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ emul="${emul}32"
+ ;;
+ *64-bit*)
+ emul="${emul}64"
+ ;;
+ esac
+ case `/usr/bin/file conftest.$ac_objext` in
+ *MSB*)
+ emul="${emul}btsmip"
+ ;;
+ *LSB*)
+ emul="${emul}ltsmip"
+ ;;
+ esac
+ case `/usr/bin/file conftest.$ac_objext` in
+ *N32*)
+ emul="${emul}n32"
+ ;;
+ esac
+ LD="${LD-ld} -m $emul"
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly. Note that the listed cases only cover the
+ # situations where additional linker options are needed (such as when
+ # doing 32-bit compilation for a host where ld defaults to 64-bit, or
+ # vice versa); the common cases where no linker options are needed do
+ # not appear in the list.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ case `/usr/bin/file conftest.o` in
+ *x86-64*)
+ LD="${LD-ld} -m elf32_x86_64"
+ ;;
+ *)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ esac
+ ;;
+ powerpc64le-*linux*)
+ LD="${LD-ld} -m elf32lppclinux"
+ ;;
+ powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ powerpcle-*linux*)
+ LD="${LD-ld} -m elf64lppc"
+ ;;
+ powerpc-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -belf"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if ${lt_cv_cc_needs_belf+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_cc_needs_belf=yes
+else
+ lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+ if test yes != "$lt_cv_cc_needs_belf"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS=$SAVE_CFLAGS
+ fi
+ ;;
+*-*solaris*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*)
+ case $host in
+ i?86-*-solaris*|x86_64-*-solaris*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ sparc*-*-solaris*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
+ if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+ LD=${LD-ld}_sol2
+ fi
+ ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks=$enable_libtool_lock
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
+set dummy ${ac_tool_prefix}mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_MANIFEST_TOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$MANIFEST_TOOL"; then
+ ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
+if test -n "$MANIFEST_TOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
+$as_echo "$MANIFEST_TOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
+ ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
+ # Extract the first word of "mt", so it can be a program name with args.
+set dummy mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_MANIFEST_TOOL"; then
+ ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
+if test -n "$ac_ct_MANIFEST_TOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
+$as_echo "$ac_ct_MANIFEST_TOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_MANIFEST_TOOL" = x; then
+ MANIFEST_TOOL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
+ fi
+else
+ MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL"
+fi
+
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
+$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
+if ${lt_cv_path_mainfest_tool+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_path_mainfest_tool=no
+ echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
+ $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+ cat conftest.err >&5
+ if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+ lt_cv_path_mainfest_tool=yes
+ fi
+ rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
+$as_echo "$lt_cv_path_mainfest_tool" >&6; }
+if test yes != "$lt_cv_path_mainfest_tool"; then
+ MANIFEST_TOOL=:
+fi
+
+
+
+
+
+
+ case $host_os in
+ rhapsody* | darwin*)
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DSYMUTIL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DSYMUTIL"; then
+ ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+ ac_ct_DSYMUTIL=$DSYMUTIL
+ # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DSYMUTIL"; then
+ ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DSYMUTIL" = x; then
+ DSYMUTIL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DSYMUTIL=$ac_ct_DSYMUTIL
+ fi
+else
+ DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_NMEDIT+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NMEDIT"; then
+ ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+ ac_ct_NMEDIT=$NMEDIT
+ # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_NMEDIT"; then
+ ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_NMEDIT="nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_NMEDIT" = x; then
+ NMEDIT=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ NMEDIT=$ac_ct_NMEDIT
+ fi
+else
+ NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LIPO+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$LIPO"; then
+ ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+ ac_ct_LIPO=$LIPO
+ # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_LIPO"; then
+ ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_LIPO="lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_LIPO" = x; then
+ LIPO=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ LIPO=$ac_ct_LIPO
+ fi
+else
+ LIPO="$ac_cv_prog_LIPO"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL"; then
+ ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+ ac_ct_OTOOL=$OTOOL
+ # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL"; then
+ ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_OTOOL="otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL" = x; then
+ OTOOL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL=$ac_ct_OTOOL
+ fi
+else
+ OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL64+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL64"; then
+ ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+ ac_ct_OTOOL64=$OTOOL64
+ # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL64"; then
+ ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_OTOOL64="otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL64" = x; then
+ OTOOL64=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL64=$ac_ct_OTOOL64
+ fi
+else
+ OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if ${lt_cv_apple_cc_single_mod+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_apple_cc_single_mod=no
+ if test -z "$LT_MULTI_MODULE"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ # If there is a non-empty error log, and "single_module"
+ # appears in it, assume the flag caused a linker warning
+ if test -s conftest.err && $GREP single_module conftest.err; then
+ cat conftest.err >&5
+ # Otherwise, if the output was created with a 0 exit code from
+ # the compiler, it worked.
+ elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if ${lt_cv_ld_exported_symbols_list+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_ld_exported_symbols_list=yes
+else
+ lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if ${lt_cv_ld_force_load+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_force_load=no
+ cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+ echo "$AR cr libconftest.a conftest.o" >&5
+ $AR cr libconftest.a conftest.o 2>&5
+ echo "$RANLIB libconftest.a" >&5
+ $RANLIB libconftest.a 2>&5
+ cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+ _lt_result=$?
+ if test -s conftest.err && $GREP force_load conftest.err; then
+ cat conftest.err >&5
+ elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
+ lt_cv_ld_force_load=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -f conftest.err libconftest.a conftest conftest.c
+ rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+ case $host_os in
+ rhapsody* | darwin1.[012])
+ _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[912]*)
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+ 10.[012][,.]*)
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+ 10.*|11.*)
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test yes = "$lt_cv_apple_cc_single_mod"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test yes = "$lt_cv_ld_exported_symbols_list"; then
+ _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
+ fi
+ if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+
+# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+# string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+# string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+# string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+# "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+# VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+ case x$2 in
+ x)
+ ;;
+ *:)
+ eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\"
+ ;;
+ x:*)
+ eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\"
+ ;;
+ *::*)
+ eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+ eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\"
+ ;;
+ *)
+ eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\"
+ ;;
+ esac
+}
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in dlfcn.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+# Set options
+
+
+
+ enable_dlopen=no
+
+
+ enable_win32_dll=no
+
+
+ # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+ enableval=$enable_shared; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for pkg in $enableval; do
+ IFS=$lt_save_ifs
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac
+else
+ enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+ # Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+ enableval=$enable_static; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for pkg in $enableval; do
+ IFS=$lt_save_ifs
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac
+else
+ enable_static=yes
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+ withval=$with_pic; lt_p=${PACKAGE-default}
+ case $withval in
+ yes|no) pic_mode=$withval ;;
+ *)
+ pic_mode=default
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for lt_pkg in $withval; do
+ IFS=$lt_save_ifs
+ if test "X$lt_pkg" = "X$lt_p"; then
+ pic_mode=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac
+else
+ pic_mode=default
+fi
+
+
+
+
+
+
+
+
+ # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+ enableval=$enable_fast_install; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for pkg in $enableval; do
+ IFS=$lt_save_ifs
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac
+else
+ enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+ shared_archive_member_spec=
+case $host,$enable_shared in
+power*-*-aix[5-9]*,yes)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5
+$as_echo_n "checking which variant of shared library versioning to provide... " >&6; }
+
+# Check whether --with-aix-soname was given.
+if test "${with_aix_soname+set}" = set; then :
+ withval=$with_aix_soname; case $withval in
+ aix|svr4|both)
+ ;;
+ *)
+ as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5
+ ;;
+ esac
+ lt_cv_with_aix_soname=$with_aix_soname
+else
+ if ${lt_cv_with_aix_soname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_with_aix_soname=aix
+fi
+
+ with_aix_soname=$lt_cv_with_aix_soname
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5
+$as_echo "$with_aix_soname" >&6; }
+ if test aix != "$with_aix_soname"; then
+ # For the AIX way of multilib, we name the shared archive member
+ # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
+ # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
+ # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
+ # the AIX toolchain works better with OBJECT_MODE set (default 32).
+ if test 64 = "${OBJECT_MODE-32}"; then
+ shared_archive_member_spec=shr_64
+ else
+ shared_archive_member_spec=shr
+ fi
+ fi
+ ;;
+*)
+ with_aix_soname=aix
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS=$ltmain
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}"; then
+ setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if ${lt_cv_objdir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test set != "${COLLECT_NAMES+set}"; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a '.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+old_CC=$CC
+old_CFLAGS=$CFLAGS
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+func_cc_basename $compiler
+cc_basename=$func_cc_basename_result
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD=$MAGIC_CMD
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/${ac_tool_prefix}file"; then
+ lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS=$lt_save_ifs
+ MAGIC_CMD=$lt_save_MAGIC_CMD
+ ;;
+esac
+fi
+
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD=$MAGIC_CMD
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/file"; then
+ lt_cv_path_MAGIC_CMD=$ac_dir/"file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS=$lt_save_ifs
+ MAGIC_CMD=$lt_save_MAGIC_CMD
+ ;;
+esac
+fi
+
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ else
+ MAGIC_CMD=:
+ fi
+fi
+
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC=$CC
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test yes = "$GCC"; then
+ case $cc_basename in
+ nvcc*)
+ lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+ *)
+ lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+ esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_rtti_exceptions=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_rtti_exceptions=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then
+ lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+ :
+fi
+
+fi
+
+
+
+
+
+
+ lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+
+ if test yes = "$GCC"; then
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_static='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the '-m68020' flag to GCC prevents building anything better,
+ # like '-m68040'.
+ lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ case $host_os in
+ os2*)
+ lt_prog_compiler_static='$wl-static'
+ ;;
+ esac
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ lt_prog_compiler_static=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[3-9]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ lt_prog_compiler_wl='-Xlinker '
+ if test -n "$lt_prog_compiler_pic"; then
+ lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic"
+ fi
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl='-Wl,'
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ else
+ lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic='-fno-common'
+ case $cc_basename in
+ nagfor*)
+ # NAG Fortran compiler
+ lt_prog_compiler_wl='-Wl,-Wl,,'
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ esac
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ case $host_os in
+ os2*)
+ lt_prog_compiler_static='$wl-static'
+ ;;
+ esac
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static='$wl-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ # old Intel for x86_64, which still supported -KPIC.
+ ecc*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # flang / f18. f95 an alias for gfortran or flang on Debian
+ flang* | f18* | f95*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='--shared'
+ lt_prog_compiler_static='--static'
+ ;;
+ nagfor*)
+ # NAG Fortran compiler
+ lt_prog_compiler_wl='-Wl,-Wl,,'
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ tcc*)
+ # Fabrice Bellard et al's Tiny C Compiler
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-qpic'
+ lt_prog_compiler_static='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl=''
+ ;;
+ *Sun\ F* | *Sun*Fortran*)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl='-Qoption ld '
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl='-Wl,'
+ ;;
+ *Intel*\ [CF]*Compiler*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ *Portland\ Group*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ rdos*)
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+ lt_prog_compiler_wl='-Qoption ld ';;
+ *)
+ lt_prog_compiler_wl='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl='-Qoption ld '
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic='-Kconform_pic'
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ unicos*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_can_build_shared=no
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic='-pic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared=no
+ ;;
+ esac
+ fi
+
+case $host_os in
+ # For platforms that do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic=
+ ;;
+ *)
+ lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+ ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic=$lt_prog_compiler_pic
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
+$as_echo "$lt_cv_prog_compiler_pic" >&6; }
+lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic_works=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_pic_works=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test yes = "$lt_cv_prog_compiler_pic_works"; then
+ case $lt_prog_compiler_pic in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+ esac
+else
+ lt_prog_compiler_pic=
+ lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_static_works=no
+ save_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ else
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS=$save_LDFLAGS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test yes = "$lt_cv_prog_compiler_static_works"; then
+ :
+else
+ lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links=nottested
+if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then
+ # do not overwrite the value of need_locks provided by the user
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+ if test no = "$hard_links"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+ runpath_var=
+ allow_undefined_flag=
+ always_export_symbols=no
+ archive_cmds=
+ archive_expsym_cmds=
+ compiler_needs_object=no
+ enable_shared_with_static_runtimes=no
+ export_dynamic_flag_spec=
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ hardcode_automatic=no
+ hardcode_direct=no
+ hardcode_direct_absolute=no
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_separator=
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=unsupported
+ inherit_rpath=no
+ link_all_deplibs=unknown
+ module_cmds=
+ module_expsym_cmds=
+ old_archive_from_new_cmds=
+ old_archive_from_expsyms_cmds=
+ thread_safe_flag_spec=
+ whole_archive_flag_spec=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ' (' and ')$', so one must not match beginning or
+ # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
+ # as well as any symbol that contains 'd'.
+ exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test yes != "$GCC"; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd* | bitrig*)
+ with_gnu_ld=no
+ ;;
+ linux* | k*bsd*-gnu | gnu*)
+ link_all_deplibs=no
+ ;;
+ esac
+
+ ld_shlibs=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test yes = "$with_gnu_ld"; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+ *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test yes = "$lt_use_gnu_ld_interface"; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='$wl'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+ export_dynamic_flag_spec='$wl--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[3-9]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test ia64 != "$host_cpu"; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ export_dynamic_flag_spec='$wl--export-all-symbols'
+ allow_undefined_flag=unsupported
+ always_export_symbols=no
+ enable_shared_with_static_runtimes=yes
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+ exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file, use it as
+ # is; otherwise, prepend EXPORTS...
+ archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ haiku*)
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ link_all_deplibs=yes
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ shrext_cmds=.dll
+ archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ enable_shared_with_static_runtimes=yes
+ ;;
+
+ interix[3-9]*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='$wl-rpath,$libdir'
+ export_dynamic_flag_spec='$wl-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test linux-dietlibc = "$host_os"; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test no = "$tmp_diet"
+ then
+ tmp_addflag=' $pic_flag'
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ whole_archive_flag_spec=
+ tmp_sharedflag='--shared' ;;
+ nagfor*) # NAGFOR 5.3
+ tmp_sharedflag='-Wl,-shared' ;;
+ xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ compiler_needs_object=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ compiler_needs_object=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+
+ if test yes = "$supports_anon_versioning"; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ tcc*)
+ export_dynamic_flag_spec='-rdynamic'
+ ;;
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+ archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+ if test yes = "$supports_anon_versioning"; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+
+ if test no = "$ld_shlibs"; then
+ runpath_var=
+ hardcode_libdir_flag_spec=
+ export_dynamic_flag_spec=
+ whole_archive_flag_spec=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test ia64 = "$host_cpu"; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+ # Without the "-l" option, or with the "-B" option, AIX nm treats
+ # weak defined symbols like other global defined symbols, whereas
+ # GNU nm marks them as "W".
+ # While the 'weak' keyword is ignored in the Export File, we need
+ # it in the Import File for the 'aix-soname' feature, so we have
+ # to replace the "-B" option with "-P" for AIX nm.
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # have runtime linking enabled, and use it for executables.
+ # For shared libraries, we enable/disable runtime linking
+ # depending on the kind of the shared library created -
+ # when "with_aix_soname,aix_use_runtimelinking" is:
+ # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
+ # "aix,yes" lib.so shared, rtl:yes, for executables
+ # lib.a static archive
+ # "both,no" lib.so.V(shr.o) shared, rtl:yes
+ # lib.a(lib.so.V) shared, rtl:no, for executables
+ # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a(lib.so.V) shared, rtl:no
+ # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a static archive
+ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+ for ld_flag in $LDFLAGS; do
+ if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # With aix-soname=svr4, we create the lib.so.V shared archives only,
+ # so we don't have lib.a shared libs to link our executables.
+ # We have to force runtime linking in this case.
+ aix_use_runtimelinking=yes
+ LDFLAGS="$LDFLAGS -Wl,-brtl"
+ fi
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds=''
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ file_list_spec='$wl-f,'
+ case $with_aix_soname,$aix_use_runtimelinking in
+ aix,*) ;; # traditional, no import file
+ svr4,* | *,yes) # use import file
+ # The Import File defines what to hardcode.
+ hardcode_direct=no
+ hardcode_direct_absolute=no
+ ;;
+ esac
+
+ if test yes = "$GCC"; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`$CC -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag="$shared_flag "'$wl-G'
+ fi
+ # Need to ensure runtime linking is disabled for the traditional
+ # shared library, or the linker may eventually find shared libraries
+ # /with/ Import File - we do not want to mix them.
+ shared_flag_aix='-shared'
+ shared_flag_svr4='-shared $wl-G'
+ else
+ # not using gcc
+ if test ia64 = "$host_cpu"; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag='$wl-G'
+ else
+ shared_flag='$wl-bM:SRE'
+ fi
+ shared_flag_aix='$wl-bM:SRE'
+ shared_flag_svr4='$wl-G'
+ fi
+ fi
+
+ export_dynamic_flag_spec='$wl-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols=yes
+ if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ if test set = "${lt_cv_aix_libpath+set}"; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ if ${lt_cv_aix_libpath_+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }'
+ lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_=/usr/lib:/lib
+ fi
+
+fi
+
+ aix_libpath=$lt_cv_aix_libpath_
+fi
+
+ hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
+ else
+ if test ia64 = "$host_cpu"; then
+ hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag="-z nodefs"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ if test set = "${lt_cv_aix_libpath+set}"; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ if ${lt_cv_aix_libpath_+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }'
+ lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_=/usr/lib:/lib
+ fi
+
+fi
+
+ aix_libpath=$lt_cv_aix_libpath_
+fi
+
+ hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag=' $wl-bernotok'
+ allow_undefined_flag=' $wl-berok'
+ if test yes = "$with_gnu_ld"; then
+ # We only use this code for GNU lds that support --whole-archive.
+ whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec='$convenience'
+ fi
+ archive_cmds_need_lc=yes
+ archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+ # -brtl affects multiple linker settings, -berok does not and is overridden later
+ compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`'
+ if test svr4 != "$with_aix_soname"; then
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+ fi
+ if test aix != "$with_aix_soname"; then
+ archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+ else
+ # used by -dlpreopen to get the symbols
+ archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
+ fi
+ archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[45]*)
+ export_dynamic_flag_spec=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ case $cc_basename in
+ cl*)
+ # Native MSVC
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ file_list_spec='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=.dll
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+ archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then
+ cp "$export_symbols" "$output_objdir/$soname.def";
+ echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+ else
+ $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, )='true'
+ enable_shared_with_static_runtimes=yes
+ exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+ # Don't use ranlib
+ old_postinstall_cmds='chmod 644 $oldlib'
+ postlink_cmds='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile=$lt_outputfile.exe
+ lt_tool_outputfile=$lt_tool_outputfile.exe
+ ;;
+ esac~
+ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # Assume MSVC wrapper
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=.dll
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_from_new_cmds='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ enable_shared_with_static_runtimes=yes
+ ;;
+ esac
+ ;;
+
+ darwin* | rhapsody*)
+
+
+ archive_cmds_need_lc=no
+ hardcode_direct=no
+ hardcode_automatic=yes
+ hardcode_shlibpath_var=unsupported
+ if test yes = "$lt_cv_ld_force_load"; then
+ whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+
+ else
+ whole_archive_flag_spec=''
+ fi
+ link_all_deplibs=yes
+ allow_undefined_flag=$_lt_dar_allow_undefined
+ case $cc_basename in
+ ifort*|nagfor*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test yes = "$_lt_dar_can_shared"; then
+ output_verbose_link_cmd=func_echo_all
+ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+ archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+ module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
+
+ else
+ ld_shlibs=no
+ fi
+
+ ;;
+
+ dgux*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2.*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ hpux9*)
+ if test yes = "$GCC"; then
+ archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec='$wl+b $wl$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ export_dynamic_flag_spec='$wl-E'
+ ;;
+
+ hpux10*)
+ if test yes,no = "$GCC,$with_gnu_ld"; then
+ archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test no = "$with_gnu_ld"; then
+ hardcode_libdir_flag_spec='$wl+b $wl$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='$wl-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test yes,no = "$GCC,$with_gnu_ld"; then
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+
+ # Older versions of the 11.00 compiler do not understand -b yet
+ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if ${lt_cv_prog_compiler__b+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler__b=no
+ save_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS -b"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler__b=yes
+ fi
+ else
+ lt_cv_prog_compiler__b=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS=$save_LDFLAGS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test yes = "$lt_cv_prog_compiler__b"; then
+ archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
+ ;;
+ esac
+ fi
+ if test no = "$with_gnu_ld"; then
+ hardcode_libdir_flag_spec='$wl+b $wl$libdir'
+ hardcode_libdir_separator=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ ;;
+ *)
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='$wl-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test yes = "$GCC"; then
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ # This should be the same for all languages, so no per-tag cache variable.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
+$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
+if ${lt_cv_irix_exported_symbol+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ save_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int foo (void) { return 0; }
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_irix_exported_symbol=yes
+else
+ lt_cv_irix_exported_symbol=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
+$as_echo "$lt_cv_irix_exported_symbol" >&6; }
+ if test yes = "$lt_cv_irix_exported_symbol"; then
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
+ fi
+ link_all_deplibs=no
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+ hardcode_libdir_separator=:
+ inherit_rpath=yes
+ link_all_deplibs=yes
+ ;;
+
+ linux*)
+ case $cc_basename in
+ tcc*)
+ # Fabrice Bellard et al's Tiny C Compiler
+ ld_shlibs=yes
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ newsos6)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+ hardcode_libdir_separator=:
+ hardcode_shlibpath_var=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd* | bitrig*)
+ if test -f /usr/libexec/ld.so; then
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ hardcode_direct_absolute=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec='$wl-rpath,$libdir'
+ export_dynamic_flag_spec='$wl-E'
+ else
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='$wl-rpath,$libdir'
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ shrext_cmds=.dll
+ archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ enable_shared_with_static_runtimes=yes
+ ;;
+
+ osf3*)
+ if test yes = "$GCC"; then
+ allow_undefined_flag=' $wl-expect_unresolved $wl\*'
+ archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test yes = "$GCC"; then
+ allow_undefined_flag=' $wl-expect_unresolved $wl\*'
+ archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_separator=:
+ ;;
+
+ solaris*)
+ no_undefined_flag=' -z defs'
+ if test yes = "$GCC"; then
+ wlarc='$wl'
+ archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='$wl'
+ archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_shlibpath_var=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands '-z linker_flag'. GCC discards it without '$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test yes = "$GCC"; then
+ whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
+ else
+ whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ link_all_deplibs=yes
+ ;;
+
+ sunos4*)
+ if test sequent = "$host_vendor"; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds='$CC -r -o $output$reload_objs'
+ hardcode_direct=no
+ ;;
+ motorola)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag='$wl-z,text'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ runpath_var='LD_RUN_PATH'
+
+ if test yes = "$GCC"; then
+ archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We CANNOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag='$wl-z,text'
+ allow_undefined_flag='$wl-z,nodefs'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='$wl-R,$libdir'
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ export_dynamic_flag_spec='$wl-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test yes = "$GCC"; then
+ archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+
+ if test sni = "$host_vendor"; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ export_dynamic_flag_spec='$wl-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test no = "$ld_shlibs" && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc=yes
+
+ if test yes,yes = "$GCC,$enable_shared"; then
+ case $archive_cmds in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl
+ pic_flag=$lt_prog_compiler_pic
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag
+ allow_undefined_flag=
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+ (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ then
+ lt_cv_archive_cmds_need_lc=no
+ else
+ lt_cv_archive_cmds_need_lc=yes
+ fi
+ allow_undefined_flag=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+ archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test yes = "$GCC"; then
+ case $host_os in
+ darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
+ *) lt_awk_arg='/^libraries:/' ;;
+ esac
+ case $host_os in
+ mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;;
+ *) lt_sed_strip_eq='s|=/|/|g' ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+ case $lt_search_path_spec in
+ *\;*)
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+ ;;
+ *)
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ esac
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary...
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ # ...but if some path component already ends with the multilib dir we assume
+ # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
+ case "$lt_multi_os_dir; $lt_search_path_spec " in
+ "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
+ lt_multi_os_dir=
+ ;;
+ esac
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
+ elif test -n "$lt_multi_os_dir"; then
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS = " "; FS = "/|\n";} {
+ lt_foo = "";
+ lt_count = 0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo = "/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[lt_foo]++; }
+ if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+ # AWK program above erroneously prepends '/' to C:/dos/paths
+ # for these hosts.
+ case $host_os in
+ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ $SED 's|/\([A-Za-z]:\)|\1|g'` ;;
+ esac
+ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=.so
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+
+
+case $host_os in
+aix3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+
+aix[4-9]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 supports IA64
+ library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line '#! .'. This would cause the generated library to
+ # depend on '.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # Using Import Files as archive members, it is possible to support
+ # filename-based versioning of shared library archives on AIX. While
+ # this would work for both with and without runtime linking, it will
+ # prevent static linking of such archives. So we do filename-based
+ # shared library versioning with .so extension only, which is used
+ # when both runtime linking and shared linking is enabled.
+ # Unfortunately, runtime linking may impact performance, so we do
+ # not want this to be the default eventually. Also, we use the
+ # versioned .so libs for executables only if there is the -brtl
+ # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+ # To allow for filename-based versioning support, we need to create
+ # libNAME.so.V as an archive file, containing:
+ # *) an Import File, referring to the versioned filename of the
+ # archive as well as the shared archive member, telling the
+ # bitwidth (32 or 64) of that shared object, and providing the
+ # list of exported symbols of that shared object, eventually
+ # decorated with the 'weak' keyword
+ # *) the shared object with the F_LOADONLY flag set, to really avoid
+ # it being seen by the linker.
+ # At run time we better use the real file rather than another symlink,
+ # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+ case $with_aix_soname,$aix_use_runtimelinking in
+ # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ aix,yes) # traditional libtool
+ dynamic_linker='AIX unversionable lib.so'
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ ;;
+ aix,no) # traditional AIX only
+ dynamic_linker='AIX lib.a(lib.so.V)'
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+ svr4,*) # full svr4 only
+ dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,yes) # both, prefer svr4
+ dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # unpreferred sharedlib libNAME.a needs extra handling
+ postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+ postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,no) # both, prefer aix
+ dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)"
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+ postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+ postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+ ;;
+ esac
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='$libname$shared_ext'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=.dll
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$cc_basename in
+ yes,*)
+ # gcc
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ ;;
+
+ *,cl*)
+ # Native MSVC
+ libname_spec='$name'
+ soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+ library_names_spec='$libname.dll.lib'
+
+ case $build_os in
+ mingw*)
+ sys_lib_search_path_spec=
+ lt_save_ifs=$IFS
+ IFS=';'
+ for lt_path in $LIB
+ do
+ IFS=$lt_save_ifs
+ # Let DOS variable expansion print the short 8.3 style file name.
+ lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+ sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+ done
+ IFS=$lt_save_ifs
+ # Convert to MSYS style.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+ ;;
+ cygwin*)
+ # Convert to unix form, then to dos form, then back to unix form
+ # but this time dos style (no spaces!) so that the unix form looks
+ # like /cygdrive/c/PROGRA~1:/cygdr...
+ sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+ sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+ sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ *)
+ sys_lib_search_path_spec=$LIB
+ if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # FIXME: find the short name or the path components, as spaces are
+ # common. (e.g. "Program Files" -> "PROGRA~1")
+ ;;
+ esac
+
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+ dynamic_linker='Win32 link.exe'
+ ;;
+
+ *)
+ # Assume MSVC wrapper
+ library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib'
+ dynamic_linker='Win32 ld.exe'
+ ;;
+ esac
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$major$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[23].*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2.*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[01]* | freebsdelf3.[01]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+haiku*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ if test 32 = "$HPUX_IA64_MODE"; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux32
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux64
+ fi
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[3-9]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test yes = "$lt_cv_prog_gnu_ld"; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+ sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+linux*android*)
+ version_type=none # Android doesn't support versioned libraries.
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext'
+ soname_spec='$libname$release$shared_ext'
+ finish_cmds=
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ dynamic_linker='Android linker'
+ # Don't embed -rpath directories since the linker doesn't support them.
+ hardcode_libdir_flag_spec='-L$libdir'
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+ lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+
+fi
+
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Ideally, we could use ldconfig to report *all* directores which are
+ # searched for libraries, however this is still not possible. Aside from not
+ # being certain /sbin/ldconfig is available, command
+ # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+ # even though it is searched at run-time. Try to do the best guess by
+ # appending ld.so.conf contents (and includes) to the search path.
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsdelf*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='NetBSD ld.elf_so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd* | bitrig*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec=/usr/lib
+ need_lib_prefix=no
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ need_version=no
+ else
+ need_version=yes
+ fi
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+os2*)
+ libname_spec='$name'
+ version_type=windows
+ shrext_cmds=.dll
+ need_version=no
+ need_lib_prefix=no
+ # OS/2 can only load a DLL with a base name of 8 characters or less.
+ soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+ v=$($ECHO $release$versuffix | tr -d .-);
+ n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+ $ECHO $n$v`$shared_ext'
+ library_names_spec='${libname}_dll.$libext'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=BEGINLIBPATH
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test yes = "$with_gnu_ld"; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+ soname_spec='$libname$shared_ext.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=sco
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test yes = "$with_gnu_ld"; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test no = "$dynamic_linker" && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test yes = "$GCC"; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+ sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
+fi
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+ sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
+fi
+
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+ test -n "$runpath_var" ||
+ test yes = "$hardcode_automatic"; then
+
+ # We can hardcode non-existent directories.
+ if test no != "$hardcode_direct" &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" &&
+ test no != "$hardcode_minus_L"; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test relink = "$hardcode_action" ||
+ test yes = "$inherit_rpath"; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test yes = "$shlibpath_overrides_runpath" ||
+ test no = "$enable_shared"; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+
+
+
+
+
+ if test yes != "$enable_dlopen"; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen=load_add_on
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen=LoadLibrary
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen=dlopen
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+ lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl
+else
+
+ lt_cv_dlopen=dyld
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ tpf*)
+ # Don't try to run any link tests for TPF. We know it's impossible
+ # because TPF is a cross-compiler, and we know how we open DSOs.
+ lt_cv_dlopen=dlopen
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=no
+ ;;
+
+ *)
+ ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = xyes; then :
+ lt_cv_dlopen=shl_load
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if ${ac_cv_lib_dld_shl_load+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_shl_load=yes
+else
+ ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
+ lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld
+else
+ ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = xyes; then :
+ lt_cv_dlopen=dlopen
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+ lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if ${ac_cv_lib_svld_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_svld_dlopen=yes
+else
+ ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
+ lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if ${ac_cv_lib_dld_dld_link+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_dld_link=yes
+else
+ ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
+ lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test no = "$lt_cv_dlopen"; then
+ enable_dlopen=no
+ else
+ enable_dlopen=yes
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS=$CPPFLAGS
+ test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS=$LDFLAGS
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS=$LIBS
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test yes = "$cross_compiling"; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisibility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+ if test yes = "$lt_cv_dlopen_self"; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self_static+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test yes = "$cross_compiling"; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisibility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+ fi
+
+ CPPFLAGS=$save_CPPFLAGS
+ LDFLAGS=$save_LDFLAGS
+ LIBS=$save_LIBS
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP"; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ ;;
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+ # Report what library types will actually be built
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+ test no = "$can_build_shared" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test yes = "$enable_shared" && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
+ fi
+ ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+ # Make sure either enable_shared or enable_static is yes.
+ test yes = "$enable_shared" || enable_static=yes
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC=$lt_save_CC
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+
+# Couple with Dovecot
+#
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -Werror -Wunknown-warning-option" >&5
+$as_echo_n "checking whether C compiler handles -Werror -Wunknown-warning-option... " >&6; }
+if ${gl_cv_warn_c__Werror__Wunknown_warning_option+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CFLAGS"
+ as_fn_append CFLAGS " $gl_unknown_warnings_are_errors -Werror -Wunknown-warning-option"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ gl_cv_warn_c__Werror__Wunknown_warning_option=yes
+else
+ gl_cv_warn_c__Werror__Wunknown_warning_option=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__Werror__Wunknown_warning_option" >&5
+$as_echo "$gl_cv_warn_c__Werror__Wunknown_warning_option" >&6; }
+if test "x$gl_cv_warn_c__Werror__Wunknown_warning_option" = xyes; then :
+ gl_unknown_warnings_are_errors='-Wunknown-warning-option -Werror'
+else
+ gl_unknown_warnings_are_errors=
+fi
+
+
+
+# Check whether --with-dovecot was given.
+if test "${with_dovecot+set}" = set; then :
+ withval=$with_dovecot; dovecotdir="$withval"
+else
+
+ dc_prefix=$prefix
+ test "x$dc_prefix" = xNONE && dc_prefix=$ac_default_prefix
+ dovecotdir="$dc_prefix/lib/dovecot"
+
+
+fi
+
+
+
+# Check whether --with-dovecot-install-dirs was given.
+if test "${with_dovecot_install_dirs+set}" = set; then :
+ withval=$with_dovecot_install_dirs; if test x$withval = xno; then :
+
+ use_install_dirs=no
+
+else
+
+ use_install_dirs=yes
+
+fi
+else
+ use_install_dirs=yes
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for \"$dovecotdir/dovecot-config\"" >&5
+$as_echo_n "checking for \"$dovecotdir/dovecot-config\"... " >&6; }
+ if test -f "$dovecotdir/dovecot-config"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dovecotdir/dovecot-config" >&5
+$as_echo "$dovecotdir/dovecot-config" >&6; }
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: " >&5
+$as_echo "$as_me: " >&6;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Use --with-dovecot=DIR to provide the path to the dovecot-config file." >&5
+$as_echo "$as_me: Use --with-dovecot=DIR to provide the path to the dovecot-config file." >&6;}
+ as_fn_error $? "dovecot-config not found" "$LINENO" 5
+
+fi
+
+ old=`pwd`
+ cd $dovecotdir
+ abs_dovecotdir=`pwd`
+ cd $old
+ DISTCHECK_CONFIGURE_FLAGS="--with-dovecot=$abs_dovecotdir --without-dovecot-install-dirs"
+
+ ORIG_CFLAGS="$CFLAGS"
+ ORIG_LDFLAGS="$LDFLAGS"
+ ORIG_BINARY_CFLAGS="$BINARY_CFLAGS"
+ ORIG_BINARY_LDFLAGS="$BINARY_LDFLAGS"
+
+ eval `grep -i '^dovecot_[a-z_]*=' "$dovecotdir"/dovecot-config`
+ eval `grep '^LIBDOVECOT[A-Z0-9_]*=' "$dovecotdir"/dovecot-config`
+
+ CFLAGS="$ORIG_CFLAGS"
+ LDFLAGS="$ORIG_LDFLAGS"
+ BINARY_CFLAGS="$ORIG_BINARY_CFLAGS"
+ BINARY_LDFLAGS="$ORIG_BINARY_LDFLAGS"
+
+ dovecot_installed_moduledir="$dovecot_moduledir"
+
+ if test "$use_install_dirs" = "no"; then :
+
+ dovecot_pkgincludedir='$(pkgincludedir)'
+ dovecot_pkglibdir='$(pkglibdir)'
+ dovecot_pkglibexecdir='$(libexecdir)/dovecot'
+ dovecot_docdir='$(docdir)'
+ dovecot_moduledir='$(moduledir)'
+ dovecot_statedir='$(statedir)'
+
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC is clang 3.3+" >&5
+$as_echo_n "checking whether $CC is clang 3.3+... " >&6; }
+ if $CC -dM -E -x c /dev/null | grep __clang__ > /dev/null 2>&1; then :
+
+ have_clang=yes
+
+else
+
+ have_clang=no
+
+fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_clang" >&5
+$as_echo "$have_clang" >&6; }
+
+
+ if test "x$ac_cv_c_compiler_gnu" = "xyes"; then :
+
+ CFLAGS="$CFLAGS -Wall -W -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wchar-subscripts -Wformat=2 -Wbad-function-cast"
+
+ if test "$have_clang" = "yes"; then :
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 3)
+ # error new clang
+ #endif
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+
+ CFLAGS="$CFLAGS -Wno-duplicate-decl-specifier"
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+else
+
+ CFLAGS="$CFLAGS -fno-builtin-strftime"
+
+fi
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #if __GNUC__ < 4
+ # error old gcc
+ #endif
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ CFLAGS="$CFLAGS -Wstrict-aliasing=2"
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+ old_cflags=$CFLAGS
+ CFLAGS="-std=gnu99"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ CFLAGS="$CFLAGS $old_cflags"
+
+else
+
+ CFLAGS="$old_cflags"
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+fi
+
+
+ # Check whether --enable-hardening was given.
+if test "${enable_hardening+set}" = set; then :
+ enableval=$enable_hardening; enable_hardening=$enableval
+else
+ enable_hardening=yes
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking Whether to enable hardening" >&5
+$as_echo_n "checking Whether to enable hardening... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_hardening" >&5
+$as_echo "$enable_hardening" >&6; }
+
+
+
+ PIE_CFLAGS=
+ PIE_LDFLAGS=
+
+ if test "$enable_hardening" = yes; then :
+
+ OLD_CFLAGS=$CFLAGS
+ case "$host" in
+ *-*-mingw* | *-*-msvc* | *-*-cygwin* )
+ ;; *)
+ CFLAGS="-fPIE -DPIE"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -pie" >&5
+$as_echo_n "checking whether C compiler handles -pie... " >&6; }
+if ${gl_cv_warn_c__pie+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CFLAGS"
+ as_fn_append CFLAGS " $gl_unknown_warnings_are_errors -pie"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ gl_cv_warn_c__pie=yes
+else
+ gl_cv_warn_c__pie=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__pie" >&5
+$as_echo "$gl_cv_warn_c__pie" >&6; }
+if test "x$gl_cv_warn_c__pie" = xyes; then :
+
+ PIE_CFLAGS="-fPIE -DPIE"
+ PIE_LDFLAGS="-pie"
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -Wl,-pie" >&5
+$as_echo_n "checking whether C compiler handles -Wl,-pie... " >&6; }
+if ${gl_cv_warn_c__Wl__pie+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CFLAGS"
+ as_fn_append CFLAGS " $gl_unknown_warnings_are_errors -Wl,-pie"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ gl_cv_warn_c__Wl__pie=yes
+else
+ gl_cv_warn_c__Wl__pie=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__Wl__pie" >&5
+$as_echo "$gl_cv_warn_c__Wl__pie" >&6; }
+if test "x$gl_cv_warn_c__Wl__pie" = xyes; then :
+
+ PIE_CFLAGS="-fPIE -DPIE"
+ PIE_LDFLAGS="-Wl,-pie"
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not supported" >&5
+$as_echo "not supported" >&6; }
+fi
+
+
+fi
+
+ esac
+ CFLAGS=$OLD_CFLAGS
+
+fi
+
+
+
+
+
+ if test "$enable_hardening" = yes; then :
+
+ case "$host" in
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -fstack-protector-strong" >&5
+$as_echo_n "checking whether C compiler handles -fstack-protector-strong... " >&6; }
+if ${gl_cv_warn_c__fstack_protector_strong+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CFLAGS"
+ as_fn_append CFLAGS " $gl_unknown_warnings_are_errors -fstack-protector-strong"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ gl_cv_warn_c__fstack_protector_strong=yes
+else
+ gl_cv_warn_c__fstack_protector_strong=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__fstack_protector_strong" >&5
+$as_echo "$gl_cv_warn_c__fstack_protector_strong" >&6; }
+if test "x$gl_cv_warn_c__fstack_protector_strong" = xyes; then :
+
+ CFLAGS="$CFLAGS -fstack-protector-strong"
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -fstack-protector" >&5
+$as_echo_n "checking whether C compiler handles -fstack-protector... " >&6; }
+if ${gl_cv_warn_c__fstack_protector+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CFLAGS"
+ as_fn_append CFLAGS " $gl_unknown_warnings_are_errors -fstack-protector"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ gl_cv_warn_c__fstack_protector=yes
+else
+ gl_cv_warn_c__fstack_protector=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__fstack_protector" >&5
+$as_echo "$gl_cv_warn_c__fstack_protector" >&6; }
+if test "x$gl_cv_warn_c__fstack_protector" = xyes; then :
+
+ CFLAGS="$CFLAGS -fstack-protector"
+
+fi
+
+
+fi
+
+ esac
+
+fi
+
+
+
+ if test "$enable_hardening" = yes; then :
+
+ case "$host" in
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2" >&5
+$as_echo_n "checking whether C compiler handles -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2... " >&6; }
+if ${gl_cv_warn_c__O2__U_FORTIFY_SOURCE__D_FORTIFY_SOURCE_2+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CFLAGS"
+ as_fn_append CFLAGS " $gl_unknown_warnings_are_errors -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ gl_cv_warn_c__O2__U_FORTIFY_SOURCE__D_FORTIFY_SOURCE_2=yes
+else
+ gl_cv_warn_c__O2__U_FORTIFY_SOURCE__D_FORTIFY_SOURCE_2=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__O2__U_FORTIFY_SOURCE__D_FORTIFY_SOURCE_2" >&5
+$as_echo "$gl_cv_warn_c__O2__U_FORTIFY_SOURCE__D_FORTIFY_SOURCE_2" >&6; }
+if test "x$gl_cv_warn_c__O2__U_FORTIFY_SOURCE__D_FORTIFY_SOURCE_2" = xyes; then :
+
+ CFLAGS="$CFLAGS -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2"
+
+fi
+
+ esac
+
+fi
+
+
+
+# Check whether --with-retpoline was given.
+if test "${with_retpoline+set}" = set; then :
+ withval=$with_retpoline; with_retpoline=$withval
+else
+ with_retpoline=keep
+fi
+
+
+
+ if test "$enable_hardening" = yes; then :
+
+ case "$host" in
+ *)
+ as_gl_Warn=`$as_echo "gl_cv_warn_c_-mfunction-return=$with_retpoline" | $as_tr_sh`
+gl_positive="-mfunction-return=$with_retpoline"
+case $gl_positive in
+ -Wno-*) gl_positive=-W`expr "X$gl_positive" : 'X-Wno-\(.*\)'` ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -mfunction-return=$with_retpoline" >&5
+$as_echo_n "checking whether C compiler handles -mfunction-return=$with_retpoline... " >&6; }
+if eval \${$as_gl_Warn+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CFLAGS"
+ as_fn_append CFLAGS " $gl_unknown_warnings_are_errors $gl_positive"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$as_gl_Warn=yes"
+else
+ eval "$as_gl_Warn=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+eval ac_res=\$$as_gl_Warn
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_gl_Warn"\" = x"yes"; then :
+ CFLAGS="$CFLAGS -mfunction-return=$with_retpoline"
+fi
+
+ as_gl_Warn=`$as_echo "gl_cv_warn_c_-mindirect-branch=$with_retpoline" | $as_tr_sh`
+gl_positive="-mindirect-branch=$with_retpoline"
+case $gl_positive in
+ -Wno-*) gl_positive=-W`expr "X$gl_positive" : 'X-Wno-\(.*\)'` ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -mindirect-branch=$with_retpoline" >&5
+$as_echo_n "checking whether C compiler handles -mindirect-branch=$with_retpoline... " >&6; }
+if eval \${$as_gl_Warn+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CFLAGS"
+ as_fn_append CFLAGS " $gl_unknown_warnings_are_errors $gl_positive"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$as_gl_Warn=yes"
+else
+ eval "$as_gl_Warn=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+eval ac_res=\$$as_gl_Warn
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_gl_Warn"\" = x"yes"; then :
+
+ CFLAGS="$CFLAGS -mindirect-branch=$with_retpoline"
+
+fi
+
+ esac
+
+fi
+
+
+ RELRO_LDFLAGS=
+ if test "$enable_hardening" = yes; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for how to force completely read-only GOT table" >&5
+$as_echo_n "checking for how to force completely read-only GOT table... " >&6; }
+ ld_help=`$CC -Wl,-help 2>&1`
+ case $ld_help in
+ *"-z relro"*) RELRO_LDFLAGS="-Wl,-z -Wl,relro" ;;
+ esac
+ case $ld_help in
+ *"-z now"*) RELRO_LDFLAGS="$RELRO_LDFLAGS -Wl,-z -Wl,now" ;;
+ esac
+ if test "x$RELRO_LDFLAGS" != "x"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RELRO_LDFLAGS" >&5
+$as_echo "$RELRO_LDFLAGS" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unknown" >&5
+$as_echo "unknown" >&6; }
+
+fi
+
+fi
+
+
+
+ # Check whether --enable-ubsan was given.
+if test "${enable_ubsan+set}" = set; then :
+ enableval=$enable_ubsan; want_ubsan=yes
+else
+ want_ubsan=no
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we want undefined behaviour sanitizer" >&5
+$as_echo_n "checking whether we want undefined behaviour sanitizer... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $want_ubsan" >&5
+$as_echo "$want_ubsan" >&6; }
+ if test x$want_ubsan = xyes; then :
+
+ san_flags=""
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -fsanitize=undefined" >&5
+$as_echo_n "checking whether C compiler handles -fsanitize=undefined... " >&6; }
+if ${gl_cv_warn_c__fsanitize_undefined+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CFLAGS"
+ as_fn_append CFLAGS " $gl_unknown_warnings_are_errors -fsanitize=undefined"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ gl_cv_warn_c__fsanitize_undefined=yes
+else
+ gl_cv_warn_c__fsanitize_undefined=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__fsanitize_undefined" >&5
+$as_echo "$gl_cv_warn_c__fsanitize_undefined" >&6; }
+if test "x$gl_cv_warn_c__fsanitize_undefined" = xyes; then :
+
+ san_flags="$san_flags -fsanitize=undefined"
+
+$as_echo "#define HAVE_FSANITIZE_UNDEFINED 1" >>confdefs.h
+
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -fno-sanitize=nonnull-attribute" >&5
+$as_echo_n "checking whether C compiler handles -fno-sanitize=nonnull-attribute... " >&6; }
+if ${gl_cv_warn_c__fno_sanitize_nonnull_attribute+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CFLAGS"
+ as_fn_append CFLAGS " $gl_unknown_warnings_are_errors -fno-sanitize=nonnull-attribute"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ gl_cv_warn_c__fno_sanitize_nonnull_attribute=yes
+else
+ gl_cv_warn_c__fno_sanitize_nonnull_attribute=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__fno_sanitize_nonnull_attribute" >&5
+$as_echo "$gl_cv_warn_c__fno_sanitize_nonnull_attribute" >&6; }
+if test "x$gl_cv_warn_c__fno_sanitize_nonnull_attribute" = xyes; then :
+
+ san_flags="$san_flags -fno-sanitize=nonnull-attribute"
+
+$as_echo "#define HAVE_FNO_SANITIZE_NONNULL_ATTRIBUTE 1" >>confdefs.h
+
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -fsanitize=implicit-integer-truncation" >&5
+$as_echo_n "checking whether C compiler handles -fsanitize=implicit-integer-truncation... " >&6; }
+if ${gl_cv_warn_c__fsanitize_implicit_integer_truncation+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CFLAGS"
+ as_fn_append CFLAGS " $gl_unknown_warnings_are_errors -fsanitize=implicit-integer-truncation"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ gl_cv_warn_c__fsanitize_implicit_integer_truncation=yes
+else
+ gl_cv_warn_c__fsanitize_implicit_integer_truncation=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__fsanitize_implicit_integer_truncation" >&5
+$as_echo "$gl_cv_warn_c__fsanitize_implicit_integer_truncation" >&6; }
+if test "x$gl_cv_warn_c__fsanitize_implicit_integer_truncation" = xyes; then :
+
+ san_flags="$san_flags -fsanitize=implicit-integer-truncation"
+
+$as_echo "#define HAVE_FSANITIZE_IMPLICIT_INTEGER_TRUNCATION 1" >>confdefs.h
+
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -fsanitize=local-bounds" >&5
+$as_echo_n "checking whether C compiler handles -fsanitize=local-bounds... " >&6; }
+if ${gl_cv_warn_c__fsanitize_local_bounds+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CFLAGS"
+ as_fn_append CFLAGS " $gl_unknown_warnings_are_errors -fsanitize=local-bounds"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ gl_cv_warn_c__fsanitize_local_bounds=yes
+else
+ gl_cv_warn_c__fsanitize_local_bounds=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__fsanitize_local_bounds" >&5
+$as_echo "$gl_cv_warn_c__fsanitize_local_bounds" >&6; }
+if test "x$gl_cv_warn_c__fsanitize_local_bounds" = xyes; then :
+
+ san_flags="$san_flags -fsanitize=local-bounds"
+
+$as_echo "#define HAVE_FSANITIZE_LOCAL_BOUNDS 1" >>confdefs.h
+
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -fsanitize=integer" >&5
+$as_echo_n "checking whether C compiler handles -fsanitize=integer... " >&6; }
+if ${gl_cv_warn_c__fsanitize_integer+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CFLAGS"
+ as_fn_append CFLAGS " $gl_unknown_warnings_are_errors -fsanitize=integer"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ gl_cv_warn_c__fsanitize_integer=yes
+else
+ gl_cv_warn_c__fsanitize_integer=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__fsanitize_integer" >&5
+$as_echo "$gl_cv_warn_c__fsanitize_integer" >&6; }
+if test "x$gl_cv_warn_c__fsanitize_integer" = xyes; then :
+
+ san_flags="$san_flags -fsanitize=integer"
+
+$as_echo "#define HAVE_FSANITIZE_INTEGER 1" >>confdefs.h
+
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -fsanitize=nullability" >&5
+$as_echo_n "checking whether C compiler handles -fsanitize=nullability... " >&6; }
+if ${gl_cv_warn_c__fsanitize_nullability+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CFLAGS"
+ as_fn_append CFLAGS " $gl_unknown_warnings_are_errors -fsanitize=nullability"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ gl_cv_warn_c__fsanitize_nullability=yes
+else
+ gl_cv_warn_c__fsanitize_nullability=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__fsanitize_nullability" >&5
+$as_echo "$gl_cv_warn_c__fsanitize_nullability" >&6; }
+if test "x$gl_cv_warn_c__fsanitize_nullability" = xyes; then :
+
+ san_flags="$san_flags -fsanitize=nullability"
+
+$as_echo "#define HAVE_FSANITIZE_NULLABILITY 1" >>confdefs.h
+
+
+fi
+
+ if test "$san_flags" != "" ; then :
+
+ EXTRA_CFLAGS="$EXTRA_CFLAGS $san_flags -U_FORTIFY_SOURCE -g -ggdb3 -O0 -fno-omit-frame-pointer"
+
+$as_echo "#define HAVE_UNDEFINED_SANITIZER 1" >>confdefs.h
+
+
+else
+
+ as_fn_error $? "No undefined sanitizer support in your compiler" "$LINENO" 5
+
+fi
+ san_flags=""
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if test "$DOVECOT_INSTALLED" = "yes"; then
+ DOVECOT_INSTALLED_TRUE=
+ DOVECOT_INSTALLED_FALSE='#'
+else
+ DOVECOT_INSTALLED_TRUE='#'
+ DOVECOT_INSTALLED_FALSE=
+fi
+
+
+
+ _plugin_deps=yes
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OS supports plugin dependencies" >&5
+$as_echo_n "checking whether OS supports plugin dependencies... " >&6; }
+ case "$host_os" in
+ darwin*)
+ _plugin_deps=no
+ ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_plugin_deps" >&5
+$as_echo "$_plugin_deps" >&6; }
+ if test "x$_plugin_deps" = "xyes"; then
+ DOVECOT_PLUGIN_DEPS_TRUE=
+ DOVECOT_PLUGIN_DEPS_FALSE='#'
+else
+ DOVECOT_PLUGIN_DEPS_TRUE='#'
+ DOVECOT_PLUGIN_DEPS_FALSE=
+fi
+
+ unset _plugin_deps
+
+
+
+ # Extract the first word of "valgrind", so it can be a program name with args.
+set dummy valgrind; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_VALGRIND+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $VALGRIND in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_VALGRIND="$VALGRIND" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_VALGRIND="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_path_VALGRIND" && ac_cv_path_VALGRIND="reject"
+ ;;
+esac
+fi
+VALGRIND=$ac_cv_path_VALGRIND
+if test -n "$VALGRIND"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $VALGRIND" >&5
+$as_echo "$VALGRIND" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "$VALGRIND" != reject; then :
+
+ cat > run-test.sh <<_DC_EOF
+#!/bin/sh
+top_srcdir=\$1
+shift
+
+if test "\$NOUNDEF" != ""; then
+ noundef="--undef-value-errors=no"
+else
+ noundef=""
+fi
+
+if test "\$NOCHILDREN" != ""; then
+ trace_children="--trace-children=no"
+else
+ trace_children="--trace-children=yes"
+fi
+
+skip_path="\$top_srcdir/run-test-valgrind.exclude"
+if test -r "\$skip_path" && grep -w -q "\$(basename \$1)" "\$skip_path"; then
+ NOVALGRIND=true
+fi
+
+if test "\$NOVALGRIND" != ""; then
+ \$*
+ ret=\$?
+else
+ test_out="test.out~\$\$"
+ trap "rm -f \$test_out" 0 1 2 3 15
+ supp_path="\$top_srcdir/run-test-valgrind.supp"
+ if test -r "\$supp_path"; then
+ $VALGRIND -q \$trace_children --error-exitcode=213 --leak-check=full --gen-suppressions=all --suppressions="\$supp_path" --log-file=\$test_out \$noundef \$*
+ else
+ $VALGRIND -q \$trace_children --error-exitcode=213 --leak-check=full --gen-suppressions=all --log-file=\$test_out \$noundef \$*
+ fi
+ ret=\$?
+ if test -s \$test_out; then
+ cat \$test_out
+ ret=1
+ fi
+fi
+if test \$ret != 0; then
+ echo "Failed to run: \$*" >&2
+fi
+exit \$ret
+_DC_EOF
+ RUN_TEST='$(LIBTOOL) execute $(SHELL) $(top_builddir)/run-test.sh $(top_srcdir)'
+
+else
+
+ RUN_TEST=''
+
+fi
+
+
+
+
+
+# Check whether --with-moduledir was given.
+if test "${with_moduledir+set}" = set; then :
+ withval=$with_moduledir; moduledir="$withval"
+else
+ moduledir="$dovecot_moduledir"
+
+fi
+
+
+
+LIBDOVECOT_INCLUDE="$LIBDOVECOT_INCLUDE $LIBDOVECOT_STORAGE_INCLUDE"
+CFLAGS="$CFLAGS -I\$(top_srcdir)"
+LIBS="$DOVECOT_LIBS"
+BINARY_LDFLAGS="$PIE_LDFLAGS $RELRO_LDFLAGS"
+BINARY_CFLAGS="$PIE_CFLAGS"
+
+
+
+
+# Define Sieve documentation install dir
+#
+
+sieve_docdir='${dovecot_docdir}/sieve'
+
+
+# Extensions under development
+#
+
+
+# Check whether --with-unfinished-features was given.
+if test "${with_unfinished_features+set}" = set; then :
+ withval=$with_unfinished_features; if test x$withval = xno || test x$withval = xauto; then
+ want_unfinished_features=$withval
+ else
+ want_unfinished_features=yes
+ fi
+else
+ want_unfinished_features=no
+fi
+
+ if test "$want_unfinished_features" = "yes"; then
+ BUILD_UNFINISHED_TRUE=
+ BUILD_UNFINISHED_FALSE='#'
+else
+ BUILD_UNFINISHED_TRUE='#'
+ BUILD_UNFINISHED_FALSE=
+fi
+
+
+if test "$want_unfinished_features" = "yes"; then
+
+$as_echo "#define HAVE_SIEVE_UNFINISHED /**/" >>confdefs.h
+
+fi
+
+#
+#
+
+
+
+
+# Check whether --with-docs was given.
+if test "${with_docs+set}" = set; then :
+ withval=$with_docs; if test x$withval = xno; then
+ want_docs=no
+ else
+ want_docs=yes
+ fi
+else
+ want_docs=yes
+fi
+
+ if test "$want_docs" = "yes"; then
+ BUILD_DOCS_TRUE=
+ BUILD_DOCS_FALSE='#'
+else
+ BUILD_DOCS_TRUE='#'
+ BUILD_DOCS_FALSE=
+fi
+
+
+
+# Check whether --with-managesieve was given.
+if test "${with_managesieve+set}" = set; then :
+ withval=$with_managesieve; if test x$withval = xno || test x$withval = xauto; then
+ want_managesieve=$withval
+ else
+ want_managesieve=yes
+ fi
+else
+ want_managesieve=yes
+fi
+
+ if test "$want_managesieve" = "yes"; then
+ BUILD_MANAGESIEVE_TRUE=
+ BUILD_MANAGESIEVE_FALSE='#'
+else
+ BUILD_MANAGESIEVE_TRUE='#'
+ BUILD_MANAGESIEVE_FALSE=
+fi
+
+
+
+# Check whether --with-ldap was given.
+if test "${with_ldap+set}" = set; then :
+ withval=$with_ldap;
+ want=want_`echo ldap|sed s/-/_/g`
+ if test $withval = yes || test $withval = no || test $withval = auto; then
+ eval $want=$withval
+ elif test $withval = plugin; then
+ if test "plugin" = plugin; then
+ eval $want=plugin
+ else
+ as_fn_error $? "--with-ldap=plugin not supported" "$LINENO" 5
+ fi
+ elif `echo $withval|grep '^/' >/dev/null`; then
+ as_fn_error $? "--with-ldap=path not supported. You may want to use instead:
+CPPFLAGS=-I$withval/include LDFLAGS=-L$withval/lib ./configure --with-ldap" "$LINENO" 5
+ else
+ as_fn_error $? "--with-ldap: Unknown value: $withval" "$LINENO" 5
+ fi
+
+else
+ want_ldap=no
+fi
+
+
+# FIXME: Imported this from Dovecot auth for now. We're working on a proper
+# lib-ldap, but, until then, some code is duplicated.
+have_ldap=no
+if test $want_ldap != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldap_init in -lldap" >&5
+$as_echo_n "checking for ldap_init in -lldap... " >&6; }
+if ${ac_cv_lib_ldap_ldap_init+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lldap $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ldap_init ();
+int
+main ()
+{
+return ldap_init ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ldap_ldap_init=yes
+else
+ ac_cv_lib_ldap_ldap_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ldap_ldap_init" >&5
+$as_echo "$ac_cv_lib_ldap_ldap_init" >&6; }
+if test "x$ac_cv_lib_ldap_ldap_init" = xyes; then :
+
+ ac_fn_c_check_header_mongrel "$LINENO" "ldap.h" "ac_cv_header_ldap_h" "$ac_includes_default"
+if test "x$ac_cv_header_ldap_h" = xyes; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldap_initialize in -lldap" >&5
+$as_echo_n "checking for ldap_initialize in -lldap... " >&6; }
+if ${ac_cv_lib_ldap_ldap_initialize+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lldap $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ldap_initialize ();
+int
+main ()
+{
+return ldap_initialize ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ldap_ldap_initialize=yes
+else
+ ac_cv_lib_ldap_ldap_initialize=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ldap_ldap_initialize" >&5
+$as_echo "$ac_cv_lib_ldap_ldap_initialize" >&6; }
+if test "x$ac_cv_lib_ldap_ldap_initialize" = xyes; then :
+
+
+$as_echo "#define LDAP_HAVE_INITIALIZE /**/" >>confdefs.h
+
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldap_start_tls_s in -lldap" >&5
+$as_echo_n "checking for ldap_start_tls_s in -lldap... " >&6; }
+if ${ac_cv_lib_ldap_ldap_start_tls_s+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lldap $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ldap_start_tls_s ();
+int
+main ()
+{
+return ldap_start_tls_s ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ldap_ldap_start_tls_s=yes
+else
+ ac_cv_lib_ldap_ldap_start_tls_s=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ldap_ldap_start_tls_s" >&5
+$as_echo "$ac_cv_lib_ldap_ldap_start_tls_s" >&6; }
+if test "x$ac_cv_lib_ldap_ldap_start_tls_s" = xyes; then :
+
+
+$as_echo "#define LDAP_HAVE_START_TLS_S /**/" >>confdefs.h
+
+
+fi
+
+ LDAP_LIBS="-lldap"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ber_free in -lldap" >&5
+$as_echo_n "checking for ber_free in -lldap... " >&6; }
+if ${ac_cv_lib_ldap_ber_free+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lldap $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ber_free ();
+int
+main ()
+{
+return ber_free ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ldap_ber_free=yes
+else
+ ac_cv_lib_ldap_ber_free=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ldap_ber_free" >&5
+$as_echo "$ac_cv_lib_ldap_ber_free" >&6; }
+if test "x$ac_cv_lib_ldap_ber_free" = xyes; then :
+
+ # do nothing, default is to add -lldap to LIBS
+ :
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ber_free in -llber" >&5
+$as_echo_n "checking for ber_free in -llber... " >&6; }
+if ${ac_cv_lib_lber_ber_free+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-llber $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ber_free ();
+int
+main ()
+{
+return ber_free ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_lber_ber_free=yes
+else
+ ac_cv_lib_lber_ber_free=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lber_ber_free" >&5
+$as_echo "$ac_cv_lib_lber_ber_free" >&6; }
+if test "x$ac_cv_lib_lber_ber_free" = xyes; then :
+
+ LDAP_LIBS="$LDAP_LIBS -llber"
+
+fi
+
+
+fi
+
+
+ if test $want_ldap != plugin; then
+
+$as_echo "#define SIEVE_BUILTIN_LDAP /**/" >>confdefs.h
+
+ fi
+
+
+$as_echo "#define STORAGE_LDAP /**/" >>confdefs.h
+
+ for ac_header in sasl.h sasl/sasl.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+ have_ldap=yes
+
+else
+
+ if test $want_ldap != auto; then
+ as_fn_error $? "Can't build with LDAP support: ldap.h not found" "$LINENO" 5
+ fi
+
+fi
+
+
+
+else
+
+ if test $want_ldap != auto; then
+ as_fn_error $? "Can't build with LDAP support: libldap not found" "$LINENO" 5
+ fi
+
+fi
+
+fi
+
+if test $have_ldap = no; then
+ not_scriptloc="$not_scriptloc ldap"
+else
+ scriptloc="$scriptloc ldap"
+ if test $want_ldap = plugin; then
+ have_ldap_plugin=yes
+ scriptloc="$scriptloc (plugin)"
+ fi
+fi
+ if test "$have_ldap_plugin" = "yes"; then
+ LDAP_PLUGIN_TRUE=
+ LDAP_PLUGIN_FALSE='#'
+else
+ LDAP_PLUGIN_TRUE='#'
+ LDAP_PLUGIN_FALSE=
+fi
+
+
+CFLAGS="$CFLAGS $EXTRA_CFLAGS"
+LDFLAGS="$LDFLAGS $EXTRA_LDFLAGS"
+
+ac_config_files="$ac_config_files Makefile doc/Makefile doc/man/Makefile doc/example-config/Makefile doc/example-config/conf.d/Makefile doc/rfc/Makefile doc/extensions/Makefile doc/locations/Makefile doc/plugins/Makefile src/Makefile src/lib-sieve/Makefile src/lib-sieve/util/Makefile src/lib-sieve/storage/Makefile src/lib-sieve/storage/data/Makefile src/lib-sieve/storage/file/Makefile src/lib-sieve/storage/dict/Makefile src/lib-sieve/storage/ldap/Makefile src/lib-sieve/plugins/Makefile src/lib-sieve/plugins/vacation/Makefile src/lib-sieve/plugins/subaddress/Makefile src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile src/lib-sieve/plugins/relational/Makefile src/lib-sieve/plugins/regex/Makefile src/lib-sieve/plugins/imap4flags/Makefile src/lib-sieve/plugins/copy/Makefile src/lib-sieve/plugins/include/Makefile src/lib-sieve/plugins/body/Makefile src/lib-sieve/plugins/variables/Makefile src/lib-sieve/plugins/enotify/Makefile src/lib-sieve/plugins/enotify/mailto/Makefile src/lib-sieve/plugins/notify/Makefile src/lib-sieve/plugins/environment/Makefile src/lib-sieve/plugins/mailbox/Makefile src/lib-sieve/plugins/date/Makefile src/lib-sieve/plugins/spamvirustest/Makefile src/lib-sieve/plugins/ihave/Makefile src/lib-sieve/plugins/editheader/Makefile src/lib-sieve/plugins/metadata/Makefile src/lib-sieve/plugins/duplicate/Makefile src/lib-sieve/plugins/index/Makefile src/lib-sieve/plugins/mime/Makefile src/lib-sieve/plugins/special-use/Makefile src/lib-sieve/plugins/vnd.dovecot/Makefile src/lib-sieve/plugins/vnd.dovecot/debug/Makefile src/lib-sieve/plugins/vnd.dovecot/environment/Makefile src/lib-sieve/plugins/vnd.dovecot/report/Makefile src/lib-sieve-tool/Makefile src/lib-managesieve/Makefile src/plugins/Makefile src/plugins/doveadm-sieve/Makefile src/plugins/lda-sieve/Makefile src/plugins/sieve-extprograms/Makefile src/plugins/imapsieve/Makefile src/plugins/imap-filter-sieve/Makefile src/plugins/settings/Makefile src/sieve-tools/Makefile src/managesieve/Makefile src/managesieve-login/Makefile src/testsuite/Makefile stamp.h"
+
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
+$as_echo_n "checking that generated files are newer than configure... " >&6; }
+ if test -n "$am_sleep_pid"; then
+ # Hide warnings about reused PIDs.
+ wait $am_sleep_pid 2>/dev/null
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
+$as_echo "done" >&6; }
+ if test -n "$EXEEXT"; then
+ am__EXEEXT_TRUE=
+ am__EXEEXT_FALSE='#'
+else
+ am__EXEEXT_TRUE='#'
+ am__EXEEXT_FALSE=
+fi
+
+if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
+ as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${DOVECOT_INSTALLED_TRUE}" && test -z "${DOVECOT_INSTALLED_FALSE}"; then
+ as_fn_error $? "conditional \"DOVECOT_INSTALLED\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${DOVECOT_PLUGIN_DEPS_TRUE}" && test -z "${DOVECOT_PLUGIN_DEPS_FALSE}"; then
+ as_fn_error $? "conditional \"DOVECOT_PLUGIN_DEPS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${BUILD_UNFINISHED_TRUE}" && test -z "${BUILD_UNFINISHED_FALSE}"; then
+ as_fn_error $? "conditional \"BUILD_UNFINISHED\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${BUILD_DOCS_TRUE}" && test -z "${BUILD_DOCS_FALSE}"; then
+ as_fn_error $? "conditional \"BUILD_DOCS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${BUILD_MANAGESIEVE_TRUE}" && test -z "${BUILD_MANAGESIEVE_FALSE}"; then
+ as_fn_error $? "conditional \"BUILD_MANAGESIEVE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LDAP_PLUGIN_TRUE}" && test -z "${LDAP_PLUGIN_FALSE}"; then
+ as_fn_error $? "conditional \"LDAP_PLUGIN\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by Pigeonhole $as_me 0.5.21, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <dovecot@dovecot.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+Pigeonhole config.status 0.5.21
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`'
+want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
+DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
+sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`'
+nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
+lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
+lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`'
+configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in SHELL \
+ECHO \
+PATH_SEPARATOR \
+SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+OBJDUMP \
+deplibs_check_method \
+file_magic_cmd \
+file_magic_glob \
+want_nocaseglob \
+DLLTOOL \
+sharedlib_from_linklib_cmd \
+AR \
+AR_FLAGS \
+archiver_list_spec \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_import \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+lt_cv_nm_interface \
+nm_file_list_spec \
+lt_cv_truncate_bin \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_pic \
+lt_prog_compiler_wl \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+MANIFEST_TOOL \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_separator \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib; do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postlink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+configure_time_dlsearch_path \
+configure_time_lt_sys_library_path; do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+ac_aux_dir='$ac_aux_dir'
+
+# See if we are running on zsh, and set the options that allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}"; then
+ setopt NO_GLOB_SUBST
+fi
+
+
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ RM='$RM'
+ ofile='$ofile'
+
+
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "dummy-config.h") CONFIG_HEADERS="$CONFIG_HEADERS dummy-config.h" ;;
+ "pigeonhole-config.h") CONFIG_HEADERS="$CONFIG_HEADERS pigeonhole-config.h" ;;
+ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+ "doc/man/Makefile") CONFIG_FILES="$CONFIG_FILES doc/man/Makefile" ;;
+ "doc/example-config/Makefile") CONFIG_FILES="$CONFIG_FILES doc/example-config/Makefile" ;;
+ "doc/example-config/conf.d/Makefile") CONFIG_FILES="$CONFIG_FILES doc/example-config/conf.d/Makefile" ;;
+ "doc/rfc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/rfc/Makefile" ;;
+ "doc/extensions/Makefile") CONFIG_FILES="$CONFIG_FILES doc/extensions/Makefile" ;;
+ "doc/locations/Makefile") CONFIG_FILES="$CONFIG_FILES doc/locations/Makefile" ;;
+ "doc/plugins/Makefile") CONFIG_FILES="$CONFIG_FILES doc/plugins/Makefile" ;;
+ "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
+ "src/lib-sieve/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/Makefile" ;;
+ "src/lib-sieve/util/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/util/Makefile" ;;
+ "src/lib-sieve/storage/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/storage/Makefile" ;;
+ "src/lib-sieve/storage/data/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/storage/data/Makefile" ;;
+ "src/lib-sieve/storage/file/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/storage/file/Makefile" ;;
+ "src/lib-sieve/storage/dict/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/storage/dict/Makefile" ;;
+ "src/lib-sieve/storage/ldap/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/storage/ldap/Makefile" ;;
+ "src/lib-sieve/plugins/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/Makefile" ;;
+ "src/lib-sieve/plugins/vacation/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/vacation/Makefile" ;;
+ "src/lib-sieve/plugins/subaddress/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/subaddress/Makefile" ;;
+ "src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile" ;;
+ "src/lib-sieve/plugins/relational/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/relational/Makefile" ;;
+ "src/lib-sieve/plugins/regex/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/regex/Makefile" ;;
+ "src/lib-sieve/plugins/imap4flags/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/imap4flags/Makefile" ;;
+ "src/lib-sieve/plugins/copy/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/copy/Makefile" ;;
+ "src/lib-sieve/plugins/include/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/include/Makefile" ;;
+ "src/lib-sieve/plugins/body/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/body/Makefile" ;;
+ "src/lib-sieve/plugins/variables/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/variables/Makefile" ;;
+ "src/lib-sieve/plugins/enotify/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/enotify/Makefile" ;;
+ "src/lib-sieve/plugins/enotify/mailto/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/enotify/mailto/Makefile" ;;
+ "src/lib-sieve/plugins/notify/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/notify/Makefile" ;;
+ "src/lib-sieve/plugins/environment/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/environment/Makefile" ;;
+ "src/lib-sieve/plugins/mailbox/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/mailbox/Makefile" ;;
+ "src/lib-sieve/plugins/date/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/date/Makefile" ;;
+ "src/lib-sieve/plugins/spamvirustest/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/spamvirustest/Makefile" ;;
+ "src/lib-sieve/plugins/ihave/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/ihave/Makefile" ;;
+ "src/lib-sieve/plugins/editheader/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/editheader/Makefile" ;;
+ "src/lib-sieve/plugins/metadata/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/metadata/Makefile" ;;
+ "src/lib-sieve/plugins/duplicate/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/duplicate/Makefile" ;;
+ "src/lib-sieve/plugins/index/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/index/Makefile" ;;
+ "src/lib-sieve/plugins/mime/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/mime/Makefile" ;;
+ "src/lib-sieve/plugins/special-use/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/special-use/Makefile" ;;
+ "src/lib-sieve/plugins/vnd.dovecot/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/vnd.dovecot/Makefile" ;;
+ "src/lib-sieve/plugins/vnd.dovecot/debug/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/vnd.dovecot/debug/Makefile" ;;
+ "src/lib-sieve/plugins/vnd.dovecot/environment/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/vnd.dovecot/environment/Makefile" ;;
+ "src/lib-sieve/plugins/vnd.dovecot/report/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve/plugins/vnd.dovecot/report/Makefile" ;;
+ "src/lib-sieve-tool/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-sieve-tool/Makefile" ;;
+ "src/lib-managesieve/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib-managesieve/Makefile" ;;
+ "src/plugins/Makefile") CONFIG_FILES="$CONFIG_FILES src/plugins/Makefile" ;;
+ "src/plugins/doveadm-sieve/Makefile") CONFIG_FILES="$CONFIG_FILES src/plugins/doveadm-sieve/Makefile" ;;
+ "src/plugins/lda-sieve/Makefile") CONFIG_FILES="$CONFIG_FILES src/plugins/lda-sieve/Makefile" ;;
+ "src/plugins/sieve-extprograms/Makefile") CONFIG_FILES="$CONFIG_FILES src/plugins/sieve-extprograms/Makefile" ;;
+ "src/plugins/imapsieve/Makefile") CONFIG_FILES="$CONFIG_FILES src/plugins/imapsieve/Makefile" ;;
+ "src/plugins/imap-filter-sieve/Makefile") CONFIG_FILES="$CONFIG_FILES src/plugins/imap-filter-sieve/Makefile" ;;
+ "src/plugins/settings/Makefile") CONFIG_FILES="$CONFIG_FILES src/plugins/settings/Makefile" ;;
+ "src/sieve-tools/Makefile") CONFIG_FILES="$CONFIG_FILES src/sieve-tools/Makefile" ;;
+ "src/managesieve/Makefile") CONFIG_FILES="$CONFIG_FILES src/managesieve/Makefile" ;;
+ "src/managesieve-login/Makefile") CONFIG_FILES="$CONFIG_FILES src/managesieve-login/Makefile" ;;
+ "src/testsuite/Makefile") CONFIG_FILES="$CONFIG_FILES src/testsuite/Makefile" ;;
+ "stamp.h") CONFIG_FILES="$CONFIG_FILES stamp.h" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+ ac_MKDIR_P=$MKDIR_P
+ case $MKDIR_P in
+ [\\/$]* | ?:[\\/]* ) ;;
+ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$_am_arg" : 'X\(//\)[^/]' \| \
+ X"$_am_arg" : 'X\(//\)$' \| \
+ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+ :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+ "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+ # Older Autoconf quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ # TODO: see whether this extra hack can be removed once we start
+ # requiring Autoconf 2.70 or later.
+ case $CONFIG_FILES in #(
+ *\'*) :
+ eval set x "$CONFIG_FILES" ;; #(
+ *) :
+ set x $CONFIG_FILES ;; #(
+ *) :
+ ;;
+esac
+ shift
+ # Used to flag and report bootstrapping failures.
+ am_rc=0
+ for am_mf
+ do
+ # Strip MF so we end up with the name of the file.
+ am_mf=`$as_echo "$am_mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile which includes
+ # dependency-tracking related rules and includes.
+ # Grep'ing the whole file directly is not great: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \
+ || continue
+ am_dirpart=`$as_dirname -- "$am_mf" ||
+$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$am_mf" : 'X\(//\)[^/]' \| \
+ X"$am_mf" : 'X\(//\)$' \| \
+ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$am_mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ am_filepart=`$as_basename -- "$am_mf" ||
+$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$am_mf" : 'X\(//\)$' \| \
+ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$am_mf" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ { echo "$as_me:$LINENO: cd "$am_dirpart" \
+ && sed -e '/# am--include-marker/d' "$am_filepart" \
+ | $MAKE -f - am--depfiles" >&5
+ (cd "$am_dirpart" \
+ && sed -e '/# am--include-marker/d' "$am_filepart" \
+ | $MAKE -f - am--depfiles) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } || am_rc=$?
+ done
+ if test $am_rc -ne 0; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Something went wrong bootstrapping makefile fragments
+ for automatic dependency tracking. If GNU make was not used, consider
+ re-running the configure script with MAKE=\"gmake\" (or whatever is
+ necessary). You can also try re-running configure with the
+ '--disable-dependency-tracking' option to at least be able to build
+ the package (albeit without support for automatic dependency tracking).
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ { am_dirpart=; unset am_dirpart;}
+ { am_filepart=; unset am_filepart;}
+ { am_mf=; unset am_mf;}
+ { am_rc=; unset am_rc;}
+ rm -f conftest-deps.mk
+}
+ ;;
+ "libtool":C)
+
+ # See if we are running on zsh, and set the options that allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}"; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile=${ofile}T
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+# Generated automatically by $as_me ($PACKAGE) $VERSION
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit, 1996
+
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program or library that is built
+# using GNU Libtool, you may include this file under the same
+# distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags=''
+
+# Configured defaults for sys_lib_dlsearch_path munging.
+: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# Shared archive member basename,for filename based shared library versioning on AIX.
+shared_archive_member_spec=$shared_archive_member_spec
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# The PATH separator for the build system.
+PATH_SEPARATOR=$lt_PATH_SEPARATOR
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# convert \$build file names to \$host format.
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+
+# convert \$build files to toolchain format.
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+
+# An object symbol dumper.
+OBJDUMP=$lt_OBJDUMP
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method = "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# How to find potential files when deplibs_check_method = "file_magic".
+file_magic_glob=$lt_file_magic_glob
+
+# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
+want_nocaseglob=$lt_want_nocaseglob
+
+# DLL creation program.
+DLLTOOL=$lt_DLLTOOL
+
+# Command to associate shared and link libraries.
+sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
+
+# The archiver.
+AR=$lt_AR
+
+# Flags to create an archive.
+AR_FLAGS=$lt_AR_FLAGS
+
+# How to feed a file listing to the archiver.
+archiver_list_spec=$lt_archiver_list_spec
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm into a list of symbols to manually relocate.
+global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# The name lister interface.
+nm_interface=$lt_lt_cv_nm_interface
+
+# Specify filename containing input files for \$NM.
+nm_file_list_spec=$lt_nm_file_list_spec
+
+# The root where to search for dependent libraries,and where our libraries should be installed.
+lt_sysroot=$lt_sysroot
+
+# Command to truncate a binary pipe.
+lt_truncate_bin=$lt_lt_cv_truncate_bin
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Manifest tool.
+MANIFEST_TOOL=$lt_MANIFEST_TOOL
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Detected run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path
+
+# Explicit LT_SYS_LIBRARY_PATH set during ./configure time.
+configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \$shlibpath_var if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ cat <<'_LT_EOF' >> "$cfgfile"
+
+# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
+
+# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+# string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+# string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+# string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+# "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+# VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+ case x$2 in
+ x)
+ ;;
+ *:)
+ eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\"
+ ;;
+ x:*)
+ eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\"
+ ;;
+ *::*)
+ eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+ eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\"
+ ;;
+ *)
+ eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\"
+ ;;
+ esac
+}
+
+
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+ for cc_temp in $*""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+ done
+ func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+
+
+# ### END FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test set != "${COLLECT_NAMES+set}"; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+
+ltmain=$ac_aux_dir/ltmain.sh
+
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+
+ ;;
+
+ esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+not_scriptloc=`echo "$not_scriptloc"|sed 's/ / -/g'`
+
+echo
+echo "Install prefix . : $prefix"
+echo "script drivers . : file dict$scriptloc"
+if test "$not_scriptloc" != ""; then
+ echo " :$not_scriptloc"
+fi
+
diff --git a/pigeonhole/configure.ac b/pigeonhole/configure.ac
new file mode 100644
index 0000000..6239f62
--- /dev/null
+++ b/pigeonhole/configure.ac
@@ -0,0 +1,245 @@
+AC_PREREQ([2.59])
+
+# Be sure to update ABI version also if anything changes that might require
+# recompiling plugins. Most importantly that means if any structs are changed.
+AC_INIT([Pigeonhole], [0.5.21], [dovecot@dovecot.org], [dovecot-2.3-pigeonhole])
+AC_DEFINE_UNQUOTED([PIGEONHOLE_ABI_VERSION], "0.5.ABIv21($PACKAGE_VERSION)", [Pigeonhole ABI version])
+
+AC_CONFIG_AUX_DIR([.])
+AC_CONFIG_SRCDIR([src])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Autoheader is not needed and does more harm than good for this package. However, it is
+# tightly integrated in autoconf/automake and therefore it is difficult not to use it. As
+# a workaround we give autoheader a dummy config header to chew on and we handle the
+# real config header ourselves.
+AC_CONFIG_HEADERS([dummy-config.h pigeonhole-config.h])
+
+AC_DEFINE_UNQUOTED(PIGEONHOLE_NAME, "$PACKAGE_NAME",
+ [Define to the full name of Pigeonhole for Dovecot.])
+AC_DEFINE_UNQUOTED(PIGEONHOLE_VERSION, "$PACKAGE_VERSION",
+ [Define to the version of Pigeonhole for Dovecot.])
+
+AM_INIT_AUTOMAKE([no-define foreign tar-ustar])
+
+AM_MAINTAINER_MODE
+
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_LIBTOOL
+
+# Couple with Dovecot
+#
+
+DC_DOVECOT
+DC_DOVECOT_MODULEDIR
+LIBDOVECOT_INCLUDE="$LIBDOVECOT_INCLUDE $LIBDOVECOT_STORAGE_INCLUDE"
+CFLAGS="$CFLAGS -I\$(top_srcdir)"
+LIBS="$DOVECOT_LIBS"
+BINARY_LDFLAGS="$PIE_LDFLAGS $RELRO_LDFLAGS"
+BINARY_CFLAGS="$PIE_CFLAGS"
+AC_SUBST(BINARY_CFLAGS)
+AC_SUBST(BINARY_LDFLAGS)
+AC_SUBST(LIBDOVECOT_INCLUDE)
+
+# Define Sieve documentation install dir
+#
+
+sieve_docdir='${dovecot_docdir}/sieve'
+AC_SUBST(sieve_docdir)
+
+# Extensions under development
+#
+
+AC_ARG_WITH(unfinished-features,
+[AC_HELP_STRING([--with-unfinished-features],
+ [Build unfinished new features/extensions [default=no]])],
+ if test x$withval = xno || test x$withval = xauto; then
+ want_unfinished_features=$withval
+ else
+ want_unfinished_features=yes
+ fi,
+ want_unfinished_features=no)
+AM_CONDITIONAL(BUILD_UNFINISHED, test "$want_unfinished_features" = "yes")
+
+if test "$want_unfinished_features" = "yes"; then
+ AC_DEFINE(HAVE_SIEVE_UNFINISHED,,
+ [Define to build unfinished features/extensions.])
+fi
+
+#
+#
+
+dnl TEST_WITH(name, value, [plugin])
+AC_DEFUN([TEST_WITH], [
+ want=want_`echo $1|sed s/-/_/g`
+ if test $2 = yes || test $2 = no || test $2 = auto; then
+ eval $want=$2
+ elif test $2 = plugin; then
+ if test "$3" = plugin; then
+ eval $want=plugin
+ else
+ AC_ERROR([--with-$1=plugin not supported])
+ fi
+ elif `echo $2|grep '^/' >/dev/null`; then
+ AC_ERROR([--with-$1=path not supported. You may want to use instead:
+CPPFLAGS=-I$2/include LDFLAGS=-L$2/lib ./configure --with-$1])
+ else
+ AC_ERROR([--with-$1: Unknown value: $2])
+ fi
+])
+
+AC_ARG_WITH(docs,
+[ --with-docs Install documentation (default)],
+ if test x$withval = xno; then
+ want_docs=no
+ else
+ want_docs=yes
+ fi,
+ want_docs=yes)
+AM_CONDITIONAL(BUILD_DOCS, test "$want_docs" = "yes")
+
+AC_ARG_WITH(managesieve,
+[AC_HELP_STRING([--with-managesieve],
+ [Build ManageSieve service [default=yes]])],
+ if test x$withval = xno || test x$withval = xauto; then
+ want_managesieve=$withval
+ else
+ want_managesieve=yes
+ fi,
+ want_managesieve=yes)
+AM_CONDITIONAL(BUILD_MANAGESIEVE, test "$want_managesieve" = "yes")
+
+AC_ARG_WITH(ldap,
+AS_HELP_STRING([--with-ldap=yes|plugin], [Build with LDAP support]),
+ TEST_WITH(ldap, $withval, plugin),
+ want_ldap=no)
+
+# FIXME: Imported this from Dovecot auth for now. We're working on a proper
+# lib-ldap, but, until then, some code is duplicated.
+have_ldap=no
+if test $want_ldap != no; then
+ AC_CHECK_LIB(ldap, ldap_init, [
+ AC_CHECK_HEADER(ldap.h, [
+ AC_CHECK_LIB(ldap, ldap_initialize, [
+ AC_DEFINE(LDAP_HAVE_INITIALIZE,, [Define if you have ldap_initialize])
+ ])
+ AC_CHECK_LIB(ldap, ldap_start_tls_s, [
+ AC_DEFINE(LDAP_HAVE_START_TLS_S,, [Define if you have ldap_start_tls_s])
+ ])
+ LDAP_LIBS="-lldap"
+ AC_CHECK_LIB(ldap, ber_free, [
+ # do nothing, default is to add -lldap to LIBS
+ :
+ ], [
+ AC_CHECK_LIB(lber, ber_free, [
+ LDAP_LIBS="$LDAP_LIBS -llber"
+ ])
+ ])
+ AC_SUBST(LDAP_LIBS)
+ if test $want_ldap != plugin; then
+ AC_DEFINE(SIEVE_BUILTIN_LDAP,, [LDAP support is built in])
+ fi
+
+ AC_DEFINE(STORAGE_LDAP,, [Build with LDAP support])
+ AC_CHECK_HEADERS(sasl.h sasl/sasl.h)
+ have_ldap=yes
+ ], [
+ if test $want_ldap != auto; then
+ AC_ERROR([Can't build with LDAP support: ldap.h not found])
+ fi
+ ])
+ ], [
+ if test $want_ldap != auto; then
+ AC_ERROR([Can't build with LDAP support: libldap not found])
+ fi
+ ])
+fi
+
+if test $have_ldap = no; then
+ not_scriptloc="$not_scriptloc ldap"
+else
+ scriptloc="$scriptloc ldap"
+ if test $want_ldap = plugin; then
+ have_ldap_plugin=yes
+ scriptloc="$scriptloc (plugin)"
+ fi
+fi
+AM_CONDITIONAL(LDAP_PLUGIN, test "$have_ldap_plugin" = "yes")
+
+CFLAGS="$CFLAGS $EXTRA_CFLAGS"
+LDFLAGS="$LDFLAGS $EXTRA_LDFLAGS"
+
+AC_CONFIG_FILES([
+Makefile
+doc/Makefile
+doc/man/Makefile
+doc/example-config/Makefile
+doc/example-config/conf.d/Makefile
+doc/rfc/Makefile
+doc/extensions/Makefile
+doc/locations/Makefile
+doc/plugins/Makefile
+src/Makefile
+src/lib-sieve/Makefile
+src/lib-sieve/util/Makefile
+src/lib-sieve/storage/Makefile
+src/lib-sieve/storage/data/Makefile
+src/lib-sieve/storage/file/Makefile
+src/lib-sieve/storage/dict/Makefile
+src/lib-sieve/storage/ldap/Makefile
+src/lib-sieve/plugins/Makefile
+src/lib-sieve/plugins/vacation/Makefile
+src/lib-sieve/plugins/subaddress/Makefile
+src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile
+src/lib-sieve/plugins/relational/Makefile
+src/lib-sieve/plugins/regex/Makefile
+src/lib-sieve/plugins/imap4flags/Makefile
+src/lib-sieve/plugins/copy/Makefile
+src/lib-sieve/plugins/include/Makefile
+src/lib-sieve/plugins/body/Makefile
+src/lib-sieve/plugins/variables/Makefile
+src/lib-sieve/plugins/enotify/Makefile
+src/lib-sieve/plugins/enotify/mailto/Makefile
+src/lib-sieve/plugins/notify/Makefile
+src/lib-sieve/plugins/environment/Makefile
+src/lib-sieve/plugins/mailbox/Makefile
+src/lib-sieve/plugins/date/Makefile
+src/lib-sieve/plugins/spamvirustest/Makefile
+src/lib-sieve/plugins/ihave/Makefile
+src/lib-sieve/plugins/editheader/Makefile
+src/lib-sieve/plugins/metadata/Makefile
+src/lib-sieve/plugins/duplicate/Makefile
+src/lib-sieve/plugins/index/Makefile
+src/lib-sieve/plugins/mime/Makefile
+src/lib-sieve/plugins/special-use/Makefile
+src/lib-sieve/plugins/vnd.dovecot/Makefile
+src/lib-sieve/plugins/vnd.dovecot/debug/Makefile
+src/lib-sieve/plugins/vnd.dovecot/environment/Makefile
+src/lib-sieve/plugins/vnd.dovecot/report/Makefile
+src/lib-sieve-tool/Makefile
+src/lib-managesieve/Makefile
+src/plugins/Makefile
+src/plugins/doveadm-sieve/Makefile
+src/plugins/lda-sieve/Makefile
+src/plugins/sieve-extprograms/Makefile
+src/plugins/imapsieve/Makefile
+src/plugins/imap-filter-sieve/Makefile
+src/plugins/settings/Makefile
+src/sieve-tools/Makefile
+src/managesieve/Makefile
+src/managesieve-login/Makefile
+src/testsuite/Makefile
+stamp.h])
+
+AC_OUTPUT
+
+not_scriptloc=`echo "$not_scriptloc"|sed 's/ / -/g'`
+
+echo
+echo "Install prefix . : $prefix"
+echo "script drivers . : file dict$scriptloc"
+if test "$not_scriptloc" != ""; then
+ echo " :$not_scriptloc"
+fi
+
diff --git a/pigeonhole/depcomp b/pigeonhole/depcomp
new file mode 100755
index 0000000..6b39162
--- /dev/null
+++ b/pigeonhole/depcomp
@@ -0,0 +1,791 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by 'PROGRAMS ARGS'.
+ object Object file output by 'PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputting dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+# Get the directory component of the given path, and save it in the
+# global variables '$dir'. Note that this directory component will
+# be either empty or ending with a '/' character. This is deliberate.
+set_dir_from ()
+{
+ case $1 in
+ */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
+ *) dir=;;
+ esac
+}
+
+# Get the suffix-stripped basename of the given path, and save it the
+# global variable '$base'.
+set_base_from ()
+{
+ base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
+}
+
+# If no dependency file was actually created by the compiler invocation,
+# we still have to create a dummy depfile, to avoid errors with the
+# Makefile "include basename.Plo" scheme.
+make_dummy_depfile ()
+{
+ echo "#dummy" > "$depfile"
+}
+
+# Factor out some common post-processing of the generated depfile.
+# Requires the auxiliary global variable '$tmpdepfile' to be set.
+aix_post_process_depfile ()
+{
+ # If the compiler actually managed to produce a dependency file,
+ # post-process it.
+ if test -f "$tmpdepfile"; then
+ # Each line is of the form 'foo.o: dependency.h'.
+ # Do two passes, one to just change these to
+ # $object: dependency.h
+ # and one to simply output
+ # dependency.h:
+ # which is needed to avoid the deleted-header problem.
+ { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
+ sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
+ } > "$depfile"
+ rm -f "$tmpdepfile"
+ else
+ make_dummy_depfile
+ fi
+}
+
+# A tabulation character.
+tab=' '
+# A newline character.
+nl='
+'
+# Character ranges might be problematic outside the C locale.
+# These definitions help.
+upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
+lower=abcdefghijklmnopqrstuvwxyz
+digits=0123456789
+alpha=${upper}${lower}
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Avoid interferences from the environment.
+gccflag= dashmflag=
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+ # This is just like msvisualcpp but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+ # This is just like msvc7 but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvc7
+fi
+
+if test "$depmode" = xlc; then
+ # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
+ gccflag=-qmakedep=gcc,-MF
+ depmode=gcc
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am. Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+ for arg
+ do
+ case $arg in
+ -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+ *) set fnord "$@" "$arg" ;;
+ esac
+ shift # fnord
+ shift # $arg
+ done
+ "$@"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
+## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
+## (see the conditional assignment to $gccflag above).
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say). Also, it might not be
+## supported by the other compilers which use the 'gcc' depmode.
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The second -e expression handles DOS-style file names with drive
+ # letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the "deleted header file" problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+## Some versions of gcc put a space before the ':'. On the theory
+## that the space means something, we add a space to the output as
+## well. hp depmode also adds that space, but also prefixes the VPATH
+## to the object. Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like '#:fec' to the end of the
+ # dependency line.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
+ | tr "$nl" ' ' >> "$depfile"
+ echo >> "$depfile"
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> "$depfile"
+ else
+ make_dummy_depfile
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+xlc)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts '$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ set_dir_from "$object"
+ set_base_from "$object"
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$base.u
+ tmpdepfile3=$dir.libs/$base.u
+ "$@" -Wc,-M
+ else
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$dir$base.u
+ tmpdepfile3=$dir$base.u
+ "$@" -M
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ aix_post_process_depfile
+ ;;
+
+tcc)
+ # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
+ # FIXME: That version still under development at the moment of writing.
+ # Make that this statement remains true also for stable, released
+ # versions.
+ # It will wrap lines (doesn't matter whether long or short) with a
+ # trailing '\', as in:
+ #
+ # foo.o : \
+ # foo.c \
+ # foo.h \
+ #
+ # It will put a trailing '\' even on the last line, and will use leading
+ # spaces rather than leading tabs (at least since its commit 0394caf7
+ # "Emit spaces for -MD").
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
+ # We have to change lines of the first kind to '$object: \'.
+ sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
+ # And for each line of the second kind, we have to emit a 'dep.h:'
+ # dummy dependency, to avoid the deleted-header problem.
+ sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+## The order of this option in the case statement is important, since the
+## shell code in configure will try each of these formats in the order
+## listed in this file. A plain '-MD' option would be understood by many
+## compilers, so we must ensure this comes after the gcc and icc options.
+pgcc)
+ # Portland's C compiler understands '-MD'.
+ # Will always output deps to 'file.d' where file is the root name of the
+ # source file under compilation, even if file resides in a subdirectory.
+ # The object file name does not affect the name of the '.d' file.
+ # pgcc 10.2 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using '\' :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+ set_dir_from "$object"
+ # Use the source, not the object, to determine the base name, since
+ # that's sadly what pgcc will do too.
+ set_base_from "$source"
+ tmpdepfile=$base.d
+
+ # For projects that build the same source file twice into different object
+ # files, the pgcc approach of using the *source* file root name can cause
+ # problems in parallel builds. Use a locking strategy to avoid stomping on
+ # the same $tmpdepfile.
+ lockdir=$base.d-lock
+ trap "
+ echo '$0: caught signal, cleaning up...' >&2
+ rmdir '$lockdir'
+ exit 1
+ " 1 2 13 15
+ numtries=100
+ i=$numtries
+ while test $i -gt 0; do
+ # mkdir is a portable test-and-set.
+ if mkdir "$lockdir" 2>/dev/null; then
+ # This process acquired the lock.
+ "$@" -MD
+ stat=$?
+ # Release the lock.
+ rmdir "$lockdir"
+ break
+ else
+ # If the lock is being held by a different process, wait
+ # until the winning process is done or we timeout.
+ while test -d "$lockdir" && test $i -gt 0; do
+ sleep 1
+ i=`expr $i - 1`
+ done
+ fi
+ i=`expr $i - 1`
+ done
+ trap - 1 2 13 15
+ if test $i -le 0; then
+ echo "$0: failed to acquire lock after $numtries attempts" >&2
+ echo "$0: check lockdir '$lockdir'" >&2
+ exit 1
+ fi
+
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp2)
+ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+ # compilers, which have integrated preprocessors. The correct option
+ # to use with these is +Maked; it writes dependencies to a file named
+ # 'foo.d', which lands next to the object file, wherever that
+ # happens to be.
+ # Much of this is similar to the tru64 case; see comments there.
+ set_dir_from "$object"
+ set_base_from "$object"
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir.libs/$base.d
+ "$@" -Wc,+Maked
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ "$@" +Maked
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
+ # Add 'dependent.h:' lines.
+ sed -ne '2,${
+ s/^ *//
+ s/ \\*$//
+ s/$/:/
+ p
+ }' "$tmpdepfile" >> "$depfile"
+ else
+ make_dummy_depfile
+ fi
+ rm -f "$tmpdepfile" "$tmpdepfile2"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in 'foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ set_dir_from "$object"
+ set_base_from "$object"
+
+ if test "$libtool" = yes; then
+ # Libtool generates 2 separate objects for the 2 libraries. These
+ # two compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir$base.o.d # libtool 1.5
+ tmpdepfile2=$dir.libs/$base.o.d # Likewise.
+ tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ # Same post-processing that is required for AIX mode.
+ aix_post_process_depfile
+ ;;
+
+msvc7)
+ if test "$libtool" = yes; then
+ showIncludes=-Wc,-showIncludes
+ else
+ showIncludes=-showIncludes
+ fi
+ "$@" $showIncludes > "$tmpdepfile"
+ stat=$?
+ grep -v '^Note: including file: ' "$tmpdepfile"
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The first sed program below extracts the file names and escapes
+ # backslashes for cygpath. The second sed program outputs the file
+ # name when reading, but also accumulates all include files in the
+ # hold buffer in order to output them again at the end. This only
+ # works with sed implementations that can handle large buffers.
+ sed < "$tmpdepfile" -n '
+/^Note: including file: *\(.*\)/ {
+ s//\1/
+ s/\\/\\\\/g
+ p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/'"$tab"'\1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+ s/.*/'"$tab"'/
+ G
+ p
+}' >> "$depfile"
+ echo >> "$depfile" # make sure the fragment doesn't end with a backslash
+ rm -f "$tmpdepfile"
+ ;;
+
+msvc7msys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove '-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for ':'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+ "$@" $dashmflag |
+ sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this sed invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no eat=no
+ for arg
+ do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ if test $eat = yes; then
+ eat=no
+ continue
+ fi
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -arch)
+ eat=yes ;;
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix=`echo "$object" | sed 's/^.*\././'`
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ # makedepend may prepend the VPATH from the source file name to the object.
+ # No need to regex-escape $object, excess matching of '.' is harmless.
+ sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process the last invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed '1,2d' "$tmpdepfile" \
+ | tr ' ' "$nl" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove '-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E \
+ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ | sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E 2>/dev/null |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+ echo "$tab" >> "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvcmsys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/pigeonhole/doc/Makefile.am b/pigeonhole/doc/Makefile.am
new file mode 100644
index 0000000..5131ece
--- /dev/null
+++ b/pigeonhole/doc/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS = \
+ man \
+ example-config \
+ rfc \
+ extensions \
+ locations \
+ plugins
+
+docfiles =
+
+if BUILD_DOCS
+sieve_doc_DATA = $(docfiles)
+endif
+
+EXTRA_DIST = \
+ devel \
+ $(docfiles)
+
diff --git a/pigeonhole/doc/Makefile.in b/pigeonhole/doc/Makefile.in
new file mode 100644
index 0000000..4ac14f7
--- /dev/null
+++ b/pigeonhole/doc/Makefile.in
@@ -0,0 +1,760 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = doc
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(sieve_docdir)"
+DATA = $(sieve_doc_DATA)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = \
+ man \
+ example-config \
+ rfc \
+ extensions \
+ locations \
+ plugins
+
+docfiles =
+@BUILD_DOCS_TRUE@sieve_doc_DATA = $(docfiles)
+EXTRA_DIST = \
+ devel \
+ $(docfiles)
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign doc/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-sieve_docDATA: $(sieve_doc_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(sieve_doc_DATA)'; test -n "$(sieve_docdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sieve_docdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sieve_docdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(sieve_docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(sieve_docdir)" || exit $$?; \
+ done
+
+uninstall-sieve_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sieve_doc_DATA)'; test -n "$(sieve_docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(sieve_docdir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(DATA)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(sieve_docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-sieve_docDATA
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-sieve_docDATA
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-sieve_docDATA install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-sieve_docDATA
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/doc/devel/DESIGN b/pigeonhole/doc/devel/DESIGN
new file mode 100644
index 0000000..8e78112
--- /dev/null
+++ b/pigeonhole/doc/devel/DESIGN
@@ -0,0 +1,45 @@
+The compiler consists of the following stages:
+
+PARSER: sieve-parser.c, sieve-lexer.c
+ Parses the scriptfile and produces an abstract syntax tree for it
+ (sieve-ast.c).
+
+VALIDATOR: sieve-validator.c
+ Performs contextual analysis on the ast produced by the parser. This checks
+ for the validity of commands, tests and arguments. Also, the ast is decorated
+ with any context data acquired during the process. This context is used by the
+ last compiler stage.
+
+GENERATOR: sieve-generator.c
+ This last compiler stage uses a visitor pattern to wander through the ast and
+ produces sieve byte code (sieve-binary.c).
+
+The resulting (in-memory) binary can be fed to the interpreter for execution:
+
+INTERPRETER: sieve-interpreter.c
+ The interpreter executes the byte code and produces a sieve_result object.
+ This result is no more than just a collection of actions to be performed.
+ During execution, action commands add actions to the result. Duplates and
+ conflicts between actions are handled in this execution phase.
+
+RESULT: sieve-result.c sieve-actions.c
+ When the result is to be executed, it needs no further checking, as the
+ validity of the result was verified during interpretation already. The
+ result's actions are executed in a transaction-like atomic manner. If one of
+ the actions fails, the whole transaction is rolled back meaning that either
+ everything succeeds or everything fails. This is only possible to some extent:
+ transmitted responses can of course not be rolled back. However, these are
+ executed in the commit phase, meaning that they will only be performed if all
+ other actions were successful.
+
+Debugging:
+
+BINARY-DUMPER: sieve-code-dumper.c sieve-binary-dumper.c
+ A loaded binary can be dumped to a stream in human-readable form using the
+ binary-dumper. The binary-dumper displays information on all the blocks that
+ the binary consists off. Program code blocks are dumped using the code-dumper.
+ It's implementation is similar to the interpreter, with the exception that it
+ performs no actions and just sequentially wanders through the byte code
+ printing instructions along the way. The term human-readable is a bit optimistic
+ though; currently, the presented data looks like an assembly language.
+
diff --git a/pigeonhole/doc/example-config/Makefile.am b/pigeonhole/doc/example-config/Makefile.am
new file mode 100644
index 0000000..f30c9fb
--- /dev/null
+++ b/pigeonhole/doc/example-config/Makefile.am
@@ -0,0 +1,10 @@
+SUBDIRS = conf.d
+
+pkgsysconfdir = $(sysconfdir)/dovecot
+
+exampledir = $(dovecot_docdir)/example-config
+example_DATA = \
+ sieve-ldap.conf
+
+EXTRA_DIST = \
+ $(example_DATA)
diff --git a/pigeonhole/doc/example-config/Makefile.in b/pigeonhole/doc/example-config/Makefile.in
new file mode 100644
index 0000000..af6460c
--- /dev/null
+++ b/pigeonhole/doc/example-config/Makefile.in
@@ -0,0 +1,755 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = doc/example-config
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(exampledir)"
+DATA = $(example_DATA)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = conf.d
+pkgsysconfdir = $(sysconfdir)/dovecot
+exampledir = $(dovecot_docdir)/example-config
+example_DATA = \
+ sieve-ldap.conf
+
+EXTRA_DIST = \
+ $(example_DATA)
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/example-config/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign doc/example-config/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-exampleDATA: $(example_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(example_DATA)'; test -n "$(exampledir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(exampledir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(exampledir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(exampledir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(exampledir)" || exit $$?; \
+ done
+
+uninstall-exampleDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(example_DATA)'; test -n "$(exampledir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(exampledir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(DATA)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(exampledir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-exampleDATA
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-exampleDATA
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exampleDATA install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-exampleDATA
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/doc/example-config/conf.d/20-managesieve.conf b/pigeonhole/doc/example-config/conf.d/20-managesieve.conf
new file mode 100644
index 0000000..3f71b58
--- /dev/null
+++ b/pigeonhole/doc/example-config/conf.d/20-managesieve.conf
@@ -0,0 +1,84 @@
+##
+## ManageSieve specific settings
+##
+
+# Uncomment to enable managesieve protocol:
+#protocols = $protocols sieve
+
+# Service definitions
+
+#service managesieve-login {
+ #inet_listener sieve {
+ # port = 4190
+ #}
+
+ #inet_listener sieve_deprecated {
+ # port = 2000
+ #}
+
+ # Number of connections to handle before starting a new process. Typically
+ # the only useful values are 0 (unlimited) or 1. 1 is more secure, but 0
+ # is faster. <doc/wiki/LoginProcess.txt>
+ #service_count = 1
+
+ # Number of processes to always keep waiting for more connections.
+ #process_min_avail = 0
+
+ # If you set service_count=0, you probably need to grow this.
+ #vsz_limit = 64M
+#}
+
+#service managesieve {
+ # Max. number of ManageSieve processes (connections)
+ #process_limit = 1024
+#}
+
+# Service configuration
+
+protocol sieve {
+ # Maximum ManageSieve command line length in bytes. ManageSieve usually does
+ # not involve overly long command lines, so this setting will not normally
+ # need adjustment
+ #managesieve_max_line_length = 65536
+
+ # Maximum number of ManageSieve connections allowed for a user from each IP
+ # address.
+ # NOTE: The username is compared case-sensitively.
+ #mail_max_userip_connections = 10
+
+ # Space separated list of plugins to load (none known to be useful so far).
+ # Do NOT try to load IMAP plugins here.
+ #mail_plugins =
+
+ # MANAGESIEVE logout format string:
+ # %i - total number of bytes read from client
+ # %o - total number of bytes sent to client
+ # %{put_bytes} - Number of bytes saved using PUTSCRIPT command
+ # %{put_count} - Number of scripts saved using PUTSCRIPT command
+ # %{get_bytes} - Number of bytes read using GETCRIPT command
+ # %{get_count} - Number of scripts read using GETSCRIPT command
+ # %{get_bytes} - Number of bytes processed using CHECKSCRIPT command
+ # %{get_count} - Number of scripts checked using CHECKSCRIPT command
+ # %{deleted_count} - Number of scripts deleted using DELETESCRIPT command
+ # %{renamed_count} - Number of scripts renamed using RENAMESCRIPT command
+ #managesieve_logout_format = bytes=%i/%o
+
+ # To fool ManageSieve clients that are focused on CMU's timesieved you can
+ # specify the IMPLEMENTATION capability that Dovecot reports to clients.
+ # For example: 'Cyrus timsieved v2.2.13'
+ #managesieve_implementation_string = Dovecot Pigeonhole
+
+ # Explicitly specify the SIEVE and NOTIFY capability reported by the server
+ # before login. If left unassigned these will be reported dynamically
+ # according to what the Sieve interpreter supports by default (after login
+ # this may differ depending on the user).
+ #managesieve_sieve_capability =
+ #managesieve_notify_capability =
+
+ # The maximum number of compile errors that are returned to the client upon
+ # script upload or script verification.
+ #managesieve_max_compile_errors = 5
+
+ # Refer to 90-sieve.conf for script quota configuration and configuration of
+ # Sieve execution limits.
+}
diff --git a/pigeonhole/doc/example-config/conf.d/90-sieve-extprograms.conf b/pigeonhole/doc/example-config/conf.d/90-sieve-extprograms.conf
new file mode 100644
index 0000000..17dcb77
--- /dev/null
+++ b/pigeonhole/doc/example-config/conf.d/90-sieve-extprograms.conf
@@ -0,0 +1,44 @@
+# Sieve Extprograms plugin configuration
+
+# Don't forget to add the sieve_extprograms plugin to the sieve_plugins setting.
+# Also enable the extensions you need (one or more of vnd.dovecot.pipe,
+# vnd.dovecot.filter and vnd.dovecot.execute) by adding these to the
+# sieve_extensions or sieve_global_extensions settings. Restricting these
+# extensions to a global context using sieve_global_extensions is recommended.
+
+plugin {
+
+ # The directory where the program sockets are located for the
+ # vnd.dovecot.pipe, vnd.dovecot.filter and vnd.dovecot.execute extension
+ # respectively. The name of each unix socket contained in that directory
+ # directly maps to a program-name referenced from the Sieve script.
+ #sieve_pipe_socket_dir = sieve-pipe
+ #sieve_filter_socket_dir = sieve-filter
+ #sieve_execute_socket_dir = sieve-execute
+
+ # The directory where the scripts are located for direct execution by the
+ # vnd.dovecot.pipe, vnd.dovecot.filter and vnd.dovecot.execute extension
+ # respectively. The name of each script contained in that directory
+ # directly maps to a program-name referenced from the Sieve script.
+ #sieve_pipe_bin_dir = /usr/lib/dovecot/sieve-pipe
+ #sieve_filter_bin_dir = /usr/lib/dovecot/sieve-filter
+ #sieve_execute_bin_dir = /usr/lib/dovecot/sieve-execute
+}
+
+# An example program service called 'do-something' to pipe messages to
+#service do-something {
+ # Define the executed script as parameter to the sieve service
+ #executable = script /usr/lib/dovecot/sieve-pipe/do-something.sh
+
+ # Use some unprivileged user for executing the program
+ #user = dovenull
+
+ # The unix socket located in the sieve_pipe_socket_dir (as defined in the
+ # plugin {} section above)
+ #unix_listener sieve-pipe/do-something {
+ # LDA/LMTP must have access
+ # user = vmail
+ # mode = 0600
+ #}
+#}
+
diff --git a/pigeonhole/doc/example-config/conf.d/90-sieve.conf b/pigeonhole/doc/example-config/conf.d/90-sieve.conf
new file mode 100644
index 0000000..238bcf4
--- /dev/null
+++ b/pigeonhole/doc/example-config/conf.d/90-sieve.conf
@@ -0,0 +1,205 @@
+##
+## Settings for the Sieve interpreter
+##
+
+# Do not forget to enable the Sieve plugin in 15-lda.conf and 20-lmtp.conf
+# by adding it to the respective mail_plugins= settings.
+
+# The Sieve interpreter can retrieve Sieve scripts from several types of
+# locations. The default `file' location type is a local filesystem path
+# pointing to a Sieve script file or a directory containing multiple Sieve
+# script files. More complex setups can use other location types such as
+# `ldap' or `dict' to fetch Sieve scripts from remote databases.
+#
+# All settings that specify the location of one ore more Sieve scripts accept
+# the following syntax:
+#
+# location = [<type>:]path[;<option>[=<value>][;...]]
+#
+# If the type prefix is omitted, the script location type is 'file' and the
+# location is interpreted as a local filesystem path pointing to a Sieve script
+# file or directory. Refer to Pigeonhole wiki or INSTALL file for more
+# information.
+
+plugin {
+ # The location of the user's main Sieve script or script storage. The LDA
+ # Sieve plugin uses this to find the active script for Sieve filtering at
+ # delivery. The "include" extension uses this location for retrieving
+ # :personal" scripts. This is also where the ManageSieve service will store
+ # the user's scripts, if supported.
+ #
+ # Currently only the 'file:' location type supports ManageSieve operation.
+ # Other location types like 'dict:' and 'ldap:' can currently only
+ # be used as a read-only script source ().
+ #
+ # For the 'file:' type: use the ';active=' parameter to specify where the
+ # active script symlink is located.
+ # For other types: use the ';name=' parameter to specify the name of the
+ # default/active script.
+ sieve = file:~/sieve;active=~/.dovecot.sieve
+
+ # The default Sieve script when the user has none. This is the location of a
+ # global sieve script file, which gets executed ONLY if user's personal Sieve
+ # script doesn't exist. Be sure to pre-compile this script manually using the
+ # sievec command line tool if the binary is not stored in a global location.
+ # --> See sieve_before for executing scripts before the user's personal
+ # script.
+ #sieve_default = /var/lib/dovecot/sieve/default.sieve
+
+ # The name by which the default Sieve script (as configured by the
+ # sieve_default setting) is visible to the user through ManageSieve.
+ #sieve_default_name =
+
+ # Location for ":global" include scripts as used by the "include" extension.
+ #sieve_global =
+
+ # The location of a Sieve script that is run for any message that is about to
+ # be discarded; i.e., it is not delivered anywhere by the normal Sieve
+ # execution. This only happens when the "implicit keep" is canceled, by e.g.
+ # the "discard" action, and no actions that deliver the message are executed.
+ # This "discard script" can prevent discarding the message, by executing
+ # alternative actions. If the discard script does nothing, the message is
+ # still discarded as it would be when no discard script is configured.
+ #sieve_discard =
+
+ # Location Sieve of scripts that need to be executed before the user's
+ # personal script. If a 'file' location path points to a directory, all the
+ # Sieve scripts contained therein (with the proper `.sieve' extension) are
+ # executed. The order of execution within that directory is determined by the
+ # file names, using a normal 8bit per-character comparison.
+ #
+ # Multiple script locations can be specified by appending an increasing number
+ # to the setting name. The Sieve scripts found from these locations are added
+ # to the script execution sequence in the specified order. Reading the
+ # numbered sieve_before settings stops at the first missing setting, so no
+ # numbers may be skipped.
+ #sieve_before = /var/lib/dovecot/sieve.d/
+ #sieve_before2 = ldap:/etc/sieve-ldap.conf;name=ldap-domain
+ #sieve_before3 = (etc...)
+
+ # Identical to sieve_before, only the specified scripts are executed after the
+ # user's script (only when keep is still in effect!). Multiple script
+ # locations can be specified by appending an increasing number.
+ #sieve_after =
+ #sieve_after2 =
+ #sieve_after2 = (etc...)
+
+ # Which Sieve language extensions are available to users. By default, all
+ # supported extensions are available, except for deprecated extensions or
+ # those that are still under development. Some system administrators may want
+ # to disable certain Sieve extensions or enable those that are not available
+ # by default. This setting can use '+' and '-' to specify differences relative
+ # to the default. For example `sieve_extensions = +imapflags' will enable the
+ # deprecated imapflags extension in addition to all extensions were already
+ # enabled by default.
+ #sieve_extensions = +notify +imapflags
+
+ # Which Sieve language extensions are ONLY available in global scripts. This
+ # can be used to restrict the use of certain Sieve extensions to administrator
+ # control, for instance when these extensions can cause security concerns.
+ # This setting has higher precedence than the `sieve_extensions' setting
+ # (above), meaning that the extensions enabled with this setting are never
+ # available to the user's personal script no matter what is specified for the
+ # `sieve_extensions' setting. The syntax of this setting is similar to the
+ # `sieve_extensions' setting, with the difference that extensions are
+ # enabled or disabled for exclusive use in global scripts. Currently, no
+ # extensions are marked as such by default.
+ #sieve_global_extensions =
+
+ # The Pigeonhole Sieve interpreter can have plugins of its own. Using this
+ # setting, the used plugins can be specified. Check the Dovecot wiki
+ # (wiki2.dovecot.org) or the pigeonhole website
+ # (http://pigeonhole.dovecot.org) for available plugins.
+ # The sieve_extprograms plugin is included in this release.
+ #sieve_plugins =
+
+ # The maximum size of a Sieve script. The compiler will refuse to compile any
+ # script larger than this limit. If set to 0, no limit on the script size is
+ # enforced.
+ #sieve_max_script_size = 1M
+
+ # The maximum number of actions that can be performed during a single script
+ # execution. If set to 0, no limit on the total number of actions is enforced.
+ #sieve_max_actions = 32
+
+ # The maximum number of redirect actions that can be performed during a single
+ # script execution. If set to 0, no redirect actions are allowed.
+ #sieve_max_redirects = 4
+
+ # The maximum number of personal Sieve scripts a single user can have. If set
+ # to 0, no limit on the number of scripts is enforced.
+ # (Currently only relevant for ManageSieve)
+ #sieve_quota_max_scripts = 0
+
+ # The maximum amount of disk storage a single user's scripts may occupy. If
+ # set to 0, no limit on the used amount of disk storage is enforced.
+ # (Currently only relevant for ManageSieve)
+ #sieve_quota_max_storage = 0
+
+ # The primary e-mail address for the user. This is used as a default when no
+ # other appropriate address is available for sending messages. If this setting
+ # is not configured, either the postmaster or null "<>" address is used as a
+ # sender, depending on the action involved. This setting is important when
+ # there is no message envelope to extract addresses from, such as when the
+ # script is executed in IMAP.
+ #sieve_user_email =
+
+ # The path to the file where the user log is written. If not configured, a
+ # default location is used. If the main user's personal Sieve (as configured
+ # with sieve=) is a file, the logfile is set to <filename>.log by default. If
+ # it is not a file, the default user log file is ~/.dovecot.sieve.log.
+ #sieve_user_log =
+
+ # Specifies what envelope sender address is used for redirected messages.
+ # The following values are supported for this setting:
+ #
+ # "sender" - The sender address is used (default).
+ # "recipient" - The final recipient address is used.
+ # "orig_recipient" - The original recipient is used.
+ # "user_email" - The user's primary address is used. This is
+ # configured with the "sieve_user_email" setting. If
+ # that setting is unconfigured, "user_mail" is equal to
+ # "recipient".
+ # "postmaster" - The postmaster_address configured for the LDA.
+ # "<user@domain>" - Redirected messages are always sent from user@domain.
+ # The angle brackets are mandatory. The null "<>" address
+ # is also supported.
+ #
+ # This setting is ignored when the envelope sender is "<>". In that case the
+ # sender of the redirected message is also always "<>".
+ #sieve_redirect_envelope_from = sender
+
+ ## TRACE DEBUGGING
+ # Trace debugging provides detailed insight in the operations performed by
+ # the Sieve script. These settings apply to both the LDA Sieve plugin and the
+ # IMAPSIEVE plugin.
+ #
+ # WARNING: On a busy server, this functionality can quickly fill up the trace
+ # directory with a lot of trace files. Enable this only temporarily and as
+ # selective as possible.
+
+ # The directory where trace files are written. Trace debugging is disabled if
+ # this setting is not configured or if the directory does not exist. If the
+ # path is relative or it starts with "~/" it is interpreted relative to the
+ # current user's home directory.
+ #sieve_trace_dir =
+
+ # The verbosity level of the trace messages. Trace debugging is disabled if
+ # this setting is not configured. Possible values are:
+ #
+ # "actions" - Only print executed action commands, like keep,
+ # fileinto, reject and redirect.
+ # "commands" - Print any executed command, excluding test commands.
+ # "tests" - Print all executed commands and performed tests.
+ # "matching" - Print all executed commands, performed tests and the
+ # values matched in those tests.
+ #sieve_trace_level =
+
+ # Enables highly verbose debugging messages that are usually only useful for
+ # developers.
+ #sieve_trace_debug = no
+
+ # Enables showing byte code addresses in the trace output, rather than only
+ # the source line numbers.
+ #sieve_trace_addresses = no
+}
diff --git a/pigeonhole/doc/example-config/conf.d/Makefile.am b/pigeonhole/doc/example-config/conf.d/Makefile.am
new file mode 100644
index 0000000..8cea566
--- /dev/null
+++ b/pigeonhole/doc/example-config/conf.d/Makefile.am
@@ -0,0 +1,10 @@
+pkgsysconfdir = $(sysconfdir)/dovecot
+
+exampledir = $(dovecot_docdir)/example-config/conf.d
+example_DATA = \
+ 20-managesieve.conf \
+ 90-sieve.conf \
+ 90-sieve-extprograms.conf
+
+EXTRA_DIST = \
+ $(example_DATA)
diff --git a/pigeonhole/doc/example-config/conf.d/Makefile.in b/pigeonhole/doc/example-config/conf.d/Makefile.in
new file mode 100644
index 0000000..a32ed00
--- /dev/null
+++ b/pigeonhole/doc/example-config/conf.d/Makefile.in
@@ -0,0 +1,576 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = doc/example-config/conf.d
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(exampledir)"
+DATA = $(example_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkgsysconfdir = $(sysconfdir)/dovecot
+exampledir = $(dovecot_docdir)/example-config/conf.d
+example_DATA = \
+ 20-managesieve.conf \
+ 90-sieve.conf \
+ 90-sieve-extprograms.conf
+
+EXTRA_DIST = \
+ $(example_DATA)
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/example-config/conf.d/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign doc/example-config/conf.d/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-exampleDATA: $(example_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(example_DATA)'; test -n "$(exampledir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(exampledir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(exampledir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(exampledir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(exampledir)" || exit $$?; \
+ done
+
+uninstall-exampleDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(example_DATA)'; test -n "$(exampledir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(exampledir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(exampledir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-exampleDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-exampleDATA
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exampleDATA install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
+ uninstall-am uninstall-exampleDATA
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/doc/example-config/sieve-ldap.conf b/pigeonhole/doc/example-config/sieve-ldap.conf
new file mode 100644
index 0000000..0325ee5
--- /dev/null
+++ b/pigeonhole/doc/example-config/sieve-ldap.conf
@@ -0,0 +1,74 @@
+# This file needs to be accessible by the Sieve interpreter running in LDA/LMTP.
+# This requires acces by the mail user. Don't use privileged LDAP credentials
+# here as these may likely leak. Only search and read access is required.
+
+# Space separated list of LDAP hosts to use. host:port is allowed too.
+hosts = localhost
+
+# LDAP URIs to use. You can use this instead of hosts list. Note that this
+# setting isn't supported by all LDAP libraries.
+#uris =
+
+# Distinguished Name - the username used to login to the LDAP server.
+# Leave it commented out to bind anonymously.
+#dn =
+
+# Password for LDAP server, if dn is specified.
+#dnpass =
+
+# Use SASL binding instead of the simple binding. Note that this changes
+# ldap_version automatically to be 3 if it's lower.
+#sasl_bind = no
+# SASL mechanism name to use.
+#sasl_mech =
+# SASL realm to use.
+#sasl_realm =
+# SASL authorization ID, ie. the dnpass is for this "master user", but the
+# dn is still the logged in user. Normally you want to keep this empty.
+#sasl_authz_id =
+
+# Use TLS to connect to the LDAP server.
+#tls = no
+# TLS options, currently supported only with OpenLDAP:
+#tls_ca_cert_file =
+#tls_ca_cert_dir =
+#tls_cipher_suite =
+# TLS cert/key is used only if LDAP server requires a client certificate.
+#tls_cert_file =
+#tls_key_file =
+# Valid values: never, hard, demand, allow, try
+#tls_require_cert =
+
+# Use the given ldaprc path.
+#ldaprc_path =
+
+# LDAP library debug level as specified by LDAP_DEBUG_* in ldap_log.h.
+# -1 = everything. You may need to recompile OpenLDAP with debugging enabled
+# to get enough output.
+#debug_level = 0
+
+# LDAP protocol version to use. Likely 2 or 3.
+#ldap_version = 3
+
+# LDAP base. %variables can be used here.
+# For example: dc=mail, dc=example, dc=org
+base =
+
+# Dereference: never, searching, finding, always
+#deref = never
+
+# Search scope: base, onelevel, subtree
+#scope = subtree
+
+# Filter for user lookup. Some variables can be used:
+# %u - username
+# %n - user part in user@domain, same as %u if there's no domain
+# %d - domain part in user@domain, empty if there's no domain
+# %{name} - name of the Sieve script
+#sieve_ldap_filter = (&(objectClass=posixAccount)(uid=%u))
+
+# Attribute containing the Sieve script
+#sieve_ldap_script_attr = mailSieveRuleSource
+
+# Attribute used for modification tracking
+#sieve_ldap_mod_attr = modifyTimestamp
diff --git a/pigeonhole/doc/extensions/Makefile.am b/pigeonhole/doc/extensions/Makefile.am
new file mode 100644
index 0000000..54d6b86
--- /dev/null
+++ b/pigeonhole/doc/extensions/Makefile.am
@@ -0,0 +1,17 @@
+docfiles = \
+ duplicate.txt \
+ editheader.txt \
+ include.txt \
+ spamtest-virustest.txt \
+ vacation.txt \
+ vnd.dovecot.environment.txt \
+ vnd.dovecot.report.txt
+
+if BUILD_DOCS
+extensions_docdir = $(sieve_docdir)/extensions
+extensions_doc_DATA = $(docfiles)
+endif
+
+EXTRA_DIST = \
+ $(docfiles)
+
diff --git a/pigeonhole/doc/extensions/Makefile.in b/pigeonhole/doc/extensions/Makefile.in
new file mode 100644
index 0000000..b2c0c88
--- /dev/null
+++ b/pigeonhole/doc/extensions/Makefile.in
@@ -0,0 +1,580 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = doc/extensions
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(extensions_docdir)"
+DATA = $(extensions_doc_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+docfiles = \
+ duplicate.txt \
+ editheader.txt \
+ include.txt \
+ spamtest-virustest.txt \
+ vacation.txt \
+ vnd.dovecot.environment.txt \
+ vnd.dovecot.report.txt
+
+@BUILD_DOCS_TRUE@extensions_docdir = $(sieve_docdir)/extensions
+@BUILD_DOCS_TRUE@extensions_doc_DATA = $(docfiles)
+EXTRA_DIST = \
+ $(docfiles)
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/extensions/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign doc/extensions/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-extensions_docDATA: $(extensions_doc_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(extensions_doc_DATA)'; test -n "$(extensions_docdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(extensions_docdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(extensions_docdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(extensions_docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(extensions_docdir)" || exit $$?; \
+ done
+
+uninstall-extensions_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(extensions_doc_DATA)'; test -n "$(extensions_docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(extensions_docdir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(extensions_docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-extensions_docDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-extensions_docDATA
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am \
+ install-extensions_docDATA install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
+ uninstall-am uninstall-extensions_docDATA
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/doc/extensions/duplicate.txt b/pigeonhole/doc/extensions/duplicate.txt
new file mode 100644
index 0000000..962e69e
--- /dev/null
+++ b/pigeonhole/doc/extensions/duplicate.txt
@@ -0,0 +1,48 @@
+Duplicate Extension
+
+Relevant specifications
+=======================
+
+ doc/rfc/duplicate.rfc7352.txt
+
+Description
+===========
+
+The "duplicate" extension adds a new test command called "duplicate" to the
+Sieve language. This test adds the ability to detect duplications. The main
+application for this new test is handling duplicate deliveries commonly caused
+by mailing list subscriptions or redirected mail addresses. The detection is
+normally performed by matching the message ID to an internal list of message
+IDs from previously delivered messages. For more complex applications, the
+"duplicate" test can also use the content of a specific header field or other
+parts of the message.
+
+Refer to doc/rfc/duplicate.rfc7352.txt for a specification of the Sieve language
+extension. Previously, this extension was Dovecot-specific and available under
+the name "vnd.dovecot.duplicate". That implementation differs significantly from
+what is now published as an RFC, but for backwards compatibility the original
+extension is still supported.
+
+Configuration
+=============
+
+The "duplicate" extension is available by default. The "duplicate" extension has
+its own specific settings. The following settings are available (default
+values are indicated):
+
+sieve_duplicate_default_period = 14d
+sieve_duplicate_max_period = 7d
+ These options respectively specify the default and the maximum value for the
+ period after which tracked values are purged from the duplicate tracking
+ database. The period is specified in s(econds), unless followed by a d(ay),
+ h(our) or m(inute) specifier character.
+
+Example
+=======
+
+plugin {
+ sieve = ~/.dovecot.sieve
+
+ sieve_duplicate_default_period = 1h
+ sieve_duplicate_max_period = 1d
+}
diff --git a/pigeonhole/doc/extensions/editheader.txt b/pigeonhole/doc/extensions/editheader.txt
new file mode 100644
index 0000000..4c75831
--- /dev/null
+++ b/pigeonhole/doc/extensions/editheader.txt
@@ -0,0 +1,64 @@
+Editheader Extension
+
+Relevant specifications
+=======================
+
+ RFC5293 - doc/rfc/editheader.rfc5293.txt
+
+Description
+===========
+
+The editheader extension [RFC5293] enables Sieve scripts to delete and add
+message header fields, thereby allowing interaction with other components that
+consume or produce header fields.
+
+Configuration
+=============
+
+The editheader extension is not available by default and needs to be enabled
+explicitly by adding it to the sieve_extensions setting.
+
+The following settings can be configured for the editheader extension (default
+values are indicated):
+
+sieve_editheader_max_header_size = 2048
+ The maximum size in bytes of a header field value passed to the addheader
+ command. The minimum value for this setting is 1024 bytes. The value is in
+ bytes, unless followed by a k(ilo).
+
+sieve_editheader_forbid_add =
+ A space-separated list of headers that cannot be added to the message header.
+ Addition of the `Subject:' header cannot be prohibited, as required by the RFC
+ specification. Therefore, adding this header to this setting has no effect.
+
+sieve_editheader_forbid_delete =
+ A space-separated list of headers that cannot be deleted from the message
+ header. Deleting the `Received:' and `Auto-Submitted:' fields is always
+ forbidden, while removing the `Subject:' header cannot be prohibited,
+ as required by the RFC specification. Therefore, adding one of these headers
+ to this setting has no effect.
+
+sieve_editheader_protected =
+ A space-separated list of headers that cannot be added to or deleted from
+ the message header. This setting is provided for backwards compatibility. It
+ is a combination of the sieve_editheader_forbid_add and
+ sieve_editheader_forbid_delete settings. The same limitations apply.
+
+Invalid values for the settings above will make the Sieve interpreter log
+a warning and revert to the default values.
+
+Example
+=======
+
+plugin {
+ # Use editheader
+ sieve_extensions = +editheader
+
+ # Header fiels must not exceed one 1k
+ sieve_editheader_max_header_size = 1k
+
+ # Protected special headers
+ sieve_editheader_forbid_add = X-Verified
+ sieve_editheader_forbid_delete = X-Verified X-Seen
+}
+
diff --git a/pigeonhole/doc/extensions/include.txt b/pigeonhole/doc/extensions/include.txt
new file mode 100644
index 0000000..44cfacc
--- /dev/null
+++ b/pigeonhole/doc/extensions/include.txt
@@ -0,0 +1,32 @@
+Include Extension
+
+Relevant Specifications
+=======================
+
+ draft-ietf-sieve-include-05 - doc/rfc/draft-ietf-sieve-include-05.txt
+
+Description
+===========
+
+The Sieve include extension permits users to include one Sieve script into
+another. This can make managing large scripts or multiple sets of scripts much
+easier, and allows a site and its users to build up libraries of scripts. Users
+are able to include their own personal scripts or site-wide scripts.
+
+Included scripts can include more scripts of their own, yielding a tree of
+included scripts with the main script (typically the user's personal script) at
+its root.
+
+Configuration
+=============
+
+The include extension is available by default. The include extension has its own
+specific settings. The following settings can be configured for the include
+extension (default values are indicated):
+
+sieve_include_max_includes = 255
+ The maximum number of scripts that may be included. This is the total number
+ of scripts involved in the include tree.
+
+sieve_include_max_nesting_depth = 10
+ The maximum nesting depth for the include tree.
diff --git a/pigeonhole/doc/extensions/spamtest-virustest.txt b/pigeonhole/doc/extensions/spamtest-virustest.txt
new file mode 100644
index 0000000..2ac8ad4
--- /dev/null
+++ b/pigeonhole/doc/extensions/spamtest-virustest.txt
@@ -0,0 +1,140 @@
+Spamtest and Virustest Extensions
+
+Relevant Specifications
+=======================
+
+ RFC5235 - doc/rfc/spamvirustest.rfc5235.txt
+
+Description
+===========
+
+Using the spamtest and virustest extensions (RFC 5235), the Sieve language
+provides a uniform and standardized command interface for evaluating spam and
+virus tests performed on the message. Users no longer need to know what headers
+need to be checked and how the scanner's verdict is represented in the header
+field value. They only need to know how to use the spamtest (spamtestplus) and
+virustest extensions. This also gives GUI-based Sieve editors the means to
+provide a portable and easy to install interface for spam and virus filter
+configuration. The burden of specifying which headers need to be checked and how
+the scanner output is represented falls onto the Sieve administrator.
+
+Configuration
+=============
+
+The spamtest, spamtestplus and virustest extensions are not enabled by default
+and thus need to be enabled explicitly using the sieve_extensions setting.
+
+The following settings need to be configured for using the spamtest and
+spamtestplus extensions. The virustest extension has identical configuration
+settings, but with a `sieve_virustest_' prefix instead of a `sieve_spamtest_'
+prefix:
+
+sieve_spamtest_status_type = "score" / "strlen" / "text"
+ This specifies the type of status result that the spam/virus scanner produces.
+ This can either be a numeric score ("score"), a string of identical characters
+ ("strlen"), e.g. '*******', or a textual description, e.g. `Spam'
+ or `Not Spam'.
+
+sieve_spamtest_status_header = <header-field> [ ":" <regexp> ]
+ This specifies the header field that contains the result information of the
+ spam scanner and it may express the syntax of the content of the header. If no
+ matching header is found in the message, the spamtest command will match
+ against "0".
+
+ This is a structured setting. The first part specifies the header field name.
+ Optionally, an extended POSIX regular expression follows the header field
+ name, separated by a colon. Any whitespace directly following the colon is not
+ part of the regular expression. If the regular expression is omitted, any
+ header content is accepted and the full header value is used. When a regular
+ expression is used, it must specify one match value (inside brackets) that
+ yields the desired spam scanner result. If the header does not match the
+ regular expression or if no value match is found, the spamtest will match
+ against "0".
+
+sieve_spamtest_max_value =
+ This statically specifies the maximum value a numeric spam score can have.
+
+sieve_spamtest_max_header = <header-field> [ ":" <regexp> ]
+ Some spam scanners include the maximum score value in one of their status
+ headers. Using this setting, this maximum can be extracted from the message
+ itself instead of specifying the maximum manually using the setting
+ `sieve_spamtest_max_value' explained above. The syntax is identical to the
+ `sieve_spamtext_status_header' setting.
+
+sieve_spamtest_text_valueX =
+ When the `sieve_spamtest_status_type' setting is set to "text", these settings
+ specify that the spamtest command will match against "X" when the specified
+ string is equal to the text (extracted) from the status header. For spamtest,
+ values of X between 0 and 10 are recognized, while virustest only uses values
+ between 0 and 5.
+
+Examples
+========
+
+This section shows several configuration examples. Each example shows a specimen
+of valid virus/spam test headers that the given configuration will work on.
+
+Example 1
+---------
+
+Spam header: `X-Spam-Score: No, score=-3.2'
+
+plugin {
+ sieve_extensions = +spamtest +spamtestplus
+
+ sieve_spamtest_status_type = score
+ sieve_spamtest_status_header = \
+ X-Spam-Score: [[:alnum:]]+, score=(-?[[:digit:]]+\.[[:digit:]])
+ sieve_spamtest_max_value = 5.0
+}
+
+Example 2
+---------
+
+Spam header: `X-Spam-Status: Yes'
+
+plugin {
+ sieve_extensions = +spamtest +spamtestplus
+
+ sieve_spamtest_status_type = text
+ sieve_spamtest_status_header = X-Spam-Status
+ sieve_spamtest_text_value1 = No
+ sieve_spamtest_text_value10 = Yes
+}
+
+Example 3
+---------
+
+Spam header: `X-Spam-Score: sssssss'
+
+plugin {
+ sieve_extensions = +spamtest +spamtestplus
+
+ sieve_spamtest_status_header = X-Spam-Score
+ sieve_spamtest_status_type = strlen
+ sieve_spamtest_max_value = 5
+}
+
+Example 4
+---------
+
+Spam header: `X-Spam-Score: status=3.2 required=5.0'
+Virus header: `X-Virus-Scan: Found to be clean.'
+
+plugin {
+ sieve_extensions = +spamtest +spamtestplus +virustest
+
+ sieve_spamtest_status_type = score
+ sieve_spamtest_status_header = \
+ X-Spam-Score: score=(-?[[:digit:]]+\.[[:digit:]]).*
+ sieve_spamtest_max_header = \
+ X-Spam-Score: score=-?[[:digit:]]+\.[[:digit:]] required=([[:digit:]]+\.[[:digit:]])
+
+ sieve_virustest_status_type = text
+ sieve_virustest_status_header = X-Virus-Scan: Found to be (.+)\.
+ sieve_virustest_text_value1 = clean
+ sieve_virustest_text_value5 = infected
+}
+
+
+
diff --git a/pigeonhole/doc/extensions/vacation.txt b/pigeonhole/doc/extensions/vacation.txt
new file mode 100644
index 0000000..3e405a9
--- /dev/null
+++ b/pigeonhole/doc/extensions/vacation.txt
@@ -0,0 +1,122 @@
+Vacation Extension
+
+Relevant specifications
+=======================
+
+ RFC5230 - doc/rfc/vacation.rfc5230.txt
+ RFC6131 - doc/rfc/vacation-seconds.rfc6131.txt
+
+Description
+===========
+
+The Sieve vacation extension [RFC5230] defines a mechanism to generate automatic
+replies to incoming email messages. It takes various precautions to make sure
+replies are only sent when appropriate. Script authors specify how often replies
+are sent to a particular contact. In the original vacation extension, this
+interval is specified in days with a minimum of one day. When more granularity
+is necessary and particularly when replies must be sent more frequently than one
+day, the vacation-seconds extension [RFC6131] can be used. This allows
+specifying the minimum reply interval in seconds with a minimum of zero (reply
+is then always sent), depending on administrator configuration.
+
+Configuration
+=============
+
+The vacation extension is available by default. In contrast, the
+vacation-seconds extension - which implies the vacation extension when used - is
+not available by default and needs to be enabled explicitly by adding it to the
+sieve_extensions setting. The configuration also needs to be adjusted
+accordingly to allow a non-reply period of less than a day.
+
+The vacation and vacation-seconds extensions have their own specific settings.
+The settings that specify a period are specified in s(econds), unless followed
+by a d(ay), h(our) or m(inute) specifier character.
+
+The following settings can be configured for the vacation extension (default
+values are indicated):
+
+sieve_vacation_min_period = 1d
+ This specifies the minimum period that can be specified for the :days and
+ :seconds tags of the vacation command. A minimum of 0 indicates that users are
+ allowed to make the Sieve interpreter send a vacation response message for
+ every incoming message that meets the other reply criteria (refer to RFC5230).
+ A value of zero is however not recommended.
+
+sieve_vacation_max_period = 0
+ This specifies the maximum period that can be specified for the :days tag of
+ the vacation command. The configured value must be larger than the
+ sieve_vacation_min_period setting. A value of 0 has a special meaning: it
+ indicates that there is no upper limit.
+
+sieve_vacation_default_period = 7d
+ This specifies the default period that is used when no :days or :seconds tag
+ is specified. The configured value must lie between the
+ sieve_vacation_min_period and sieve_vacation_max_period.
+
+sieve_vacation_max_subject_codepoints = 256
+ The maximum number of Unicode codepoints used in the Subject header generated
+ for the outgoing vacation message. When composite characters are involved,
+ the number of actual charactes in the Subject text can be less than this
+ number, otherwise it is equal. When the subject text exceeds the limit, it is
+ truncated and the removed part is replaced with an ellipsis character ('...').
+
+sieve_vacation_use_original_recipient = no
+ This specifies whether the original envelope recipient should be used in the
+ check for implicit delivery. The vacation command checks headers of the
+ incoming message, such as To: and Cc: for the address of the recipient, to
+ verify that the message is explicitly addressed at the recipient. If the
+ recipient address is not found, the vacation action will not trigger a
+ response to prevent sending a reply when it is not appropriate. Normally only
+ the final recipient address is used in this check. This setting allows
+ including the original recipient specified in the SMTP session if available.
+ This is useful to handle mail accounts with aliases. Use this option with
+ caution: if you are using aliases that point to more than a single account,
+ senders can get multiple vacation responses for a single message.
+
+sieve_vacation_dont_check_recipient = no
+ This disables the checks for implicit delivery entirely. This means that the
+ vacation command does not verify that the message is explicitly addressed at
+ the recipient. Use this option with caution. Specifying 'yes' will violate the
+ Sieve standards and can cause vacation replies to be sent for messages not
+ directly addressed at the recipient.
+
+sieve_vacation_send_from_recipient = no
+ This setting determines whether vacation messages are sent with the SMTP MAIL
+ FROM envelope address set to the recipient address of the Sieve script owner.
+ Normally this is set to <>, which is the default as recommended in the
+ specification. This is meant to prevent mail loops. However, there are
+ situations for which a valid sender address is required and this setting can
+ be used to accommodate for those.
+
+sieve_vacation_to_header_ignore_envelope = no
+ With this setting disabled (the default), the "To:" header in the composed
+ vacation reply is determined by finding the envelope sender address in the
+ first "Sender:", "Resent-From:", or "From:" headers (in that order). The
+ matching address is used in the "To:" header of the reply, which then includes
+ the "phrase" part of the address; i.e., usually the name of the person
+ associated with that address. If no match is found, the bare envelope sender
+ address is used instead. In contrast, with this setting enabled, the envelope
+ is completely ignored for this purpose and the first address found from the
+ mentioned headers is always used. This is useful when the envelope sender is
+ mangled somehow; e.g. by the Sender Rewriting Scheme (SRS).
+
+Invalid values for the settings above will make the Sieve interpreter log a
+warning and revert to the default values.
+
+Example
+=======
+
+plugin {
+ # Use vacation-seconds
+ sieve_extensions = +vacation-seconds
+
+ # One hour at minimum
+ sieve_vacation_min_period = 1h
+
+ # Ten days default
+ sieve_vacation_min_period = 10d
+
+ # Thirty days at maximum
+ sieve_vacation_max_period = 30d
+}
+
diff --git a/pigeonhole/doc/extensions/vnd.dovecot.environment.txt b/pigeonhole/doc/extensions/vnd.dovecot.environment.txt
new file mode 100644
index 0000000..59ed93a
--- /dev/null
+++ b/pigeonhole/doc/extensions/vnd.dovecot.environment.txt
@@ -0,0 +1,48 @@
+Vnd.dovecot.environment Extension
+
+Relevant specifications
+=======================
+
+ doc/rfc/spec-bosch-sieve-dovecot-environment.txt
+
+Description
+===========
+
+The "vnd.dovecot.environment" extension builds upon the existing standard
+"environment" extension, which allows Sieve scripts to access information about
+their execution context, such as the name and version of the Sieve interpreter
+implementation. The new "vnd.dovecot.environment" extension adds a few more
+environment items that can be accessed by Sieve scripts. Additionally, it makes
+the environment items available directly as variables [VARIABLES].
+
+Configuration
+=============
+
+The "vnd.dovecot.environment" extension is not available by default; it needs
+to be added to the sieve_extensions or (rather) the sieve_global extensions
+setting.
+
+Currently, the "vnd.dovecot.environment" extension has no specific settings.
+However, this extension adds environment items with a "vnd.dovecot.config."
+prefix that can be used to access part of the Dovecot configuration. An
+environment item named "vnd.dovecot.config.identifier" yields the value of a
+plugin setting called "sieve_env_identifier".
+
+Example
+=======
+
+With the following configuration:
+
+plugin {
+ sieve = ~/.dovecot.sieve
+
+ sieve_env_reject_reason = Please don't mail me.
+}
+
+The following script will reject the message with the configured reason:
+
+require "reject";
+require "variables";
+require "vnd.dovecot.environment";
+
+reject "${vnd.dovecot.config.reject_reason}";
diff --git a/pigeonhole/doc/extensions/vnd.dovecot.report.txt b/pigeonhole/doc/extensions/vnd.dovecot.report.txt
new file mode 100644
index 0000000..c512607
--- /dev/null
+++ b/pigeonhole/doc/extensions/vnd.dovecot.report.txt
@@ -0,0 +1,54 @@
+Vnd.dovecot.report Extension
+
+Relevant specifications
+=======================
+
+ doc/rfc/spec-bosch-sieve-report.txt
+
+Description
+===========
+
+The "vnd.dovecot.report" extension provides the means to send Messaging Abuse
+Reporting Format (MARF) reports (RFC 5965). This format is intended for
+communications regarding email abuse and related issues. The "report" command
+allows (partially) automating the exchange of these reports, which is
+particularly useful when the Sieve script is executed for an IMAP event
+(RFC 6785) that is triggered by direct user action.
+
+Configuration
+=============
+
+The "vnd.dovecot.report" extension is not available by default; it needs
+to be added to the sieve_extensions setting (or any of the alternatives).
+
+The "vnd.dovecot.report" extension has its own specific settings. The following
+settings can be configured for the vacation extension (default values are
+indicated):
+
+ sieve_report_from = postmaster
+ Specifies what address is used for the "From:" header field in reports.
+ The following values are supported for this setting:
+
+ "postmaster" - The postmaster_address configured for the LDA (default).
+ "sender" - The sender address is used.
+ "recipient" - The final recipient address is used.
+ "orig_recipient" - The original recipient is used.
+ "user_email" - The user's primary address is used. This is
+ configured with the "sieve_user_email" setting. If
+ that setting is unconfigured, "user_mail" is equal to
+ "recipient".
+ "<user@domain>" - Redirected messages are always sent from user@domain.
+ The angle brackets are mandatory. The null "<>" address
+ not supported and interpreted as "postmaster".
+
+Invalid values for the settings above will make the Sieve interpreter log a
+warning and revert to the default values.
+
+Example
+=======
+
+plugin {
+ sieve = file:~/sieve;active=~/.dovecot.sieve
+
+ sieve_report_from = <reporter@example.com>
+}
diff --git a/pigeonhole/doc/locations/Makefile.am b/pigeonhole/doc/locations/Makefile.am
new file mode 100644
index 0000000..d6be0df
--- /dev/null
+++ b/pigeonhole/doc/locations/Makefile.am
@@ -0,0 +1,13 @@
+docfiles = \
+ dict.txt \
+ file.txt \
+ ldap.txt
+
+if BUILD_DOCS
+locations_docdir = $(sieve_docdir)/locations
+locations_doc_DATA = $(docfiles)
+endif
+
+EXTRA_DIST = \
+ $(docfiles)
+
diff --git a/pigeonhole/doc/locations/Makefile.in b/pigeonhole/doc/locations/Makefile.in
new file mode 100644
index 0000000..894eda9
--- /dev/null
+++ b/pigeonhole/doc/locations/Makefile.in
@@ -0,0 +1,576 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = doc/locations
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(locations_docdir)"
+DATA = $(locations_doc_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+docfiles = \
+ dict.txt \
+ file.txt \
+ ldap.txt
+
+@BUILD_DOCS_TRUE@locations_docdir = $(sieve_docdir)/locations
+@BUILD_DOCS_TRUE@locations_doc_DATA = $(docfiles)
+EXTRA_DIST = \
+ $(docfiles)
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/locations/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign doc/locations/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-locations_docDATA: $(locations_doc_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(locations_doc_DATA)'; test -n "$(locations_docdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(locations_docdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(locations_docdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(locations_docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(locations_docdir)" || exit $$?; \
+ done
+
+uninstall-locations_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(locations_doc_DATA)'; test -n "$(locations_docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(locations_docdir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(locations_docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-locations_docDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-locations_docDATA
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am \
+ install-locations_docDATA install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
+ uninstall-am uninstall-locations_docDATA
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/doc/locations/dict.txt b/pigeonhole/doc/locations/dict.txt
new file mode 100644
index 0000000..59cf958
--- /dev/null
+++ b/pigeonhole/doc/locations/dict.txt
@@ -0,0 +1,145 @@
+DICT Sieve Script Location Type
+
+Description
+===========
+
+This location type is used to retrieve Sieve scripts from a Dovecot dict lookup.
+Such dictionaries use a file or an SQL database as backend. Refer to the Dovecot
+dict documentation for more information on dict lookups.
+
+To retrieve a Sieve script from the dict database, two lookups are performed.
+First, the name of the Sieve script is queried from the dict path
+`/priv/sieve/name/<name>'. If the Sieve script exists, this yields a data ID
+which in turn points to the actual script text. The script text is subsequently
+queried from the dict path '/priv/sieve/data/<dict-id>'.
+
+The second query is only necessary when no compiled binary is available or when
+the script has changed and needs to be recompiled. The data ID is used to detect
+changes in the dict's underlying database. Changing a Sieve script in the
+database must be done by first making a new script data item with a new data ID.
+Then, the mapping from name to data ID must be changed to point to the new
+script text, thereby changing the data ID returned from the name lookup, i.e.
+the first query mentioned above. Script binaries compiled from Sieve scripts
+contained in a dict database record the data ID. While the data ID contained in
+the binary is identical to the one returned from the dict lookup, the binary is
+assumed up-to-date. When the returned data ID is different, the new script text
+is retrieved using the second query and compiled into a new binary containing
+the updated data ID.
+
+Note that, by default, compiled binaries are not stored at all for Sieve scripts
+retrieved from a dict database. The bindir= option needs to be specified in the
+location specification. Refer to the INSTALL file for more general information
+about configuration of script locations.
+
+Configuration
+=============
+
+The script location syntax is specified as follows:
+
+location = dict:<dict-uri>[;<option>[=<value>][;...]]
+
+The following additional options are recognized:
+
+ user=<username>
+ Overrides the user name used for the dict lookup. Normally, the name of the
+ user running the Sieve interpreter is used.
+
+If the name of the Script is left unspecified and not otherwise provided by the
+Sieve interpreter, the name defaults to `default'.
+
+Examples
+========
+
+Example 1
+---------
+
+This example is mainly useful for performing a quick test of the dict location
+configuration without configuring an actual (SQL) database. For this example, a
+very simple file dict is assumed to be contained in the file
+/etc/dovecot/sieve.dict:
+
+priv/sieve/name/keep
+1
+priv/sieve/name/discard
+2
+priv/sieve/name/spam
+3
+priv/sieve/data/1
+keep;
+priv/sieve/data/2
+discard;
+priv/sieve/data/3
+require ["fileinto", "mailbox"]; fileinto :create "spam";
+
+To use this file dict for the main active script, you can change the
+configuration as follows (e.g. in /etc/dovecot/conf.d/90-sieve.conf):
+
+plugin {
+ sieve = dict:file:/etc/dovecot/sieve.dict;name=keep;bindir=~/.sieve-bin
+}
+
+The Sieve script named "keep" is retrieved from the file dict as the main
+script. Binaries are stored in the ~/.sieve-bin directory.
+
+Example 2
+---------
+
+This example uses a PostgreSQL database. Our database contains the following
+table:
+
+CREATE TABLE user_sieve_scripts (
+ id integer,
+ username varchar(40),
+ script_name varchar(256),
+ script_data varchar(10240),
+
+ PRIMARY KEY (id),
+ UNIQUE(username, script_name)
+);
+
+We create a file /etc/dovecot/dict-sieve-sql.conf with the following content:
+
+connect = host=localhost dbname=dovecot user=dovecot password=password
+map {
+ pattern = priv/sieve/name/$script_name
+ table = user_sieve_scripts
+ username_field = username
+ value_field = id
+ fields {
+ script_name = $script_name
+ }
+}
+map {
+ pattern = priv/sieve/data/$id
+ table = user_sieve_scripts
+ username_field = username
+ value_field = script_data
+ fields {
+ id = $id
+ }
+}
+
+These are the mappings used by the SQL dict. The first mapping is the name query
+that yields the id of the Sieve script. The second mapping is the query used to
+retrieve the Sieve script itself.
+
+Much like the dict configuration for mailbox quota, it is often not possible to
+directly use an SQL dict because the SQL drivers are not linked to binaries such
+as dovecot-lda and lmtp. You need to use the dict proxy service. Add the dict
+URI to the dict section (typically located in your main dovecot.conf):
+
+dict {
+ sieve = pgsql:/etc/dovecot/dict-sieve-sql.conf.ext
+}
+
+To use this SQL dict for the main active script, you can change the
+configuration as follows (e.g. in /etc/dovecot/conf.d/90-sieve.conf):
+
+plugin {
+ sieve = dict:proxy::sieve;name=active;bindir=~/.sieve-bin
+}
+
+This uses the proxy dict uri `proxy::sieve'. This refers to the `sieve =' entry
+in the dict {...} section above. With this configuration, a Sieve script called
+"main" is retrieved from the SQL dict. Binaries are stored in the ~/.sieve-bin
+directory.
diff --git a/pigeonhole/doc/locations/file.txt b/pigeonhole/doc/locations/file.txt
new file mode 100644
index 0000000..1c291d9
--- /dev/null
+++ b/pigeonhole/doc/locations/file.txt
@@ -0,0 +1,48 @@
+FILE Sieve Script Location Type
+
+Description
+===========
+
+This location type is used to retrieve Sieve scripts from the file system. The
+location can either point to a directory or to a regular file. If the location
+points to a directory, a script called "name" is retrieved by reading a file
+from that directory with the file name "name.sieve".
+
+When this location type is involved in a sieve_before/sieve_after script
+sequence and the location points to a directory, all files in that directory
+with a ".sieve" extension are part of the sequence. The sequence order of the
+scripts in that directory is determined by the file names, using a normal 8bit
+per-character comparison.
+
+Unless overridden using the `bindir=<path>' location option, compiled binaries
+for scripts retrieved from the `file' location type are by default stored in the
+same directory as where the script file was found if possible. Refer to the
+INSTALL file for more general information about configuration of script
+locations.
+
+Configuration
+=============
+
+The script location syntax is specified as follows:
+
+location = file:<path>[;<option>[=<value>][;...]]
+
+The following additional options are recognized:
+
+ active=<path>
+ When ManageSieve is used, one script in the storage can be active; i.e.,
+ evaluated at delivery. For the `file' location, the active script in the
+ storage directory is pointed to by a symbolic link. This option configures
+ where this symbolic link is located. If the `file' location path points to
+ a regular file, this setting has no effect (and ManageSieve cannot be used).
+
+Example
+=======
+
+plugin {
+ ...
+ sieve = file:~/sieve;active=~/.dovecot.sieve
+
+ sieve_default = file:/var/lib/dovecot/;name=default
+}
+
diff --git a/pigeonhole/doc/locations/ldap.txt b/pigeonhole/doc/locations/ldap.txt
new file mode 100644
index 0000000..e69b1ee
--- /dev/null
+++ b/pigeonhole/doc/locations/ldap.txt
@@ -0,0 +1,73 @@
+LDAP Sieve Script Location Type
+
+Description
+===========
+
+This location type is used to retrieve Sieve scripts from an LDAP database. To
+retrieve a Sieve script from the LDAP database, at most two lookups are
+performed. First, the LDAP entry containing the Sieve script is searched using
+the specified LDAP search filter. If the LDAP entry changed since it was last
+retrieved (or it was never retieved before), the attribute containing the actual
+Sieve script is retrieved in a second lookup. In the first lookup, a special
+attribute is read and checked for changes. Usually, this is the
+`modifyTimestamp' attribute, but an alternative can be configured.
+
+Note that, by default, compiled binaries are not stored at all for Sieve scripts
+retrieved from an LDAP database. The bindir= option needs to be specified in the
+location specification. Refer to the INSTALL file for more general information
+about configuration of script locations.
+
+Depending on how Pigeonhole was configured and compiled (refer to INSTALL file
+for more information), LDAP support may only be available from a plugin called
+`sieve_storage_ldap'.
+
+Configuration
+=============
+
+If support for the LDAP location type is compiled as a plugin, it needs to be
+added to the sieve_plugins setting before it can be used, e.g.:
+
+sieve_plugins = sieve_storage_ldap
+
+The script location syntax is specified as follows:
+
+location = ldap:<config-file>[;<option>[=<value>][;...]]
+
+The <config-file> is a filesystem path that points to a configuration file
+containing the actual configuration for this LDAP script location.
+
+The following additional location options are recognized:
+
+ user=<username>
+ Overrides the user name used for the lookup. Normally, the name of the
+ user running the Sieve interpreter is used.
+
+If the name of the Script is left unspecified and not otherwise provided by the
+Sieve interpreter, the name defaults to `default'.
+
+The configuration file is based on the auth userdb/passdb LDAP configuration
+(refer to Dovecot wiki at http://wiki2.dovecot.org/AuthDatabase/LDAP). The
+following options are specific to the Sieve ldap location type:
+
+ sieve_ldap_filter = (&(objectClass=posixAccount)(uid=%u))
+ The LDAP search filter that is used to find the entry containing the Sieve
+ script.
+
+ sieve_ldap_script_attr = mailSieveRuleSource
+ The name of the attribute containing the Sieve script itself.
+
+ sieve_ldap_mod_attr = modifyTimestamp
+ The name of the attribute used to detect modifications to the LDAP entry.
+
+Examples
+========
+
+plugin {
+ sieve = ldap:/etc/dovecot/sieve-ldap.conf;bindir=~/.sieve-bin/
+}
+
+An example LDAP location configuration is available in this package as
+doc/example-config/sieve-ldap.conf.
+
+
+
diff --git a/pigeonhole/doc/man/Makefile.am b/pigeonhole/doc/man/Makefile.am
new file mode 100644
index 0000000..2d2af01
--- /dev/null
+++ b/pigeonhole/doc/man/Makefile.am
@@ -0,0 +1,46 @@
+pkgsysconfdir = $(sysconfdir)/dovecot
+rundir = ${prefix}/var/run/dovecot
+
+SUFFIXES = .1.in .1 .7.in .7
+
+dist_man1_MANS = \
+ sieved.1
+
+nodist_man1_MANS = \
+ doveadm-sieve.1 \
+ sievec.1 \
+ sieve-dump.1 \
+ sieve-test.1 \
+ sieve-filter.1
+
+nodist_man7_MANS = \
+ pigeonhole.7
+
+man_includefiles = \
+ $(srcdir)/global-options-formatter.inc \
+ $(srcdir)/global-options.inc \
+ $(srcdir)/option-A.inc \
+ $(srcdir)/option-S-socket.inc \
+ $(srcdir)/option-u-user.inc \
+ $(srcdir)/reporting-bugs.inc
+
+EXTRA_DIST = \
+ doveadm-sieve.1.in \
+ sievec.1.in \
+ sieve-dump.1.in \
+ sieve-test.1.in \
+ sieve-filter.1.in \
+ pigeonhole.7.in \
+ sed.sh \
+ $(man_includefiles)
+
+CLEANFILES = $(nodist_man1_MANS) $(nodist_man7_MANS)
+
+.1.in.1: $(man_includefiles) Makefile
+ $(SHELL) $(srcdir)/sed.sh $(srcdir) $(rundir) $(pkgsysconfdir) \
+ $(pkglibexecdir) < $< > $@
+.7.in.7: $(man_includefiles) Makefile
+ $(SHELL) $(srcdir)/sed.sh $(srcdir) $(rundir) $(pkgsysconfdir) \
+ $(pkglibexecdir) < $< > $@
+
+
diff --git a/pigeonhole/doc/man/Makefile.in b/pigeonhole/doc/man/Makefile.in
new file mode 100644
index 0000000..b2bc957
--- /dev/null
+++ b/pigeonhole/doc/man/Makefile.in
@@ -0,0 +1,675 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = doc/man
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+man1dir = $(mandir)/man1
+am__installdirs = "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man7dir)"
+man7dir = $(mandir)/man7
+NROFF = nroff
+MANS = $(dist_man1_MANS) $(nodist_man1_MANS) $(nodist_man7_MANS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(dist_man1_MANS) $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkgsysconfdir = $(sysconfdir)/dovecot
+rundir = ${prefix}/var/run/dovecot
+SUFFIXES = .1.in .1 .7.in .7
+dist_man1_MANS = \
+ sieved.1
+
+nodist_man1_MANS = \
+ doveadm-sieve.1 \
+ sievec.1 \
+ sieve-dump.1 \
+ sieve-test.1 \
+ sieve-filter.1
+
+nodist_man7_MANS = \
+ pigeonhole.7
+
+man_includefiles = \
+ $(srcdir)/global-options-formatter.inc \
+ $(srcdir)/global-options.inc \
+ $(srcdir)/option-A.inc \
+ $(srcdir)/option-S-socket.inc \
+ $(srcdir)/option-u-user.inc \
+ $(srcdir)/reporting-bugs.inc
+
+EXTRA_DIST = \
+ doveadm-sieve.1.in \
+ sievec.1.in \
+ sieve-dump.1.in \
+ sieve-test.1.in \
+ sieve-filter.1.in \
+ pigeonhole.7.in \
+ sed.sh \
+ $(man_includefiles)
+
+CLEANFILES = $(nodist_man1_MANS) $(nodist_man7_MANS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .1.in .1 .7.in .7
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/man/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign doc/man/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man1: $(dist_man1_MANS) $(nodist_man1_MANS)
+ @$(NORMAL_INSTALL)
+ @list1='$(dist_man1_MANS) $(nodist_man1_MANS)'; \
+ list2=''; \
+ test -n "$(man1dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.1[a-z]*$$/p'; \
+ fi; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man1:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_man1_MANS) $(nodist_man1_MANS)'; test -n "$(man1dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir)
+install-man7: $(nodist_man7_MANS)
+ @$(NORMAL_INSTALL)
+ @list1='$(nodist_man7_MANS)'; \
+ list2=''; \
+ test -n "$(man7dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man7dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man7dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.7[a-z]*$$/p'; \
+ fi; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^7][0-9a-z]*$$,7,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man7dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man7dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man7dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man7dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man7:
+ @$(NORMAL_UNINSTALL)
+ @list='$(nodist_man7_MANS)'; test -n "$(man7dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^7][0-9a-z]*$$,7,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man7dir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man7dir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man1 install-man7
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-man
+
+uninstall-man: uninstall-man1 uninstall-man7
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-man1 install-man7 install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
+ uninstall-am uninstall-man uninstall-man1 uninstall-man7
+
+.PRECIOUS: Makefile
+
+
+.1.in.1: $(man_includefiles) Makefile
+ $(SHELL) $(srcdir)/sed.sh $(srcdir) $(rundir) $(pkgsysconfdir) \
+ $(pkglibexecdir) < $< > $@
+.7.in.7: $(man_includefiles) Makefile
+ $(SHELL) $(srcdir)/sed.sh $(srcdir) $(rundir) $(pkgsysconfdir) \
+ $(pkglibexecdir) < $< > $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/doc/man/doveadm-sieve.1.in b/pigeonhole/doc/man/doveadm-sieve.1.in
new file mode 100644
index 0000000..aed9337
--- /dev/null
+++ b/pigeonhole/doc/man/doveadm-sieve.1.in
@@ -0,0 +1,125 @@
+.\" Copyright (c) 2010-2018 Pigeonhole authors, see the included COPYING file
+.TH DOVEADM\-SIEVE 1 "2016-02-29" "Pigeonhole for Dovecot v2.4" "Pigeonhole"
+.SH NAME
+doveadm\-sieve \- Commands related to handling Sieve scripts
+.\"------------------------------------------------------------------------
+.SH SYNOPSIS
+.BR doveadm " [" \-Dv "] [" \-f
+.IR formatter "] " sieve_cmd " [" options "] [" arguments ]
+.\"------------------------------------------------------------------------
+.SH DESCRIPTION
+.PP
+The
+.B doveadm sieve
+commands are part of the Pigeonhole Project (\fBpigeonhole\fR(7)), which adds
+Sieve (RFC 5228) and ManageSieve (RFC 5804) support to the Dovecot secure IMAP
+and POP3 server (\fBdovecot\fR(1)). The
+.B doveadm sieve
+commands can be used to manage Sieve filtering.
+.\"------------------------------------------------------------------------
+@INCLUDE:global-options-formatter@
+.\" --- command specific options --- "/.
+.PP
+Command specific
+.IR options :
+.\"-------------------------------------
+@INCLUDE:option-A@
+.\"-------------------------------------
+@INCLUDE:option-S-socket@
+.\"-------------------------------------
+@INCLUDE:option-u-user@
+.\"------------------------------------------------------------------------
+.SH ARGUMENTS
+.TP
+.I scriptname
+Is the name of a
+.IR Sieve\ script ,
+as visible to ManageSieve clients.
+.IP
+NOTE: For Sieve scripts that are stored on disk, this is the filename without the
+".sieve" extension.
+.\"------------------------------------------------------------------------
+.SH COMMANDS
+.SS sieve put
+.B doveadm sieve put
+[\fB\-A\fP|\fB\-u\fP \fIuser\fP]
+[\fB\-S\fP \fIsocket_path\fP]
+.RB [ \-a ]
+.IR scriptname
+.PP
+This command puts one new Sieve script in the script storage. The script
+is read from standard input. If the script compiles successfully, it is stored
+under the provided
+.IR scriptname\ .
+If the
+.B \-a
+option is present, the Sieve script is subsequently marked as the active script
+for execution at delivery.
+.\"------------------------------------------------------------------------
+.SS sieve get
+.B doveadm sieve get
+[\fB\-A\fP|\fB\-u\fP \fIuser\fP]
+[\fB\-S\fP \fIsocket_path\fP]
+.I scriptname
+.PP
+This command retrieves the Sieve script named
+.IR scriptname .
+.\"------------------------------------------------------------------------
+.SS sieve delete
+.B doveadm sieve delete
+[\fB\-A\fP|\fB\-u\fP \fIuser\fP]
+[\fB\-S\fP \fIsocket_path\fP]
+.RB [ \-a ]
+.IR scriptname\ ...
+.PP
+This command deletes one or more Sieve scripts. The deleted script may not be the
+active script, unless the
+.B \-a
+option is present.
+.\"------------------------------------------------------------------------
+.SS sieve list
+.B doveadm sieve list
+[\fB\-A\fP|\fB\-u\fP \fIuser\fP]
+[\fB\-S\fP \fIsocket_path\fP]
+.I scriptname
+.PP
+Use this command to get an overview of existing Sieve scripts.
+.\"------------------------------------------------------------------------
+.SS sieve rename
+.B doveadm sieve rename
+[\fB\-A\fP|\fB\-u\fP \fIuser\fP]
+[\fB\-S\fP \fIsocket_path\fP]
+.I old_name
+.I new_name
+.PP
+The
+.B sieve rename
+command is used to rename the Sieve script
+.I old_name
+to
+.IR new_name .
+.\"------------------------------------------------------------------------
+.SS sieve activate
+.B doveadm sieve activate
+[\fB\-A\fP|\fB\-u\fP \fIuser\fP]
+[\fB\-S\fP \fIsocket_path\fP]
+.IR scriptname
+.PP
+This command marks the Sieve script named
+.I scriptname
+as the active script for execution at delivery.
+.\"------------------------------------------------------------------------
+.SS sieve deactivate
+.B doveadm sieve deactivate
+[\fB\-A\fP|\fB\-u\fP \fIuser\fP]
+[\fB\-S\fP \fIsocket_path\fP]
+.I scriptname
+.PP
+This command deactivates Sieve processing.
+.\"------------------------------------------------------------------------
+@INCLUDE:reporting-bugs@
+.\"------------------------------------------------------------------------
+.SH SEE ALSO
+.BR doveadm (1)
+.BR dovecot\-lda (1),
+.BR pigeonhole (7)
diff --git a/pigeonhole/doc/man/global-options-formatter.inc b/pigeonhole/doc/man/global-options-formatter.inc
new file mode 100644
index 0000000..cb792e1
--- /dev/null
+++ b/pigeonhole/doc/man/global-options-formatter.inc
@@ -0,0 +1,46 @@
+.SH OPTIONS
+Global
+.BR doveadm (1)
+.IR options :
+.TP
+.B \-D
+Enables verbosity and debug messages.
+.TP
+.BI \-f\ formatter
+Specifies the
+.I formatter
+for formatting the output.
+Supported formatters are:
+.RS
+.TP
+.B flow
+prints each line with
+.IB key = value
+pairs.
+.TP
+.B pager
+prints each
+.IR key :\ value
+pair on its own line and separates records with form feed character
+.RB ( ^L ).
+.TP
+.B tab
+prints a table header followed by tab separated value lines.
+.TP
+.B table
+prints a table header followed by adjusted value lines.
+.RE
+.TP
+.BI \-o\ setting = value
+Overrides the configuration
+.I setting
+from
+.I @pkgsysconfdir@/dovecot.conf
+and from the userdb with the given
+.IR value .
+In order to override multiple settings, the
+.B \-o
+option may be specified multiple times.
+.TP
+.B \-v
+Enables verbosity, including progress counter.
diff --git a/pigeonhole/doc/man/global-options.inc b/pigeonhole/doc/man/global-options.inc
new file mode 100644
index 0000000..bf99294
--- /dev/null
+++ b/pigeonhole/doc/man/global-options.inc
@@ -0,0 +1,21 @@
+.SH OPTIONS
+Global
+.BR doveadm (1)
+.IR options :
+.TP
+.B \-D
+Enables verbosity and debug messages.
+.TP
+.BI \-o\ setting = value
+Overrides the configuration
+.I setting
+from
+.I @pkgsysconfdir@/dovecot.conf
+and from the userdb with the given
+.IR value .
+In order to override multiple settings, the
+.B \-o
+option may be specified multiple times.
+.TP
+.B \-v
+Enables verbosity, including progress counter.
diff --git a/pigeonhole/doc/man/option-A.inc b/pigeonhole/doc/man/option-A.inc
new file mode 100644
index 0000000..256e939
--- /dev/null
+++ b/pigeonhole/doc/man/option-A.inc
@@ -0,0 +1,27 @@
+.TP
+.B \-A
+If the
+.B \-A
+option is present, the
+.I command
+will be performed for all users.
+Using this option in combination with system users from
+.B userdb { driver = passwd }
+is not recommended, because it contains also users with a lower UID than
+the one configured with the
+.I first_valid_uid
+setting.
+.sp
+When the SQL userdb module is used make sure that the
+.I iterate_query
+setting in
+.I @pkgsysconfdir@/dovecot\-sql.conf.ext
+matches your database layout.
+When using the LDAP userdb module, make sure that the
+.IR iterate_attrs " and " iterate_filter
+settings in
+.I @pkgsysconfdir@/dovecot-ldap.conf.ext
+match your LDAP schema.
+Otherwise
+.BR doveadm (1)
+will be unable to iterate over all users.
diff --git a/pigeonhole/doc/man/option-S-socket.inc b/pigeonhole/doc/man/option-S-socket.inc
new file mode 100644
index 0000000..2e0e374
--- /dev/null
+++ b/pigeonhole/doc/man/option-S-socket.inc
@@ -0,0 +1,10 @@
+.TP
+.BI \-S\ socket_path
+The option\(aqs argument is either an absolute path to a local UNIX domain
+socket, or a hostname and port
+.RI ( hostname : port ),
+in order to connect a remote host via a TCP socket.
+.sp
+This allows an administrator to execute
+.BR doveadm (1)
+mail commands through the given socket.
diff --git a/pigeonhole/doc/man/option-u-user.inc b/pigeonhole/doc/man/option-u-user.inc
new file mode 100644
index 0000000..e861145
--- /dev/null
+++ b/pigeonhole/doc/man/option-u-user.inc
@@ -0,0 +1,20 @@
+.TP
+.BI \-u\ user/mask
+Run the
+.I command
+only for the given
+.IR user .
+It\(aqs also possible to use
+.RB \(aq * \(aq
+and
+.RB \(aq ? \(aq
+wildcards (e.g. \-u *@example.org).
+.br
+When neither the
+.B \-A
+option nor
+.BI \-u\ user
+was specified, the
+.I command
+will be executed with the environment of the
+currently logged in user.
diff --git a/pigeonhole/doc/man/pigeonhole.7.in b/pigeonhole/doc/man/pigeonhole.7.in
new file mode 100644
index 0000000..18b081d
--- /dev/null
+++ b/pigeonhole/doc/man/pigeonhole.7.in
@@ -0,0 +1,99 @@
+.\" Copyright (c) 2010-2018 Pigeonhole authors, see the included COPYING file
+.TH "PIGEONHOLE" 7 "2015-02-21" "Pigeonhole for Dovecot v2.4" "Pigeonhole"
+.\"------------------------------------------------------------------------
+.SH NAME
+pigeonhole \- Overview of the Pigeonhole project\(aqs Sieve support for the
+Dovecot secure IMAP and POP3 server
+.\"------------------------------------------------------------------------
+.SH DESCRIPTION
+.PP
+The Pigeonhole project <http://pigeonhole.dovecot.org> adds support for the
+Sieve language (RFC 5228) and the ManageSieve protocol (RFC 5804) to the
+Dovecot Secure IMAP and POP3 Server (\fBdovecot\fR(1)). In the literal sense,
+a pigeonhole is a a hole or recess inside a dovecot for pigeons to nest in.
+It is, however, also the name for one of a series of small, open compartments
+in a cabinet used for filing or sorting mail. As a verb, it describes the act
+of putting an item into one of those pigeonholes. The name \(dqPigeonhole\(dq
+therefore well describes an important part of the functionality that this
+project adds to Dovecot: sorting and filing e\-mail messages.
+.PP
+The Sieve language is used to specify how e\-mail needs to be processed. By
+writing Sieve scripts, users can customize how messages are delivered, e.g.
+whether they are forwarded or stored in special folders. Unwanted messages can
+be discarded or rejected, and, when the user is not available, the Sieve
+interpreter can send an automated reply. Above all, the Sieve language is meant
+to be simple, extensible and system independent. And, unlike most other mail
+filtering script languages, it does not allow users to execute arbitrary
+programs. This is particularly useful to prevent virtual users from having full
+access to the mail store. The intention of the language is to make it impossible
+for users to do anything more complex (and dangerous) than write simple mail
+filters.
+.PP
+Using the ManageSieve protocol, users can upload their Sieve scripts remotely,
+without needing direct filesystem access through FTP or SCP. Additionally, a
+ManageSieve server always makes sure that uploaded scripts are valid, preventing
+compile failures at mail delivery.
+.PP
+The Pigeonhole project provides the following items:
+.IP \(bu 4
+The LDA Sieve plugin for Dovecot\(aqs Local Delivery Agent (LDA)
+(\fBdovecot\-lda\fR(1)) that facilitates the actual Sieve filtering upon
+delivery.
+.IP \(bu
+The ManageSieve service that implements the ManageSieve protocol through which
+users can remotely manage Sieve scripts on the server.
+.IP \(bu
+A plugin for Dovecot\(aqs
+.BR doveadm (1)
+command line tool that adds new the new
+.BR doveadm-sieve (1)
+commands for management of Sieve filtering.
+.PP
+The functionality and configuration of the LDA Sieve plugin and the ManageSieve
+service is described in detail in the README and INSTALL files contained in the
+Pigeonhole package and in the Dovecot Wiki
+<http://wiki2.dovecot.org/Pigeonhole>.
+.PP
+The following command line tools are available outside of
+.BR doveadm :
+.TP
+.BR sievec (1)
+Compiles Sieve scripts into a binary representation for later execution.
+.TP
+.BR sieve\-test (1)
+The universal Sieve test tool for testing the effect of a Sieve script on a
+particular message.
+.TP
+.BR sieve\-filter (1)
+Filters all messages in a particular source mailbox through a Sieve script.
+.TP
+.BR sieve\-dump (1)
+Dumps the content of a Sieve binary file for (development) debugging purposes.
+.\"------------------------------------------------------------------------
+@INCLUDE:reporting-bugs@
+.\"------------------------------------------------------------------------
+.SH AUTHOR
+Pigeonhole <http://pigeonhole.dovecot.org> and its manual pages were written by
+the Pigeonhole authors <http://pigeonhole.dovecot.org/doc/AUTHORS>, mainly
+Stephan Bosch <stephan at rename\-it.nl>, and are licensed under the terms of the
+LGPLv2.1 license, which is the same license as Dovecot, see
+<http://dovecot.org/doc/COPYING> for details.
+.\"------------------------------------------------------------------------
+.SH "SEE ALSO"
+.BR dovecot (1),
+.BR dovecot\-lda (1),
+.BR doveadm (1),
+.BR doveadm-sieve (1),
+.BR sieve\-dump (1),
+.BR sieve\-test (1),
+.BR sieve\-filter (1),
+.BR sievec (1)
+.\"-------------------------------------
+.PP
+Additional resources:
+.IP "Dovecot website"
+http://www.dovecot.org
+.IP "Dovecot v2.x Wiki"
+http://wiki2.dovecot.org/Pigeonhole
+.IP "Pigeonhole website"
+http://pigeonhole.dovecot.org
diff --git a/pigeonhole/doc/man/reporting-bugs.inc b/pigeonhole/doc/man/reporting-bugs.inc
new file mode 100644
index 0000000..1823ca2
--- /dev/null
+++ b/pigeonhole/doc/man/reporting-bugs.inc
@@ -0,0 +1,6 @@
+.SH REPORTING BUGS
+Report bugs, including
+.I doveconf \-n
+output, to the Dovecot Mailing List <dovecot@dovecot.org>.
+Information about reporting bugs is available at:
+http://dovecot.org/bugreport.html
diff --git a/pigeonhole/doc/man/sed.sh b/pigeonhole/doc/man/sed.sh
new file mode 100644
index 0000000..6da3963
--- /dev/null
+++ b/pigeonhole/doc/man/sed.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+SRCDIR="${1:-`pwd`}"
+RUNDIR="${2:-/usr/local/var/run/dovecot}"
+PKGSYSCONFDIR="${3:-/usr/local/etc/dovecot}"
+PKGLIBEXECDIR="${4:-/usr/local/libexec/dovecot}"
+
+sed -e "/^@INCLUDE:global-options@$/{
+ r ${SRCDIR}/global-options.inc
+ d
+ }" \
+ -e "/^@INCLUDE:global-options-formatter@$/{
+ r ${SRCDIR}/global-options-formatter.inc
+ d
+ }" \
+ -e "/^@INCLUDE:option-A@$/{
+ r ${SRCDIR}/option-A.inc
+ d
+ }" \
+ -e "/^@INCLUDE:option-S-socket@$/{
+ r ${SRCDIR}/option-S-socket.inc
+ d
+ }" \
+ -e "/^@INCLUDE:option-u-user@$/{
+ r ${SRCDIR}/option-u-user.inc
+ d
+ }" \
+ -e "/^@INCLUDE:reporting-bugs@$/{
+ r ${SRCDIR}/reporting-bugs.inc
+ d
+ }" | sed -e "s|@pkgsysconfdir@|${PKGSYSCONFDIR}|" \
+ -e "s|@rundir@|${RUNDIR}|" \
+ -e "s|@pkglibexecdir@|${PKGLIBEXECDIR}|"
+
diff --git a/pigeonhole/doc/man/sieve-dump.1.in b/pigeonhole/doc/man/sieve-dump.1.in
new file mode 100644
index 0000000..7a79c68
--- /dev/null
+++ b/pigeonhole/doc/man/sieve-dump.1.in
@@ -0,0 +1,122 @@
+.\" Copyright (c) 2010-2018 Pigeonhole authors, see the included COPYING file
+.TH "SIEVE\-DUMP" 1 "2016-04-05" "Pigeonhole for Dovecot v2.4" "Pigeonhole"
+.\"------------------------------------------------------------------------
+.SH NAME
+sieve\-dump \- Pigeonhole\(aqs Sieve script binary dump tool
+.\"------------------------------------------------------------------------
+.SH SYNOPSIS
+.B sieve\-dump
+.RI [ options ]
+.I sieve\-binary
+.RI [ out\-file ]
+.\"------------------------------------------------------------------------
+.SH DESCRIPTION
+.PP
+The \fBsieve\-dump\fP command is part of the Pigeonhole Project
+(\fBpigeonhole\fR(7)), which adds Sieve (RFC 5228) support to the Dovecot
+secure IMAP and POP3 server (\fBdovecot\fR(1)).
+.PP
+Using the \fBsieve\-dump\fP command, Sieve binaries, which are produced for
+instance by \fBsievec\fP(1), can be transformed into a human\-readable textual
+representation. This can provide valuable insight in how the Sieve script is
+executed. This is also particularly useful to view corrupt binaries that can
+result from bugs in the Sieve implementation. This tool is intended mainly for
+development purposes, so normally system administrators and users will not need
+to use this tool.
+.PP
+The format of the output is not explained here in detail, but it should be
+relatively easy to understand. The Sieve binaries comprise a set of data blocks,
+each of which can contain arbitrary data. For the base language implementation
+two blocks are used: the first containing a specification of all required
+language extensions and the second containing the main Sieve program. Compiled
+Sieve programs are represented as flat byte code and therefore the dump of the
+main program is a disassembly listing of the interpreter operations. Extensions
+can define new operations and use additional blocks. Therefore, the output of
+\fBsieve\-dump\fP depends greatly on the language extensions used when compiling
+the binary.
+.\"------------------------------------------------------------------------
+.SH OPTIONS
+.TP
+.BI \-c\ config\-file
+Alternative Dovecot configuration file path.
+.TP
+.B \-D
+Enable Sieve debugging.
+.TP
+.B \-h
+Produce per\-block hexdump output of the whole binary instead of the normal
+human\-readable output.
+.TP
+.BI \-o\ setting = value
+Overrides the configuration
+.I setting
+from
+.I @pkgsysconfdir@/dovecot.conf
+and from the userdb with the given
+.IR value .
+In order to override multiple settings, the
+.B \-o
+option may be specified multiple times.
+.TP
+.BI \-u\ user
+Run the Sieve script for the given \fIuser\fP. When omitted, the
+.I command
+will be executed with the environment of the currently logged in user.
+.TP
+.BI \-x\ extensions
+Set the available extensions. The parameter is a space\-separated list of the
+active extensions. By prepending the extension identifiers with \fB+\fP or
+\fB\-\fP, extensions can be included or excluded relative to the configured set
+of active extensions. If no extensions have a \fB+\fP or \fB\-\fP prefix, only
+those extensions that are explicitly listed will be enabled. Unknown extensions
+are ignored and a warning is produced.
+
+For example \fB\-x\fP \(dq+imapflags \-enotify\(dq will enable the deprecated
+imapflags extension and disable the enotify extension. The rest of the active
+extensions depends on the \fIsieve_extensions\fP and
+\fIsieve_global_extensions\fP settings. By default, i.e.
+when \fIsieve_extensions\fP and \fIsieve_global_extensions\fP remain
+unconfigured, all supported extensions are available, except for deprecated
+extensions or those that are still under development.
+
+.\"------------------------------------------------------------------------
+.SH ARGUMENTS
+.TP
+.I sieve\-binary
+Specifies the Sieve binary file that needs to be dumped.
+.TP
+.I out\-file
+Specifies where the output must be written. This argument is optional. If
+omitted, the output is written to \fBstdout\fR.
+.\"------------------------------------------------------------------------
+.SH "EXIT STATUS"
+.B sieve\-dump
+will exit with one of the following values:
+.TP 4
+.B 0
+Dump was successful. (EX_OK, EXIT_SUCCESS)
+.TP
+.B 1
+Operation failed. This is returned for almost all failures.
+(EXIT_FAILURE)
+.TP
+.B 64
+Invalid parameter given. (EX_USAGE)
+.\"------------------------------------------------------------------------
+.SH FILES
+.TP
+.I @pkgsysconfdir@/dovecot.conf
+Dovecot\(aqs main configuration file.
+.TP
+.I @pkgsysconfdir@/conf.d/90\-sieve.conf
+Sieve interpreter settings (included from Dovecot\(aqs main configuration file)
+.\"------------------------------------------------------------------------
+@INCLUDE:reporting-bugs@
+.\"------------------------------------------------------------------------
+.SH "SEE ALSO"
+.BR dovecot (1),
+.BR dovecot\-lda (1),
+.BR sieve\-filter (1),
+.BR sieve\-test (1),
+.BR sievec (1),
+.BR pigeonhole (7)
diff --git a/pigeonhole/doc/man/sieve-filter.1.in b/pigeonhole/doc/man/sieve-filter.1.in
new file mode 100644
index 0000000..1ce804b
--- /dev/null
+++ b/pigeonhole/doc/man/sieve-filter.1.in
@@ -0,0 +1,253 @@
+.\" Copyright (c) 2010-2018 Pigeonhole authors, see the included COPYING file
+.TH "SIEVE\-FILTER" 1 "2016-04-05" "Pigeonhole for Dovecot v2.4" "Pigeonhole"
+.SH NAME
+sieve\-filter \- Pigeonhole\(aqs Sieve mailbox filter tool
+
+.PP
+\fBWARNING: \fRThis tool is still experimental. Read this manual carefully, and
+backup any important mail before using this tool. Also note that some of the
+features documented here are not actually implemented yet; this is clearly
+indicated where applicable.
+.\"------------------------------------------------------------------------
+.SH SYNOPSIS
+.B sieve\-filter
+.RI [ options ]
+.I script\-file
+.I source\-mailbox
+.RI [ discard\-action ]
+.SH DESCRIPTION
+.PP
+The \fBsieve\-filter\fP command is part of the Pigeonhole Project
+(\fBpigeonhole\fR(7)), which adds Sieve (RFC 5228) support to the Dovecot
+secure IMAP and POP3 server (\fBdovecot\fR(1)).
+.PP
+The Sieve language was originally meant for filtering messages upon delivery.
+However, there are occasions when it is desirable to filter messages that are
+already stored in a mailbox, for instance when a bug in a Sieve script caused
+many messages to be delivered incorrectly. Using the sieve\-filter tool it is
+possible to apply a Sieve script on all messages in a particular
+\fIsource\-mailbox\fP, making it possible to delete messages, to store them in a
+different mailbox, to change their content, and to change the assigned IMAP
+flags and keywords. Attempts to send messages to the outside world are ignored
+by default for obvious reasons, but, using the proper command line options, it
+is possible to capture and handle outgoing mail as well.
+.PP
+If no options are specified, the sieve\-filter command runs in a simulation mode
+in which it only prints what would be performed, without actually doing
+anything. Use the \fB\-e\fP option to activate true script execution. Also, the
+\fIsource\-mailbox\fP is opened read\-only by default, meaning that it normally
+always remains unchanged. Use the \fB\-W\fP option to allow changes in the
+\fIsource\-mailbox\fP.
+.PP
+Even with the \fB\-W\fP option enabled, messages in the \fIsource\-mailbox\fP
+are only potentially modified or moved to a different folder. Messages are never
+lost unless a \fIdiscard\-action\fP argument other than \fBkeep\fP (the default)
+is specified. If the Sieve filter decides to store the message in the
+\fIsource\-mailbox\fP, where it obviously already exists, it is never duplicated
+there. In that case, the IMAP flags of the original message can be modified by
+the Sieve interpreter using the \fIimap4flags\fP extension, provided that
+\fB\-W\fP is specified. If the message itself is modified by the Sieve
+interpreter (e.g. using the \fIeditheader\fP extension), a new message is stored
+and the old one is expunged. However, if \fB-W\fP is omitted, the original
+message is left untouched and the modifications are discarded.
+
+.SS CAUTION
+Although this is a very useful tool, it can also be very destructive when used
+improperly. A small bug in your Sieve script in combination with the wrong
+command line options could cause it to discard the wrong e\-mails. And, even if
+the \fIsource\-mailbox\fP is opened in read\-only mode to prevent such mishaps,
+it can still litter other mailboxes with spurious copies of your e\-mails if
+your Sieve script decides to do so. Therefore, users are advised to read this
+manual carefully and to use the simulation mode first to check what the script
+will do. And, of course:
+.PP
+\fBMAKING A BACKUP IS IMPERATIVE FOR ANY IMPORTANT MAIL!\fP
+
+.\"------------------------------------------------------------------------
+.SH OPTIONS
+.TP
+.BI \-c\ config\-file
+Alternative Dovecot configuration file path.
+.TP
+.B \-C
+Force compilation. By default, the compiled binary is stored on disk. When this
+binary is found during the next execution of \fBsieve\-filter\fP and its
+modification time is more recent than the script file, it is used and the script
+is not compiled again. This option forces the script to be compiled, thus
+ignoring any present binary. Refer to \fBsievec\fP(1) for more information about
+Sieve compilation.
+.TP
+.B \-D
+Enable Sieve debugging.
+.TP
+.B \-e
+Turns on execution mode. By default, the sieve\-filter command runs in
+simulation mode in which it changes nothing, meaning that no mailbox is altered
+in any way and no actions are performed. It only prints what would be done.
+Using this option, the sieve\-filter command becomes active and performs the
+requested actions.
+.TP
+.BI \-m\ default\-mailbox
+The mailbox where the (implicit) \fBkeep\fP Sieve action stores messages. This
+is equal to the \fIsource\-mailbox\fP by default. Specifying a different folder
+will have the effect of moving (or copying if \fB\-W\fP is omitted) all kept
+messages to the indicated folder, instead of just leaving them in the
+\fIsource\-mailbox\fP. Refer to the explanation of the \fIsource\-mailbox\fP
+argument for more information on mailbox naming.
+.TP
+.BI \-o\ setting = value
+Overrides the configuration
+.I setting
+from
+.I @pkgsysconfdir@/dovecot.conf
+and from the userdb with the given
+.IR value .
+In order to override multiple settings, the
+.B \-o
+option may be specified multiple times.
+.TP
+.BI \-q\ output\-mailbox\ \fB[not\ implemented\ yet]\fP
+Store outgoing e\-mail into the indicated \fIoutput\-mailbox\fP. By default,
+the sieve\-filter command ignores Sieve actions such as redirect, reject,
+vacation and notify, but using this option outgoing messages can be appended to
+the indicated mailbox. This option has no effect in simulation mode. Flags of
+redirected messages are not preserved.
+.TP
+.BI \-Q\ mail\-command\ \fB[not\ implemented\ yet]\fP
+Send outgoing e\-mail (e.g. as produced by redirect, reject and vacation)
+through the specified program. By default, the sieve\-filter command ignores
+Sieve actions such as redirect, reject, vacation and notify, but using this
+option outgoing messages can be fed to the \fBstdin\fP of an external shell
+command. This option has no effect in simulation mode. Unless you really know
+what you are doing, \fBDO NOT USE THIS TO FEED MAIL TO SENDMAIL!\fP.
+.TP
+.BI \-s\ script\-file\ \fB[not\ implemented\ yet]\fP
+Specify additional scripts to be executed before the main script. Multiple
+\fB\-s\fP arguments are allowed and the specified scripts are executed
+sequentially in the order specified at the command line.
+.TP
+.BI \-u\ user
+Run the Sieve script for the given \fIuser\fP. When omitted, the
+.I command
+will be executed with the environment of the currently logged in user.
+.TP
+.B \-v
+Produce verbose output during filtering.
+.TP
+.B \-W
+Enables write access to the \fIsource\-mailbox\fP. This allows (re)moving the
+messages from the \fIsource\-mailbox\fP, changing their contents, and changing
+the assigned IMAP flags and keywords.
+.TP
+.BI \-x\ extensions
+Set the available extensions. The parameter is a space\-separated list of the
+active extensions. By prepending the extension identifiers with \fB+\fP or
+\fB\-\fP, extensions can be included or excluded relative to the configured set
+of active extensions. If no extensions have a \fB+\fP or \fB\-\fP prefix, only
+those extensions that are explicitly listed will be enabled. Unknown extensions
+are ignored and a warning is produced.
+
+For example \fB\-x\fP \(dq+imapflags \-enotify\(dq will enable the deprecated
+imapflags extension and disable the enotify extension. The rest of the active
+extensions depends on the \fIsieve_extensions\fP and
+\fIsieve_global_extensions\fP settings. By default, i.e.
+when \fIsieve_extensions\fP and \fIsieve_global_extensions\fP remain
+unconfigured, all supported extensions are available, except for deprecated
+extensions or those that are still under development.
+
+.\"------------------------------------------------------------------------
+.SH ARGUMENTS
+.TP
+.I script\-file
+Specifies the Sieve script to (compile and) execute.
+
+Note that this tool looks for a pre\-compiled binary file with a \fI.svbin\fP
+extension and with basename and path identical to the specified script. Use the
+\fB\-C\fP option to disable this behavior by forcing the script to be compiled
+into a new binary.
+.TP
+.I source\-mailbox
+Specifies the source mailbox containing the messages that the Sieve filter will
+act upon.
+
+This is the name of a mailbox, as visible to IMAP clients, except in UTF-8
+format. The hierarchy separator between a parent and child mailbox is commonly
+.RB \(aq / \(aq
+or
+.RB \(aq . \(aq,
+but this depends on your selected mailbox storage format and
+namespace configuration. The mailbox names may also require a namespace prefix.
+
+This mailbox is not modified unless the \fB\-W\fP option is specified.
+.TP
+.I discard\-action
+Specifies what is done with messages in the \fIsource\-mailbox\fP that where not
+kept or otherwise stored by the Sieve script; i.e. those messages that would
+normally be discarded if the Sieve script were executed at delivery.
+The \fIdiscard\-action\fP parameter accepts one of the following values:
+.RS 7
+.TP
+.BR keep\ (default)
+Keep discarded messages in source mailbox.
+.TP
+.BI move\ mailbox
+Move discarded messages to the indicated \fImailbox\fP. This is for instance
+useful to move messages to a Trash mailbox. Refer to the explanation of
+the \fIsource\-mailbox\fP argument for more information on mailbox naming.
+.TP
+.B delete
+Flag discarded messages as \\DELETED.
+.TP
+.B expunge
+Expunge discarded messages, meaning that these are removed irreversibly when the
+tool finishes filtering.
+.RE
+.IP
+When the \fB\-W\fP option is not specified, the \fIsource\-mailbox\fP is
+immutable and the specified \fIdiscard\-action\fP has no effect. This means that
+messages are at most \fIcopied\fP to a new location. In contrast, when the
+\fB\-W\fP is specified, messages that are successfully stored somewhere else by
+the Sieve script are \fBalways\fP expunged from the \fIsource\-mailbox\fP, with
+the effect that these are thus \fImoved\fP to the new location. This happens
+irrespective of the specified \fIdiscard\-action\fP. Remember: only discarded
+messages are affected by the specified \fIdiscard\-action\fP.
+
+.\"------------------------------------------------------------------------
+
+.SH EXAMPLES
+
+.TP
+[...]
+
+.\"------------------------------------------------------------------------
+.SH "EXIT STATUS"
+.B sieve\-filter
+will exit with one of the following values:
+.TP 4
+.B 0
+Sieve filter applied successfully. (EX_OK, EXIT_SUCCESS)
+.TP
+.B 1
+Operation failed. This is returned for almost all failures.
+(EXIT_FAILURE)
+.TP
+.B 64
+Invalid parameter given. (EX_USAGE)
+.\"------------------------------------------------------------------------
+.SH FILES
+.TP
+.I @pkgsysconfdir@/dovecot.conf
+Dovecot\(aqs main configuration file.
+.TP
+.I @pkgsysconfdir@/conf.d/90\-sieve.conf
+Sieve interpreter settings (included from Dovecot\(aqs main configuration file)
+.\"------------------------------------------------------------------------
+@INCLUDE:reporting-bugs@
+.\"------------------------------------------------------------------------
+.SH "SEE ALSO"
+.BR dovecot (1),
+.BR dovecot\-lda (1),
+.BR sieve\-dump (1),
+.BR sieve\-test (1),
+.BR sievec (1),
+.BR pigeonhole (7)
diff --git a/pigeonhole/doc/man/sieve-test.1.in b/pigeonhole/doc/man/sieve-test.1.in
new file mode 100644
index 0000000..65e5230
--- /dev/null
+++ b/pigeonhole/doc/man/sieve-test.1.in
@@ -0,0 +1,257 @@
+.\" Copyright (c) 2010-2018 Pigeonhole authors, see the included COPYING file
+.TH "SIEVE\-TEST" 1 "2016-04-05" "Pigeonhole for Dovecot v2.4" "Pigeonhole"
+.SH NAME
+sieve\-test \- Pigeonhole\(aqs Sieve script tester
+.\"------------------------------------------------------------------------
+.SH SYNOPSIS
+.B sieve\-test
+.RI [ options ]
+.I script\-file
+.I mail\-file
+.\"------------------------------------------------------------------------
+.SH DESCRIPTION
+.PP
+The \fBsieve\-test\fP command is part of the Pigeonhole Project
+(\fBpigeonhole\fR(7)), which adds Sieve (RFC 5228) support to the Dovecot
+secure IMAP and POP3 server (\fBdovecot\fR(1)).
+.PP
+Using the \fBsieve\-test\fP command, the execution of Sieve scripts can be
+tested. This evaluates the script for the provided message, yielding a set of
+Sieve actions. Unless the \fB\-e\fP option is specified, it does not actually
+execute these actions, meaning that it does not store or forward the message
+anywere. Instead, it prints a detailed list of what actions would normally take
+place. Note that, even when \fB\-e\fP is specified, no messages are ever
+transmitted to remote SMTP recipients. The outgoing messages are always printed
+to \fBstdout\fP instead.
+.PP
+This is a very useful tool to debug the execution of Sieve scripts. It can be
+used to verify newly installed scripts for the intended behaviour and it can
+provide more detailed information about script execution problems that are
+reported by the Sieve plugin, for example by tracing the execution and
+evaluation of commands and tests respectively.
+.\"------------------------------------------------------------------------
+.SH OPTIONS
+.TP
+.BI \-a\ orig\-recipient\-address
+The original envelope recipient address. This is what Sieve\(aqs envelope test
+will compare to when the \(dqto\(dq envelope part is requested. Some tests and
+actions will also use this as the script owner\(aqs e\-mail address. If this
+option is omitted, the recipient address is retrieved from the
+\(dqEnvelope-To:\(dq, or \(dqTo:\(dq message headers. If none of these headers
+is present either, the recipient address defaults to
+\fIrecipient@example.com\fP.
+.TP
+.BI \-c\ config\-file
+Alternative Dovecot configuration file path.
+.TP
+.B \-C
+Force compilation. By default, the compiled binary is stored on disk. When this
+binary is found during the next execution of \fBsieve\-test\fP and its
+modification time is more recent than the script file, it is used and the script
+is not compiled again. This option forces the script to be compiled, thus
+ignoring any present binary. Refer to \fBsievec\fP(1) for more information about
+Sieve compilation.
+.TP
+.B \-D
+Enable Sieve debugging.
+.TP
+.BI \-d\ dump\-file
+Causes a dump of the generated code to be written to the specified file. This is
+identical to the dump produced by \fBsieve\-dump\fR(1). Using \(aq\-\(aq as
+filename causes the dump to be written to \fBstdout\fP.
+.TP
+.BI \-e
+Enables true execution of the set of actions that results from running the
+script. In combination with the \fB\-l\fP parameter, the actual delivery of
+messages can be tested. Note that this will not transmit any messages to remote
+SMTP recipients. Such actions only print the outgoing message to \fBstdout\fP.
+.TP
+.BI \-f\ envelope\-sender
+The envelope sender address (return path). This is what Sieve\(aqs envelope test
+will compare to when the \(dqfrom\(dq envelope part is requested. Also, this is
+where response messages are \(aqsent\(aq to. If this option is omitted, the sender
+address is retrieved from the \(dqReturn-Path:\(dq, \(dqSender:\(dq or
+\(dqFrom:\(dq message headers. If none of these headers is present either,
+the sender envelope address defaults to \fIsender@example.com\fP.
+.TP
+.BI \-l\ mail\-location
+The location of the user\(aqs mail store. The syntax of this option\(aqs
+\fImail\-location\fP parameter is identical to what is used for the
+mail_location setting in the Dovecot config file. This parameter is typically
+used in combination with \fB\-e\fP to test the actual delivery of messages. If
+\fB\-l\fP is omitted when \fB\-e\fP is specified, mail store actions like
+fileinto and keep are skipped.
+.TP
+.BI \-m\ default\-mailbox
+The mailbox where the keep action stores the message. This is \(dqINBOX\(dq
+by default.
+.TP
+.BI \-o\ setting = value
+Overrides the configuration
+.I setting
+from
+.I @pkgsysconfdir@/dovecot.conf
+and from the userdb with the given
+.IR value .
+In order to override multiple settings, the
+.B \-o
+option may be specified multiple times.
+.TP
+.BI \-r\ recipient\-address
+The final envelope recipient address. Some tests and actions will
+use this as the script owner\(aqs e\-mail address. For example, this is what is
+used by the vacation action to check whether a reply is appropriate. If the
+\fB\-r\fP option is omitted, the original envelope recipient address will be used
+instead (see \fB\-a\fP option for more info).
+.TP
+.BI \-s\ script\-file
+Specify additional scripts to be executed before the main script. Multiple
+\fB\-s\fP arguments are allowed and the specified scripts are executed
+sequentially in the order specified at the command
+line.
+.TP
+.BI \-t\ trace\-file
+Enables runtime trace debugging. Trace debugging provides detailed insight in
+the operations performed by the Sieve script. Refer to the runtime trace
+debugging section below. The trace information is written to the specified file.
+Using '\-' as filename causes the trace data to be written to \fBstdout\fP.
+.TP
+.BI \-T\ trace\-option
+Configures runtime trace debugging, which is enabled with the \fP\-t\fP option.
+Refer to the runtime trace debugging section below.
+.TP
+.BI \-u\ user
+Run the Sieve script for the given \fIuser\fP. When omitted, the
+.I command
+will be executed with the environment of the currently logged in user.
+.TP
+.BI \-x\ extensions
+Set the available extensions. The parameter is a space\-separated list of the
+active extensions. By prepending the extension identifiers with \fB+\fP or
+\fB\-\fP, extensions can be included or excluded relative to the configured set
+of active extensions. If no extensions have a \fB+\fP or \fB\-\fP prefix, only
+those extensions that are explicitly listed will be enabled. Unknown extensions
+are ignored and a warning is produced.
+
+For example \fB\-x\fP \(dq+imapflags \-enotify\(dq will enable the deprecated
+imapflags extension and disable the enotify extension. The rest of the active
+extensions depends on the \fIsieve_extensions\fP and
+\fIsieve_global_extensions\fP settings. By default, i.e.
+when \fIsieve_extensions\fP and \fIsieve_global_extensions\fP remain
+unconfigured, all supported extensions are available, except for deprecated
+extensions or those that are still under development.
+
+.\"------------------------------------------------------------------------
+.SH ARGUMENTS
+.TP
+.I script\-file
+Specifies the script to (compile and) execute.
+
+Note that this tool looks for a pre\-compiled binary file with a \fI.svbin\fP
+extension and with basename and path identical to the specified script. Use the
+\fB\-C\fP option to disable this behavior by forcing the script to be compiled
+into a new binary.
+.TP
+.I mail\-file
+Specifies the file containing the e\-mail message to test with.
+.\"------------------------------------------------------------------------
+.SH USAGE
+.SS RUNTIME TRACE DEBUGGING
+.PP
+Using the \fB\-t\fP option, the \fBsieve\-test\fP tool can be configured to
+print detailed trace information on the Sieve script execution to a file or
+standard output. For example, the encountered commands, the performed tests and
+the matched values can be printed.
+.PP
+The runtime trace can be configured using the \fB\-T\fP option, which can be
+specified multiple times. It can be used as follows:
+
+.TP 2
+\fB\-Tlevel=...\fP
+Set the detail level of the trace debugging. One of the following values can
+be supplied:
+.RS 2
+.TP 3
+\fIactions\fP (default)
+Only print executed action commands, like keep, fileinto, reject and redirect.
+.TP
+\fIcommands\fP
+Print any executed command, excluding test commands.
+.TP
+\fItests\fP
+Print all executed commands and performed tests.
+.TP
+\fImatching\fP
+Print all executed commands, performed tests and the values matched in those
+tests.
+.RE
+.TP 2
+\fB\-Tdebug\fP
+Print debug messages as well. This is usually only useful for developers and
+is likely to produce messy output.
+.TP
+\fB\-Taddresses\fP
+Print byte code addresses for the current trace output. Normally, only the
+current Sieve source code position (line number) is printed. The byte code
+addresses are equal to those listed in a binary dump produced using the
+\fB\-d\fP option or by the \fBsieve\-dump(1)\fP command.
+.\"------------------------------------------------------------------------
+.SS DEBUG SIEVE EXTENSION
+.PP
+To improve script debugging, this Sieve implementation supports a custom Sieve
+language extension called \(aqvnd.dovecot.debug\(aq. It adds the \fBdebug_log\fP
+command that allows logging debug messages.
+.PP
+Example:
+.PP
+require \(dqvnd.dovecot.debug\(dq;
+.PP
+if header :contains \(dqsubject\(dq \(dqhello\(dq {
+.PP
+ debug_log \(dqSubject header contains hello!\(dq;
+.PP
+}
+.PP
+Tools such as \fBsieve\-test\fP, \fBsievec\fP and \fBsieve\-dump\fP have support
+for the vnd.dovecot.debug extension enabled by default and it is not necessary
+to enable nor possible to disable the availability of the debug extension with
+the \fB\-x\fP option. The logged messages are written to \fBstdout\fP in this
+case.
+
+In contrast, for the actual Sieve plugin for the Dovecot LDA
+(\fBdovecot\-lda\fR(1)) the vnd.dovecot.debug extension needs to be enabled
+explicitly using the \fIsieve_extensions\fP setting. The messages are then
+logged to the user's private script log file. If used in a global script, the
+messages are logged through the default Dovecot logging facility.
+.\"------------------------------------------------------------------------
+.SH "EXIT STATUS"
+.B sieve\-test
+will exit with one of the following values:
+.TP 4
+.B 0
+Execution was successful. (EX_OK, EXIT_SUCCESS)
+.TP
+.B 1
+Operation failed. This is returned for almost all failures.
+(EXIT_FAILURE)
+.TP
+.B 64
+Invalid parameter given. (EX_USAGE)
+.\"------------------------------------------------------------------------
+.SH FILES
+.TP
+.I @pkgsysconfdir@/dovecot.conf
+Dovecot\(aqs main configuration file.
+.TP
+.I @pkgsysconfdir@/conf.d/90\-sieve.conf
+Sieve interpreter settings (included from Dovecot\(aqs main configuration file)
+.\"------------------------------------------------------------------------
+@INCLUDE:reporting-bugs@
+.\"------------------------------------------------------------------------
+.SH "SEE ALSO"
+.BR dovecot (1),
+.BR dovecot\-lda (1),
+.BR sieve\-dump (1),
+.BR sieve\-filter (1),
+.BR sievec (1),
+.BR pigeonhole (7)
diff --git a/pigeonhole/doc/man/sievec.1.in b/pigeonhole/doc/man/sievec.1.in
new file mode 100644
index 0000000..548bcca
--- /dev/null
+++ b/pigeonhole/doc/man/sievec.1.in
@@ -0,0 +1,142 @@
+.\" Copyright (c) 2010-2018 Pigeonhole authors, see the included COPYING file
+.TH "SIEVEC" 1 "2016-04-05" "Pigeonhole for Dovecot v2.4" "Pigeonhole"
+.\"------------------------------------------------------------------------
+.SH NAME
+sievec \- Pigeonhole\(aqs Sieve script compiler
+.\"------------------------------------------------------------------------
+.SH SYNOPSIS
+.B sievec
+.RI [ options ]
+.I script\-file
+.RI [ out\-file ]
+.\"------------------------------------------------------------------------
+.SH DESCRIPTION
+.PP
+The \fBsievec\fP command is part of the Pigeonhole Project
+(\fBpigeonhole\fR(7)), which adds Sieve (RFC 5228) support to the Dovecot
+secure IMAP and POP3 server (\fBdovecot\fR(1)).
+.PP
+Using the \fBsievec\fP command, Sieve scripts can be compiled into a binary
+representation. The resulting binary can be used directly to process e\-mail
+messages during the delivery process. The delivery of mail messages and \- by
+means of the LDA Sieve plugin \- also the execution of Sieve scripts is
+performed by Dovecot\(aqs local delivery agent (LDA) called \fBdovecot\-lda\fP(1).
+Usually, it is not necessary to compile the Sieve script manually using
+\fBsievec\fP, because \fBdovecot\-lda\fP will do this automatically if the binary
+is missing. However, in some cases \fBdovecot\-lda\fP does not have permission to
+write the compiled binary to disk, forcing it to recompile the script every time
+it is executed. Using the \fBsievec\fP tool, this can be performed manually by
+an authorized user to increase performance.
+.PP
+The Pigeonhole Sieve implementation recognizes files with a \fB.sieve\fP
+extension as Sieve scripts and corresponding files with a \fB.svbin\fP extension
+as the associated compiled binary. This means for example that Dovecot\(aqs LDA
+process will first look for a binary file \(dqdovecot.svbin\(dq when it needs to
+execute \(dqdovecot.sieve\(dq. It will compile a new binary when it is missing
+or outdated.
+.PP
+The \fBsievec\fP command is also useful to verify Sieve scripts before using.
+Additionally, with the \fB\-d\fP option it can output a textual (and thus
+human\-readable) dump of the generated Sieve code to the specified file. The
+output is then identical to what the \fBsieve\-dump\fP(1) command produces for a
+stored binary file. This output is mainly useful to find bugs in the compiler
+that yield corrupt binaries.
+.\"------------------------------------------------------------------------
+.SH OPTIONS
+.TP
+.BI \-c\ config\-file
+Alternative Dovecot configuration file path.
+.TP
+.B \-d
+Don\(aqt write the binary to \fIout\-file\fP, but write a textual dump of the
+binary instead. In this context, the \fIout\-file\fP value '\-' has special
+meaning: it causes the the textual dump to be written to \fBstdout\fP.
+The \fIout\-file\fP argument may also be omitted, which has the same effect
+as '\-'.
+The output is identical to what the \fBsieve\-dump\fP(1) command produces
+for a compiled Sieve binary file. Note that this option is not allowed when the
+\fIout\-file\fP argument is a directory.
+.TP
+.B \-D
+Enable Sieve debugging.
+.TP
+.BI \-o\ setting = value
+Overrides the configuration
+.I setting
+from
+.I @pkgsysconfdir@/dovecot.conf
+and from the userdb with the given
+.IR value .
+In order to override multiple settings, the
+.B \-o
+option may be specified multiple times.
+.TP
+.BI \-u\ user
+Run the Sieve script for the given \fIuser\fP. When omitted, the
+.I command
+will be executed with the environment of the currently logged in user.
+.TP
+.BI \-x\ extensions
+Set the available extensions. The parameter is a space\-separated list of the
+active extensions. By prepending the extension identifiers with \fB+\fP or
+\fB\-\fP, extensions can be included or excluded relative to the configured set
+of active extensions. If no extensions have a \fB+\fP or \fB\-\fP prefix, only
+those extensions that are explicitly listed will be enabled. Unknown extensions
+are ignored and a warning is produced.
+
+For example \fB\-x\fP \(dq+imapflags \-enotify\(dq will enable the deprecated
+imapflags extension and disable the enotify extension. The rest of the active
+extensions depends on the \fIsieve_extensions\fP and
+\fIsieve_global_extensions\fP settings. By default, i.e.
+when \fIsieve_extensions\fP and \fIsieve_global_extensions\fP remain
+unconfigured, all supported extensions are available, except for deprecated
+extensions or those that are still under development.
+
+.\"------------------------------------------------------------------------
+.SH ARGUMENTS
+.TP
+.I script\-file
+Specifies the script to be compiled. If the \fIscript\-file\fP argument is a
+directory, all files in that directory with a \fI.sieve\fP extension are
+compiled into a corresponding \fI.svbin\fP binary file. The compilation is not
+halted upon errors; it attempts to compile as many scripts in the directory as
+possible. Note that the \fB\-d\fP option and the \fIout\-file\fP argument are
+not allowed when the \fIscript\-file\fP argument is a directory.
+.TP
+.I out\-file
+Specifies where the (binary) output is to be written. This argument is optional.
+If this argument is omitted, a binary compiled from <scriptname>.sieve is saved
+as <scriptname>.svbin. If this argument is omitted and \fB\-b\fP is specified,
+the binary dump is output to \fBstdout\fP.
+.\"------------------------------------------------------------------------
+.SH "EXIT STATUS"
+.B sievec
+will exit with one of the following values:
+.TP 4
+.B 0
+Compile was successful. (EX_OK, EXIT_SUCCESS)
+.TP
+.B 1
+Operation failed. This is returned for almost all failures.
+(EXIT_FAILURE)
+.TP
+.B 64
+Invalid parameter given. (EX_USAGE)
+.\"------------------------------------------------------------------------
+.SH FILES
+.TP
+.I @pkgsysconfdir@/dovecot.conf
+Dovecot\(aqs main configuration file.
+.TP
+.I @pkgsysconfdir@/conf.d/90\-sieve.conf
+Sieve interpreter settings (included from Dovecot\(aqs main configuration file)
+.\"------------------------------------------------------------------------
+@INCLUDE:reporting-bugs@
+.\"------------------------------------------------------------------------
+.SH "SEE ALSO"
+.BR dovecot (1),
+.BR dovecot\-lda (1),
+.BR sieve\-dump (1),
+.BR sieve\-filter (1),
+.BR sieve\-test (1),
+.BR pigeonhole (7)
diff --git a/pigeonhole/doc/man/sieved.1 b/pigeonhole/doc/man/sieved.1
new file mode 100644
index 0000000..7a4854a
--- /dev/null
+++ b/pigeonhole/doc/man/sieved.1
@@ -0,0 +1 @@
+.so man1/sieve-dump.1
diff --git a/pigeonhole/doc/plugins/Makefile.am b/pigeonhole/doc/plugins/Makefile.am
new file mode 100644
index 0000000..4280aa6
--- /dev/null
+++ b/pigeonhole/doc/plugins/Makefile.am
@@ -0,0 +1,13 @@
+docfiles = \
+ imap_filter_sieve.txt \
+ imapsieve.txt \
+ sieve_extprograms.txt
+
+if BUILD_DOCS
+plugins_docdir = $(sieve_docdir)/plugins
+plugins_doc_DATA = $(docfiles)
+endif
+
+EXTRA_DIST = \
+ $(docfiles)
+
diff --git a/pigeonhole/doc/plugins/Makefile.in b/pigeonhole/doc/plugins/Makefile.in
new file mode 100644
index 0000000..73ab19c
--- /dev/null
+++ b/pigeonhole/doc/plugins/Makefile.in
@@ -0,0 +1,576 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = doc/plugins
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugins_docdir)"
+DATA = $(plugins_doc_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+docfiles = \
+ imap_filter_sieve.txt \
+ imapsieve.txt \
+ sieve_extprograms.txt
+
+@BUILD_DOCS_TRUE@plugins_docdir = $(sieve_docdir)/plugins
+@BUILD_DOCS_TRUE@plugins_doc_DATA = $(docfiles)
+EXTRA_DIST = \
+ $(docfiles)
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/plugins/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign doc/plugins/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-plugins_docDATA: $(plugins_doc_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(plugins_doc_DATA)'; test -n "$(plugins_docdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(plugins_docdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(plugins_docdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(plugins_docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(plugins_docdir)" || exit $$?; \
+ done
+
+uninstall-plugins_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugins_doc_DATA)'; test -n "$(plugins_docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(plugins_docdir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(plugins_docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-plugins_docDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-plugins_docDATA
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-plugins_docDATA install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags-am uninstall uninstall-am \
+ uninstall-plugins_docDATA
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/doc/plugins/imap_filter_sieve.txt b/pigeonhole/doc/plugins/imap_filter_sieve.txt
new file mode 100644
index 0000000..78c4e59
--- /dev/null
+++ b/pigeonhole/doc/plugins/imap_filter_sieve.txt
@@ -0,0 +1,52 @@
+IMAP FILTER Sieve plugin for Pigeonhole
+
+Relevant specifications
+=======================
+
+ doc/rfc/draft-bosch-imap-filter-sieve-00.txt
+
+Introduction
+============
+
+Normally, Sieve filters can either be applied at initial mail delivery or
+triggered by certain events in the Internet Message Access Protocol (IMAPSIEVE;
+RFC 6785). The user can configure which Sieve scripts to run at these instances,
+but it is not possible to trigger the execution of Sieve scripts manually.
+However, this could be very useful; e.g, to test new Sieve rules and to
+re-filter messages that were erroneously handled by an earlier version of the
+Sieve scripts involved.
+
+Pigeonhole provides the imap_filter_sieve plugin, which provides a vendor-
+defined IMAP extension called "FILTER=SIEVE". This adds a new "FILTER" command
+that allows applying a mail filter (a Sieve script) on a set of messages that
+match the specified searching criteria.
+
+This plugin is experimental and the specification is likely to change.
+
+Configuration
+=============
+
+The IMAP FILTER Sieve plugin is activated by adding it to the mail_plugins
+setting for the imap protocol:
+
+protocol imap {
+ mail_plugins = $mail_plugins imap_filter_sieve
+}
+
+Currently, no other settings specific to this plugin are defined. It uses the
+normal configuration settings used by the LDA Sieve plugin at delivery.
+
+The sieve_before and sieve_after scripts are currently ignored by this plugin.
+
+Example
+-------
+
+protocol imap {
+ # Space separated list of plugins to load (default is global mail_plugins).
+ mail_plugins = $mail_plugins imap_filter_sieve
+}
+
+plugin {
+ sieve_global = /usr/lib/dovecot/sieve-global.d
+}
+
diff --git a/pigeonhole/doc/plugins/imapsieve.txt b/pigeonhole/doc/plugins/imapsieve.txt
new file mode 100644
index 0000000..9601e97
--- /dev/null
+++ b/pigeonhole/doc/plugins/imapsieve.txt
@@ -0,0 +1,155 @@
+IMAPSIEVE plugins for Pigeonhole
+
+Relevant specifications
+=======================
+
+ doc/rfc/imapsieve.rfc6785.txt
+
+Introduction
+============
+
+As defined in the base specification, the Sieve language is used only during
+delivery. However, in principle, it can be used at any point in the processing
+of an email message. RFC 6785 defines the use of Sieve filtering in IMAP,
+operating when messages are created or their attributes are changed. This
+feature extends both Sieve and IMAP. Therefore, Pigeonhole provides both an
+IMAP and a Sieve plugin. The IMAP plugin is called "imap_sieve" and the Sieve
+plugin is called "sieve_imapsieve".
+
+The basic IMAPSIEVE capability allows attaching a Sieve script to a mailbox
+(or any mailbox) by setting a special IMAP METADATA entry. This way, users can
+configure Sieve scripts that are run for IMAP events in their mailboxes. The
+Pigeonhole implementation also adds the ability for administrators to configure
+Sieve scripts outside the user's control, that are run either before or after a
+user's script if there is one.
+
+Dovecot-specific Environment Items
+==================================
+
+The "imapsieve" extension defined in RFC 6785 defines additional environment
+items for the "environment" extension defined in RFC 5183. Beyond those, Dovecot
+defines a few more. These are available when the Dovecot-specific
+"vnd.dovecot.imapsieve" extension is enabled using the "require" command. The
+"vnd.dovecot.imapsieve" extension implicitly uses the "imapsieve" extension, so
+that extension does not need to be enabled as well in that case. The following
+Dovecot-specific environment items are added:
+
+vnd.dovecot.mailbox-from
+ The mailbox where the message is being copied or moved from (the source
+ mailbox). This environment item is only set when the Sieve script is executed
+ from an IMAP COPY or MOVE command.
+
+vnd.dovecot.mailbox-to
+ The mailbox where the message is being copied to (the destination mailbox).
+ If the Sieve script is not executed from an IMAP COPY or MOVE command, this
+ environment is always equal to the "imap.mailbox" environment item. Otherwise,
+ the "imap.mailbox" item points to the mailbox where the Sieve script is
+ executing for, which may actually be the source mailbox (see the
+ imapsieve_mailboxXXX_copy_source_after setting).
+
+Configuration
+=============
+
+The IMAP plugin is activated by adding it to the mail_plugins setting for
+the imap protocol:
+
+protocol imap {
+ mail_plugins = $mail_plugins imap_sieve
+}
+
+This only will enable support for administrator scripts. User scripts are only
+supported when additionally a Sieve URL is configured using the imapsieve_url
+plugin setting. This URL points to the ManageSieve server that users need to use
+to upload their Sieve scripts. This URL will be shown to the client in the IMAP
+CAPABILITY response as IMAPSIEVE=<URL>.
+
+The Sieve plugin is activated by adding it to the sieve_plugins setting:
+
+sieve_plugins = sieve_imapsieve
+
+This plugin registers the "imapsieve" extension with the Sieve interpreter. This
+extension is enabled implicitly, which means that it does not need to be added
+to the "sieve_extensions" setting.
+
+Note that the "imapsieve" extension can only be used from IMAP. When it is used
+in the active delivery script, it will cause runtime errors. To make a Sieve
+script suitable for both delivery and IMAP, the availability of the extension
+can be tested using the "ihave" test (RFC 5463) as usual.
+
+The following settings are recognized the "imap_sieve" plugin:
+
+imapsieve_url =
+ If configured, this setting enables support for user Sieve scripts in IMAP.
+ So, leave this unconfigured if you don't want users to have the ability to
+ associate Sieve scripts with mailboxes. The value is an URL pointing to the
+ ManageSieve server that users must use to upload their Sieve scripts.
+
+imapsieve_mailboxXXX_name =
+ This setting configures the name of a mailbox for which administrator scripts
+ are configured. The `XXX' in this setting is a sequence number, which allows
+ configuring multiple associations between Sieve scripts and mailboxes. The
+ settings defined hereafter with matching sequence numbers apply to the mailbox
+ named by this setting. The sequence of configured mailboxes ends at the first
+ missing "imapsieve_mailboxXXX_name" setting. This setting supports wildcards
+ with a syntax compatible with the IMAP LIST command, meaning that this
+ setting can apply to multiple or even all ("*") mailboxes.
+
+imapsieve_mailboxXXX_before =
+imapsieve_mailboxXXX_after =
+ When an IMAP event of interest occurs, these sieve scripts are executed before
+ and after any user script respectively. These settings each specify the
+ location of a single sieve script. The semantics of these settings are very
+ similar to the "sieve_before" and "sieve_after" settings: the specified
+ scripts form a sequence together with the user script in which the next script
+ is only executed when an (implicit) keep action is executed.
+
+imapsieve_mailboxXXX_causes =
+ Only execute the administrator Sieve scripts for the mailbox configured with
+ "imapsieve_mailboxXXX_name" when one of the listed IMAPSIEVE causes apply.
+ This has no effect on the user script, which is always executed no matter the
+ cause.
+
+imapsieve_mailboxXXX_from =
+ Only execute the administrator Sieve scripts for the mailbox configured with
+ "imapsieve_mailboxXXX_name" when the message originates from the indicated
+ mailbox. This setting supports wildcards with a syntax compatible with the
+ IMAP LIST command
+
+imapsieve_mailboxXXX_copy_source_after =
+ When the cause is "COPY", run the specified Sieve script for the message in
+ the source mailbox after the Sieve script for the corresponding message in the
+ destination mailbox successfully finishes executing . This does not apply to
+ moved messages, since the message is removed from the source mailbox in that
+ case.
+
+imapsieve_expunge_discarded=no
+ When enabled, discarded messages (for which no keep action is in effect) will
+ be expunged immediately when the Sieve script execution is succcessful.
+ Normally, such messages are only marked with the "\Deleted" flag and will be
+ expunged only when the client explicitly issues an IMAP EXPUNGE command on the
+ mailbox at a later time.
+
+Example
+-------
+
+protocol imap {
+ # Space separated list of plugins to load (default is global mail_plugins).
+ mail_plugins = $mail_plugins imap_sieve
+}
+
+plugin {
+ sieve_plugins = sieve_imapsieve
+
+ imapsieve_url = sieve://sieve.example.org
+
+ # From elsewhere to Spam folder
+ imapsieve_mailbox1_name = Spam
+ imapsieve_mailbox1_causes = COPY
+ imapsieve_mailbox1_before = file:/usr/lib/dovecot/sieve/report-spam.sieve
+ # From Spam folder to elsewhere
+ imapsieve_mailbox2_name = *
+ imapsieve_mailbox2_from = Spam
+ imapsieve_mailbox2_causes = COPY
+ imapsieve_mailbox2_before = file:/usr/lib/dovecot/sieve/report-ham.sieve
+}
+
diff --git a/pigeonhole/doc/plugins/sieve_extprograms.txt b/pigeonhole/doc/plugins/sieve_extprograms.txt
new file mode 100644
index 0000000..4110fce
--- /dev/null
+++ b/pigeonhole/doc/plugins/sieve_extprograms.txt
@@ -0,0 +1,182 @@
+Sieve Extprograms plugin for Pigeonhole
+
+Relevant specifications
+=======================
+
+ doc/rfc/spec-bosch-sieve-extprograms.txt
+
+Introduction
+============
+
+Sieve (RFC 5228) is a highly extensible machine language specifically tailored
+for internet message filtering. For the Dovecot Secure IMAP server, Sieve
+support is provided by the Pigeonhole Sieve plugin. This package includes a
+plugin for Pigeonhole called "sieve_extprograms", which extends the Sieve
+filtering implementation with action commands for invoking a predefined set of
+external programs. Messages can be piped to or filtered through those programs
+and string data can be input to and retrieved from those programs.
+
+The Sieve language is explicitly designed to be powerful enough to be useful yet
+limited in order to allow for a safe server-side filtering system. Therefore,
+the base specification of the language makes it impossible for users to do
+anything more complex (and dangerous) than write simple mail filters. One of the
+consequences of this security-minded design is that users cannot execute
+external programs from their mail filter. Particularly for server-side filtering
+setups in which mail accounts have no corresponding system account, allowing the
+execution of arbitrary programs from the mail filter can be a significant
+security risk. However, such functionality can also be very useful, for instance
+to easily implement a custom action or external effect that Sieve normally
+cannot provide.
+
+The "sieve_extprograms" plugin provides an extension to the Sieve filtering
+language adding new action commands for invoking a predefined set of external
+programs. To mitigate the security concerns, the external programs cannot be
+chosen arbitrarily; the available programs are restricted through administrator
+configuration.
+
+This extension is specific to the Pigeonhole Sieve implementation for the
+Dovecot Secure IMAP server. It will therefore most likely not be supported by
+web interfaces or GUI-based Sieve editors. This extension is primarily meant for
+use in small setups or global scripts that are managed by the systems
+administrator.
+
+Implementation Status
+---------------------
+
+The "vnd.dovecot.pipe", "vnd.dovecot.filter" and "vnd.dovecot.execute" Sieve
+language extensions introduced by this plugin are vendor-specific with draft
+status and their implementation for Pigeonhole is experimental, which means that
+the language extensions are still subject to change and that the current
+implementation is not thoroughly tested.
+
+Configuration
+=============
+
+The plugin is activated by adding it to the sieve_plugins setting:
+
+sieve_plugins = sieve_extprograms
+
+This plugin registers the "vnd.dovecot.pipe", "vnd.dovecot.filter" and
+"vnd.dovecot.execute" extensions with the Sieve interpreter. However, these
+extensions are not enabled by default and thus need to be enabled explicitly. It
+is recommended to restrict the use of these extensions to global context by
+adding these to the "sieve_global_extensions" setting. If personal user scripts
+also need to directly access external programs, the extensions need to be added
+to the "sieve_extensions" setting.
+
+The commands introduced by the Sieve language extensions in this plugin can
+directly pipe a message or string data to an external program (typically a shell
+script) by forking a new process. Alternatively, these can connect to a unix
+socket behind which a Dovecot script service is listening to start the external
+program, e.g. to execute as a different user or for added security.
+
+The program name specified for the new Sieve "pipe", "filter" and "execute"
+commands is used to find the program or socket in a configured directory.
+Separate directories are specified for the sockets and the directly executed
+binaries. The socket directory is searched first. Since the use of "/" in
+program names is prohibited, it is not possible to build a hierarchical
+structure.
+
+Directly forked programs are executed with a limited set of environment
+variables: HOME, USER, HOST, SENDER, RECIPIENT and ORIG_RECIPIENT. Programs
+executed through the script-pipe socket service currently have no environment
+set at all.
+
+If a shell script is expected to read a message or string data, it must fully
+read the provided input until the data ends with EOF, otherwise the Sieve action
+invoking the program will fail. The action will also fail when the shell script
+returns a nonzero exit code. Standard output is available for returning a
+message (for the filter command) or string data (for the execute command) to the
+Sieve interpreter. Standard error is written to the LDA log file.
+
+The three extensions introduced by this plugin - "vnd.dovecot.pipe",
+"vnd.dovecot.filter" and "vnd.dovecot.pipe" - each have separate but similar
+configuration. The settings that specify a time period are specified in
+s(econds), unless followed by a d(ay), h(our) or m(inute) specifier character.
+The following configuration settings are used, for which "<extension>" in the
+setting name is replaced by either "pipe", "filter" or "execute" depending on
+which extension is being configured.
+
+sieve_<extension>_socket_dir =
+ Points to a directory relative to the Dovecot base_dir where the plugin looks
+ for script service sockets.
+
+sieve_<extension>_bin_dir =
+ Points to a directory where the plugin looks for programs (shell scripts) to
+ execute directly and pipe messages to.
+
+sieve_<extension>_exec_timeout = 10s
+ Configures the maximum execution time after which the program is forcibly
+ terminated.
+
+sieve_<extension>_input_eol = crlf
+ Determines the end-of-line character sequence used for the data piped to
+ external programs. The default is currently "crlf", which represents a
+ sequence of the carriage return (CR) and line feed (LF) characters. This
+ matches the Internet Message Format (RFC5322) and what Sieve itself uses as a
+ line ending. Set this setting to "lf" to use a single LF character instead.
+
+Examples
+--------
+
+Example 1: socket service for "pipe" and "execute"
+
+plugin {
+ sieve = ~/.dovecot.sieve
+
+ sieve_plugins = sieve_extprograms
+ sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.execute
+
+ # pipe sockets in /var/run/dovecot/sieve-pipe
+ sieve_pipe_socket_dir = sieve-pipe
+
+ # execute sockets in /var/run/dovecot/sieve-execute
+ sieve_execute_socket_dir = sieve-execute
+}
+
+service sieve-pipe-script {
+ # This script is executed for each service connection
+ executable = script /usr/lib/dovecot/sieve-extprograms/sieve-pipe-action.sh
+
+ # use some unprivileged user for execution
+ user = dovenull
+
+ # socket name is program-name in Sieve (without sieve-pipe/ prefix)
+ unix_listener sieve-pipe/sieve-pipe-script {
+ }
+}
+
+service sieve-execute-action {
+ # This script is executed for each service connection
+ executable = script /usr/lib/dovecot/sieve-extprograms/sieve-execute-action.sh
+
+ # use some unprivileged user for execution
+ user = dovenull
+
+ # socket name is program-name in Sieve (without sieve-execute/ prefix)
+ unix_listener sieve-execute/sieve-execute-action {
+ }
+}
+
+Example 2: direct execution for "pipe" and "filter"
+
+plugin {
+ sieve = ~/.dovecot.sieve
+
+ sieve_plugins = sieve_extprograms
+ sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.filter
+
+ # This directory contains the scripts that are available for the pipe command.
+ sieve_pipe_bin_dir = /usr/lib/dovecot/sieve-pipe
+
+ # This directory contains the scripts that are available for the filter
+ # command.
+ sieve_filter_bin_dir = /usr/lib/dovecot/sieve-filter
+}
+
+Using
+=====
+
+Refer to doc/rfc/spec-bosch-sieve-extprograms.txt for a specification of the
+Sieve language extensions.
+
diff --git a/pigeonhole/dovecot-pigeonhole.m4 b/pigeonhole/dovecot-pigeonhole.m4
new file mode 100644
index 0000000..1ccff82
--- /dev/null
+++ b/pigeonhole/dovecot-pigeonhole.m4
@@ -0,0 +1,62 @@
+# pigeonhole.m4 - Check presence of pigeonhole -*-Autoconf-*-
+#.
+
+# serial 5
+
+AC_DEFUN([DC_PIGEONHOLE],[
+ AC_ARG_WITH(pigeonhole,
+ [ --with-pigeonhole=DIR Pigeonhole base directory],
+ pigeonholedir="$withval",
+ [
+ pg_prefix=$prefix
+ test "x$pg_prefix" = xNONE && pg_prefix=$ac_default_prefix
+ pigeonholedir="$pg_prefix/include/dovecot/sieve"
+ ]
+ )
+
+ AC_MSG_CHECKING([for pigeonhole in "$pigeonholedir"])
+
+ top=`pwd`
+ cd $pigeonholedir
+ pigeonholedir=`pwd`
+ cd $top
+ AC_SUBST(pigeonholedir)
+
+ PIGEONHOLE_TESTSUITE=
+ if test -f "$pigeonholedir/src/lib-sieve/sieve.h"; then
+ AC_MSG_RESULT([found])
+ pigeonhole_incdir="$pigeonholedir"
+ LIBSIEVE_INCLUDE='\
+ -I$(pigeonhole_incdir) \
+ -I$(pigeonhole_incdir)/src/lib-sieve \
+ -I$(pigeonhole_incdir)/src/lib-sieve/util \
+ -I$(pigeonhole_incdir)/src/lib-sieve/plugins/copy \
+ -I$(pigeonhole_incdir)/src/lib-sieve/plugins/enotify \
+ -I$(pigeonhole_incdir)/src/lib-sieve/plugins/imap4flags \
+ -I$(pigeonhole_incdir)/src/lib-sieve/plugins/mailbox \
+ -I$(pigeonhole_incdir)/src/lib-sieve/plugins/variables'
+ PIGEONHOLE_TESTSUITE="${pigeonholedir}/src/testsuite/testsuite"
+ elif test -f "$pigeonholedir/sieve.h"; then
+ AC_MSG_RESULT([found])
+ pigeonhole_incdir="$pigeonholedir"
+ LIBSIEVE_INCLUDE='-I$(pigeonhole_incdir)'
+ else
+ AC_MSG_RESULT([not found])
+ AC_MSG_NOTICE([
+ Pigeonhole Sieve headers not found from $pigeonholedir and they
+ are not installed in the Dovecot include path, use --with-pigeonhole=PATH
+ to give path to Pigeonhole sources or installed headers.])
+ AC_MSG_ERROR([pigeonhole not found])
+ fi
+
+ DISTCHECK_CONFIGURE_FLAGS="$DISTCHECK_CONFIGURE_FLAGS --with-pigeonhole=$pigeonholedir"
+
+ AM_CONDITIONAL(PIGEONHOLE_TESTSUITE_AVAILABLE, ! test -z "$PIGEONHOLE_TESTSUITE")
+
+ pigeonhole_incdir="$pigeonholedir"
+
+ AC_SUBST(pigeonhole_incdir)
+
+ AC_SUBST(LIBSIEVE_INCLUDE)
+ AC_SUBST(PIGEONHOLE_TESTSUITE)
+])
diff --git a/pigeonhole/dummy-config.h.in b/pigeonhole/dummy-config.h.in
new file mode 100644
index 0000000..1f1e1bf
--- /dev/null
+++ b/pigeonhole/dummy-config.h.in
@@ -0,0 +1,106 @@
+/* dummy-config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define if your compiler has -fno-sanitize=nonnull-attribute */
+#undef HAVE_FNO_SANITIZE_NONNULL_ATTRIBUTE
+
+/* Define if your compiler has -fsanitize=implicit-integer-truncation */
+#undef HAVE_FSANITIZE_IMPLICIT_INTEGER_TRUNCATION
+
+/* Define if your compiler has -fsanitize=integer */
+#undef HAVE_FSANITIZE_INTEGER
+
+/* Define if your compiler has -fsanitize=local-bounds */
+#undef HAVE_FSANITIZE_LOCAL_BOUNDS
+
+/* Define if your compiler has -fsanitize=nullability */
+#undef HAVE_FSANITIZE_NULLABILITY
+
+/* Define if your compiler has -fsanitize=undefined */
+#undef HAVE_FSANITIZE_UNDEFINED
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <sasl.h> header file. */
+#undef HAVE_SASL_H
+
+/* Define to 1 if you have the <sasl/sasl.h> header file. */
+#undef HAVE_SASL_SASL_H
+
+/* Define to build unfinished features/extensions. */
+#undef HAVE_SIEVE_UNFINISHED
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define if your compiler supports undefined sanitizers */
+#undef HAVE_UNDEFINED_SANITIZER
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define if you have ldap_initialize */
+#undef LDAP_HAVE_INITIALIZE
+
+/* Define if you have ldap_start_tls_s */
+#undef LDAP_HAVE_START_TLS_S
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#undef LT_OBJDIR
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Pigeonhole ABI version */
+#undef PIGEONHOLE_ABI_VERSION
+
+/* Define to the full name of Pigeonhole for Dovecot. */
+#undef PIGEONHOLE_NAME
+
+/* Define to the version of Pigeonhole for Dovecot. */
+#undef PIGEONHOLE_VERSION
+
+/* LDAP support is built in */
+#undef SIEVE_BUILTIN_LDAP
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Build with LDAP support */
+#undef STORAGE_LDAP
diff --git a/pigeonhole/examples/elvey.sieve b/pigeonhole/examples/elvey.sieve
new file mode 100644
index 0000000..869f1c9
--- /dev/null
+++ b/pigeonhole/examples/elvey.sieve
@@ -0,0 +1,153 @@
+# Example Sieve Script
+# Author: Matthew Elvey (Slightly modified to remove syntax and context errors)
+# URL: http://www.elvey.com/it/sieve/SieveScript.txt
+
+# Initial version completed and put in place 4/1/02 by Matthew Elvey (firstname@lastname.com ; I've checked and it's not a valid address.); Copyright (C).and.current as of 5/19/2002
+#Change log:
+#+ spam[:high]; major reordering; +DFC,BugTraq, PB up +Economist, FolderPath corrections
+#+ redid .0 matches. +Korean + whitelist +@f(useful once I start bouncing mail!)
+#+open mag, simplifications, to fm=spamNOTwhite, Bulk changes, IETF rules, +lst
+#Reword spam bounce.+scalable@ re-correction+++Work+activate Spam Optimization, etc...
+#oops high = 2x threshold, so 2x1 is 2! Too low. To @fm:bounce. Added tons of comments.
+require ["fileinto", "reject", "vacation", "envelope", "regex"];
+
+if header :contains "subject" ["un eject", "lastname.com/spamoff.htm agreed to"] { #I give out "uneject" to people to let them bypass the spam or size filters.
+ keep;
+} elsif header :contains "subject" ["ADV:", "bounceme", "2002 Gov Grants", #bounceme is useful for testing.
+ "ADV:ADLT", "ADV-ADULT", "ADULT ADVERTISEMENT"] { #Subject text required by various US State laws
+ reject text:
+ Hello. The server content filter/spam detector I use has bounced your message. It appears to be spam.
+
+ I do not accept spam/UCE (Unsolicited Commercial Email).
+
+Please ask me how to bypass this filter if your email is not UCE. In that case, I am sorry about this
+highly unusual error. The filter is >99% accurate.
+
+ (This is an automated message; I will not be aware that your message did not get through if I do not hear from you again.)
+
+ -Firstname
+
+ (P.S. You may also override the filter if you accept the terms at http://www.lastname.com/spamoff.htm,
+ by including "lastname.com/spamoff.htm agreed to." in the subject.)
+.
+ ;
+}
+# LINE 30.
+ elsif size :over 10M { # (note that the four leading dots get "stuffed" to three)
+
+ reject text:
+ Message NOT delivered!
+ This system normally accepts email that is less than 10MB in size, because that is how I configured it.
+ You may want to put your file on a server and send me the URL.
+ Or, you may request override permission and/or unreject instructions via another (smaller) email.
+ Sorry for the inconvenience.
+
+ Thanks,
+
+.... Firstname
+ (This is an automated message; I will not be aware that your message did not get through if I do not hear from you again.)
+
+ Unsolicited advertising sent to this E-Mail address is expressly prohibited
+ under USC Title 47, Section 227. Violators are subject to charge of up to
+ $1,500 per incident or treble actual costs, whichever is greater.
+.
+ ;
+#LINE 47.
+} elsif header :contains "From" "Firstname@lastname.com" { #if I send myself email, leave it in the Inbox.
+ keep; #next, is the processing for the various mailing lists I'm on.
+} elsif header :contains ["Sender", "X-Sender", "Mailing-List", "Delivered-To", "List-Post", "Subject", "To", "Cc", "From", "Reply-to", "Received"] "burningman" {
+ fileinto "INBOX.DaBurn";
+} elsif header :contains ["Subject", "From", "Received"] ["E*TRADE", "Datek", "TD Waterhouse", "NetBank"] {
+ fileinto "INBOX.finances.status";
+} elsif header :contains "subject" "\[pacbell" {
+ fileinto "INBOX.pacbell.dslreports";
+} elsif header :contains "From" ["owner-te-wg ", "te-wg ", "iana.org"] {
+ fileinto "INBOX.lst.IETF";
+} elsif header :contains ["Mailing-List", "Subject", "From", "Received"] ["Red Hat", "Double Funk Crunch", "@economist.com", "Open Magazine", "@nytimes.com", "mottimorell", "Harrow Technology Report"] {
+ fileinto "INBOX.lst.interesting";
+} elsif header :contains ["Mailing-List", "Subject", "From", "Received", "X-LinkName"] ["DJDragonfly", "Ebates", "Webmonkey", "DHJ8091@aol.com", "Expedia Fare Tracker", "SoulShine", "Martel and Nabiel", "\[ecc\]"] {
+ fileinto "INBOX.lst.lame";
+} elsif header :contains ["Subject", "From", "To"] ["guru.com", "monster.com", "hotjobs", "dice.com", "linkify.com"] { #job boards and current clients.
+ fileinto "INBOX.lst.jobs";
+} elsif header :contains "subject" "\[yaba" {
+ fileinto "INBOX.rec.yaba";
+} elsif header :contains ["to", "cc"] "scalable@" {
+ fileinto "INBOX.lst.scalable";
+} elsif header :contains ["Sender", "To", "Return-Path", "Received"] "NTBUGTRAQ@listserv.ntbugtraq.com" {
+ fileinto "INBOX.lst.bugtraq";
+} elsif header :contains "subject" "Wired" {
+ fileinto "INBOX.lst.wired";
+#LINE 72.
+} elsif anyof (header :contains "From" ["postmaster", "daemon", "abuse"], header :contains "Subject" ["warning:", "returned mail", "failure notice", "undelivered mail"] ) {
+keep; #this one is important - don't want to miss any bounce messages!
+#LINE 77.
+} elsif anyof (header :contains "From" ["and here I put a whitelist of pretty much all the email addresses in my address book - it's several pages..."]) {
+ fileinto "INBOX.white";
+# better than keep;
+# LINE 106.
+
+
+} elsif anyof (address :all :is ["To", "CC", "BCC"] "Firstname.lastname@fastmail.fm", #a couple people send to this, but I have have all their addrs in whitelist so OK.
+ header :matches "X-Spam-score" ["9.?" , "10.?", "9", "10", "11.?", "12.?" ,"13.?", "14.?", "11", "12","13", "14", "15.?", "16.?", "17.?" ,"18.?", "19.?", "15", "16", "17" ,"18", "19", "2?.?", "2?", "3?.?" , "3?", "40"]) { #"5.?", "6.?", "5", "6" "7.?" , "8.?" , "7", "8"
+ reject text:
+ Hello. The server content filter/spam detector I use has bounced your message. It appears to be spam.
+
+ I do not accept spam/UCE (Unsolicited Commercial Email).
+
+Please ask me how to bypass this filter if your email is not UCE. In that case, I am sorry about this
+highly unusual error. The filter is >99% accurate.
+
+ (This is an automated message; I will not be aware that your message did not get through if I do not hear from you again.)
+
+ -Firstname
+
+ (P.S. You may also override the filter if you accept the terms at http://www.lastname.com/spamoff.htm,
+ by including "lastname.com/spamoff.htm agreed to." in the subject.)
+.
+ ;
+#LINE 127.
+
+} elsif
+header :matches "X-Spam" ["spam", "high"] { if #optimization idea line 1/2
+ header :matches "X-Spam-score" ["5.?", "6.?", "5", "6"] {
+ fileinto "INBOX.Spam.5-7";
+} elsif header :matches "X-Spam-score" ["7.?" , "8.?" , "7", "8"] {
+ fileinto "INBOX.Spam.7-9";
+#} elsif header :matches "X-Spam-score" ["9.?" , "10.?" , "9", "10"] { #These lines obsoleted by reject text rule above, but others will find 'em useful!
+# fileinto "INBOX.Spam.9-11";
+#} elsif header :matches "X-Spam-score" ["11.?" , "12.?" ,"13.?" , "14.?", "11" , "12" ,"13" , "14"] {
+# fileinto "INBOX.Spam.11-15";
+#} elsif header :matches "X-Spam-score" ["15.?" , "16.?" ,"17.?" ,"18.?" , "19.?", "15" , "16" ,"17" ,"18" , "19"] {
+# fileinto "INBOX.Spam.15-20";
+#} elsif header :matches "X-Spam-score" ["2?.?", "2?" ] {
+# fileinto "Inbox.Spam.20-30";
+#} elsif header :matches "X-Spam-score" ["3?.?" , "3?", "40"] {
+#fileinto "Inbox.Spam.30-40";
+ } #optimization idea line 2/2
+
+#LINE 149.
+
+} elsif header:contains ["Content-Type","Subject"] ["ks_c_5601-1987","euc_kr","euc-kr"]{
+ fileinto "Inbox.Spam.kr"; #block Korean; it's prolly spam and I certainly can't read it.
+} elsif header :contains "Received" "yale.edu" {
+ fileinto "INBOX.Yale"; #if it made it past all the filters above, it's probably of interest.
+ } elsif anyof (header :contains "Subject" ["HR 1910", "viagra", "MLM", " "," " ], # common in spam. (prolly redundant to SpamAssassin.)
+ not exists ["From", "Date"], #RFC822 violations common in spam.
+ header :contains ["Sender", "X-Sender", "Mailing-List", "X-Apparently-From", "X-Version", "X-Sender-IP", "Received", "Return-Path", "Delivered-To", "List-Post", "Date", "Subject", "To", "Cc", "From", "Reply-to", "X-AntiAbuse", "Content-Type", "Received", "X-LinkName"] ["btamail.net.cn", "@arabia.com" ] ) { #spam havens.
+ fileinto "INBOX.GreyMail";
+} elsif header :contains ["Precedence", "Priority", "X-Priority", "Mailing-List", "Subject", "From", "Received", "X-LinkName"] ["Bulk", "Newsletter"] {
+ fileinto "INBOX.Bulk Precedence";
+} elsif header :contains ["to", "cc", "Received"] ["IT@lastname.com", "mail.freeservers.com"] {
+ fileinto "INBOX.lastname.IT";
+} elsif header :contains ["To", "CC"] "Firstname@lastname.com" {
+ fileinto "INBOX.lastname.non-BCC";
+}
+#LINE 167.
+#END OF SCRIPT. Implied 'keep' is part of the Sieve spec.
+
+
+
+
+
+
+
diff --git a/pigeonhole/examples/jerry.sieve b/pigeonhole/examples/jerry.sieve
new file mode 100644
index 0000000..ff8a922
--- /dev/null
+++ b/pigeonhole/examples/jerry.sieve
@@ -0,0 +1,224 @@
+# Example Sieve Script
+# Author: Jerry
+# URL: http://www.emaildiscussions.com/showthread.php?postid=145322#post145322
+
+require ["fileinto", "reject", "vacation", "regex", "relational",
+"comparator-i;ascii-numeric"];
+
+
+#### BLACKLIST - BOUNCE ANYTHING THAT MATCHES
+# From individual addresses
+ if header :contains "from"
+ [
+ "username@example.com",
+ "username@example.net"
+ ]
+ { reject "Message bounced by server content filter"; stop; }
+
+# From domains
+ elsif header :contains "from"
+ [
+ "example.com",
+ "example.net"
+ ]
+ { reject "Message bounced by server content filter"; stop; }
+
+
+
+#### BLACKLIST - DELETE ANYTHING THAT MATCHES
+# From individual addresses
+ elsif header :contains "from"
+ [
+ "username@example.com",
+ "username@example.net"
+ ]
+ { discard; stop; }
+
+# From domains
+ elsif header :contains "from"
+ [
+ "example.com",
+ "example.net"
+ ]
+ { discard; stop; }
+
+# I just added the following section after the joe-job
+# that we all suffered at the hands of "inbox.com".
+# The "myusername" is MY username at FastMail.
+# DISCARDing this mail instead of directing it to a
+# SPAM folder kept me from going over quota repeatedly.
+
+# To individual addresses
+ elsif header :contains "to"
+ [
+ "myusername@inbox.com",
+ "myusername@example.net"
+ ]
+ { discard; stop; }
+
+ elsif allof
+ (
+ not anyof
+ (
+#### WHITELIST - KEEP ANYTHING THAT MATCHES
+# From individual addresses
+ header :contains "from"
+ [
+ "username@example.com",
+ "username@example.net"
+ ],
+
+# From trusted domains
+ header :contains "from"
+ [
+ "example.com",
+ "example.net"
+ ],
+
+# Specific "to" address (mailing lists etc)
+ header :contains ["to", "cc"]
+ [
+ "username@example.com",
+ "username@example.net"
+ ],
+
+# Specific "subject" keywords
+ header :contains "subject"
+ [
+ "code_word_for_friend_#1",
+ "code_word_for_friend_#2"
+ ]
+
+ ),
+ anyof
+ (
+
+# Filter by keywords in subject or from headers
+ header :contains ["subject", "from"]
+ [
+ "adilt", "adult", "advertise", "affordable",
+ "as seen on tv", "antenna", "alarm",
+ "background check", "bankrupt", "bargain",
+ "best price", "bikini", "boost reliability",
+ "brand new", "breast", "business directory",
+ "business opportunity", "based business", "best
+ deal", "bachelor's", "benefits", "cable",
+ "career", "casino", "celeb", "cheapest", "child
+ support", "cd-r", "catalog", "classified ad",
+ "click here", "coed", "classmate", "commerce",
+ "congratulations", "credit", "cruise", "cds",
+ "complimentary", "columbia house", "crushlink",
+ "debt", "detective", "diploma", "directv",
+ "directtv", "dish", "dream vacation", "deluxe",
+ "drug", "dvds", "dvd movie", "doubleclick",
+ "digital tv", "erotic", "exciting new",
+ "equalamail", "fantastic business", "fat
+ burning", "financial independence", "finalist",
+ "for life", "financing", "fitness", "fixed
+ rate", "four reports", "free!", "free
+ business", "from home", "funds", "fbi know",
+ "fortune", "gambl", "getaway", "girls", "great
+ price", "guaranteed", "get big", "get large",
+ "giveaway", "hard core", "hardcore", "home
+ document imaging", "home employment directory",
+ "homeowner", "home owner", "homeworker", "home
+ security", "home video", "immediate release",
+ "information you requested", "income",
+ "inkjet", "insurance", "interest rate",
+ "invest", "internet connection", "join price",
+ "judicial judgment", "just released", "know
+ your rights", "legal", "license", "loan", "long
+ distance", "look great", "low interest",
+ "low-interest", "low rate", "lust", "lbs",
+ "make money", "market", "master card",
+ "mastercard", "meg web", "merchant account",
+ "millionaire", "mini-vacation", "mortgage",
+ "master's", "magazine", "nasty", "new car",
+ "nigeria", "nude", "nympho", "naked",
+ "obligation", "online business", "opportunity",
+ "pager", "paying too much", "pda", "penis",
+ "pennies", "pills", "porn", "pounds",
+ "pre-approved", "prescri", "prscri", "prize",
+ "prostate", "printer ink", "quote", "refinanc",
+ "remove fat", "removing fat", "reward",
+ "sales", "satellite", "saw your site",
+ "scrambler", "sex", "smoking", "snoring", "some
+ people succeed", "special invitation", "special
+ offer", "stock", "saving", "singles", "teen",
+ "ticket", "tired of", "truth about anyone",
+ "the best", "ucking", "unbelievable",
+ "uncensored", "uncollected", "unlimited", "USA
+ domains", "urgent", "valium", "viagra",
+ "venture capital", "virgin", "visa", "vitamin",
+ "waist", "wealth", "webcam", "weight", "win a",
+ "winner", "win one", "work smarter", "work at
+ home", "xxx", "younger", "your web site", "your
+ money", "your date is wait",
+ "!!!", "$", "%", "10K"
+ ],
+
+# Filter when the subject is all uppercase (no lowercase)
+ header :regex :comparator
+ "i;octet" "subject" "^[^[:lower:]]+$",
+
+# Filter using regular expressions on the subject
+ header :regex "subject"
+ [
+ "start.+business", "live.+auction",
+ "discover.+card", "pay.+college", "apr$",
+ "apr[^[:alnum:]]", "adv[^[:alnum:]]",
+ "free.+(coupon|info|install|money)",
+ "free.+(phone|sample|test|trial)",
+ "(buy|sell).+(house|home)"
+ ],
+
+# Filter with tracker codes in the subject
+ header :regex "subject"
+ "[[:space:].\-_]{4}#?\[?[[:alnum:]-]+\]?$",
+
+# Filter spam with no to/from address set
+ not exists ["To", "From"],
+
+# Filter spam not addressed to me
+# Put here all of your own addresses (and alias) that you expect
+# mail addressed to. I found a lot of my spam didn't have my
+# name in the TO or CC fields at all -- it must have been in the
+# BCC (which doesn't show in the headers). I can still get BCC
+# mail from legitimate sources because everyone in my address
+# book is on the WHITELIST above.
+
+ not header :contains ["to", "cc"]
+ [
+ "myusername@example.com",
+ "myusername@example.net"
+ ]
+
+ )
+ )
+ { fileinto "INBOX.1_spam"; }
+
+
+
+#### Virus Filter
+ elsif header :contains ["subject", "from"]
+ [
+ "infected file rejected",
+ "infected file rejected"
+ ]
+ { fileinto "INBOX.1_virus"; }
+
+
+#### Telephone Alerts
+# Any message that gets this far should not be spam,
+# and a copy gets sent to my cell-phone as a TEXT message.
+
+ elsif header :contains ["to", "cc"]
+ [
+ "myusername@example.com",
+ "myaliasname@example.com"
+ ]
+ { redirect "2135551234@mobile.example.net"; keep; }
+
+
+
+# END OF SCRIPT
diff --git a/pigeonhole/examples/mjohnson.sieve b/pigeonhole/examples/mjohnson.sieve
new file mode 100644
index 0000000..802ecd8
--- /dev/null
+++ b/pigeonhole/examples/mjohnson.sieve
@@ -0,0 +1,421 @@
+# Example Sieve Script
+# Author: Matthew Johnson
+# URL: http://wiki.fastmail.fm/index.php?title=MatthewJohnson
+
+##########################################################################
+####### SIEVE SCRIPT by Matthew Johnson - MRJ Solutions, Inc. ###########
+####### Email me at mailto:mattjohnson2005@gmail.com ##
+####### Code Version: 12JUN2004 ###########
+##########################################################################
+require ["envelope", "fileinto", "reject", "vacation", "regex", "relational",
+ "comparator-i;ascii-numeric"];
+#
+# todo:
+# change to a nested format with
+# allof()s and nots.
+# add "in address book" check. ex:"header :is :comparator "i;octet" "X-Spam-Known-Sender" "yes""
+# finish reformating lines to <= 75 col (for web edit box)
+# and delete rulers.
+# Mine Michael Klose script for ideas.
+# Check out the update to the Sieve pages on the Fastmail Wiki.
+#
+
+#---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+
+require ["envelope", "fileinto", "reject", "vacation", "regex",
+ "relational", "comparator-i;ascii-numeric"];
+
+
+
+# BLACKLIST - Mails to discard, drop on the floor.
+# -high spam values except those delivered to me
+# -Chinese content except for low spam values
+# -virus rejected notifications
+# -known spam addresses
+# -newsletters that refuse my removal requests
+# -twit-list
+# -double twit-list
+# -other
+
+
+#---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+
+if anyof
+ (
+ allof # combo test one - high spam values except for mail to/from me
+ (
+ # spam score is greater or equal to 14
+ header :value "ge" :comparator "i;ascii-numeric"
+ ["X-Spam-score"] ["14"],
+ not header :contains "X-Spam-Score" "-",
+ not header :contains "X-Spam-Score" "0.0",
+ not header :contains ["to","from","cc","bcc","received"]
+ [
+ # do not discard email to me, will file or discard
+ # as spam later if needed
+ "matt@zeta.net",
+ "matthew@bigsc.com",
+ "matthew_johnson@bigsmallcompany.com",
+ "mmm@spend.com",
+ "finger@spend.com",
+ "myyaacct@yahoo.com"
+ ]
+ ), # end allof
+ allof #combo test two - chinese content except for low spam values
+ (
+ anyof
+ (
+ header :regex "Subject" "^=\\?(gb|GB)2312\\?", # Chinese ecoding at subject
+ header :regex "Subject" "^=\\?big5\\?", # Other kind of Chinese mail
+
+ # Chinese content type
+ header :contains "Content-Type"
+ [
+ "GB2312",
+ "big5"
+ ]
+ ), #end anyof
+ not anyof
+ (
+ #We have to check the sign and the value separately: ascii-numeric, defined at
+ #header :contains "X-Spam-Score" "-",
+ header :value "lt" :comparator "i;ascii-numeric" "X-Spam-Score" "3"
+ ) #end not anyof
+ ), # end allof - test two
+
+ # single tests
+
+ # discard fastmail virus notifications
+ header :is ["subject"] ["Infected file rejected"],
+
+ # black list, invalid addresses receiving a large amount of spam
+ # or spam bounces,rejected zeta.net accounts.
+ header :contains ["X-Delivered-to"]
+
+ ["eagleeye@zeta.net","ealgeeye@zeta.net",
+ "alica.thiele@zeta.net", "2005@theta.com",
+ "jimlovingu2@zeta.net",
+ "alpha@zeta.net",
+ "JoshuaS@zeta.net",
+ "donnaf@zeta.net",
+ "pspinks@zeta.net",
+ "jsherman@zeta.net",
+ "holly@zeta.net",
+ "clabarca@zeta.net",
+ "meghanr@zeta.net",
+ "rtaylor@zeta.net",
+ "lboone@zeta.net",
+ "brower@zeta.net",
+ "jenj@zeta.net",
+ "cbackus@zeta.net",
+ "spengles@zeta.net",
+ "adams@zeta.net",
+ "dsmith@zeta.net",
+ "jwilderman@zeta.net",
+ "TimF@zeta.net",
+ "zd@zeta.net",
+ "louise@zeta.net"]
+
+ # single 'not' tests
+ # ---out for testing--- not header :is :comparator "i;octet" "X-Spam-Known-Sender" "yes"
+ ) # end anyof()
+{
+ discard;
+ stop;
+}
+
+
+#
+# WHITELIST - Keep these mails and put them in the inbox
+# (some kept getting put in Junk Mail)
+# Family, Friends, Current Vendors, Customers
+# Contents of fastmail address book.
+#
+#---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+
+if anyof ( header :contains ["from","to","cc","bcc"]
+ [ "notification@eBay.com",
+ "MAILER-DAEMON@zeta.net",
+ "USPS_Track_Confirm@usps.com",
+ "credit.services@target.com",
+ "Comcast_Paydirect@comcast.net",
+ "mary@zeta.net",
+ "betty@zeta.net",
+ "andmanymore@zeta.net"
+ ],
+ header :is :comparator "i;octet" "X-Spam-Known-Sender" "yes"
+ )
+{
+ fileinto "INBOX";
+ stop;
+}
+
+# redirects
+if header :contains ["to", "cc"] "mary1@zeta.net"
+ {
+ redirect "mary@zeta.net";
+ stop;
+ }
+
+
+#
+# +Spam filtering by score on 3, 5 and 14(above).
+#
+#
+if header :value "ge" :comparator "i;ascii-numeric" ["X-Spam-score"] ["5"] {
+ fileinto "INBOX.Junk Mail.ge5";
+ stop;
+#---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+
+} elsif header :value "ge" :comparator "i;ascii-numeric" ["X-Spam-score"] ["3"] {
+ fileinto "INBOX.Junk Mail.ge3";
+ stop;
+}
+
+
+# Potential Blacklist, start with soft discard, then migrate to full discard above
+#
+# Blacklist (2nd) During testing, throw into "Junk Mail.discard" until
+# ready to discard.
+#
+if anyof
+ (
+ # rejects for accounts across all domains
+ header :contains ["X-Delivered-to"]
+ [
+ "drjoe@","VX@",
+ "alfa@zeta.net",
+ "media@zeta.net",
+ "zeta@zeta.net",
+ "xyz@zeta.net"
+ ],
+
+ # other criteria - weird message from this account
+ header :contains ["from"] ["Charlie Root"],
+ # mailers that are always sending spam returns to me
+ header :contains ["from"] ["MAILER-DAEMON@aol.com"] ,
+ header :contains ["from"] ["MAILER-DAEMON@otenet.gr"] ,
+
+ # common account names that I don't use in any of my domains and that spammers like
+ header :contains ["X-Delivered-to"]
+ [ "biz@","sales@","support@", "service@", "reg@",
+ "registration@", "regisration@", "root@", "webmaster@", "noreply@"
+ ],
+ # zeta.net common account names to reject
+ header :contains ["X-Delivered-to"] ["info@zeta.net"],
+ # bigsc.com rejects
+ header :contains ["X-Delivered-to"] ["info@bigsc.com"],
+ # theta.com rejects
+ header :contains ["X-Delivered-to"] ["info@theta.com"],
+ header :contains ["X-Delivered-to"] ["reg@theta.com"]
+#---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+
+ # saves for use maybe later
+ # header :contains ["X-Delivered-to"] ["webmaster@zeta.net"],
+ # header :contains ["X-Delivered-to"] ["webmaster@theta.com"],
+ # header :contains ["X-Delivered-to"] ["sales@bs.com"],
+ # header :contains ["X-Delivered-to"] ["sales@theta.com"],
+ # header :contains ["X-Delivered-to"] ["sales@bigsc.com"],
+ # header :contains ["X-Delivered-to"] "root@zeta.net",
+
+ ) #end anyof() 2nd blacklist
+{
+
+ fileinto "INBOX.Junk Mail.discard";
+ stop;
+}
+
+
+# +Greylist, move to "INBOX.Junk Mail.greylist"
+#
+# 'Soft' Blacklist ?Greylist?
+#
+
+#annoying person(s) that send questionable attachments
+# look at occationally
+if header :contains "from" "alex@yahoo.com"
+{
+ fileinto "INBOX.Junk Mail.greylist";
+} elsif header :contains "subject" "MAILER-DAEMON@fastmail.fm"
+ # non-person, but might
+ # want to look at it while
+ # figuring issues
+{
+ fileinto "INBOX.Junk Mail.greylist";
+ stop;
+}
+
+# +Spammy domains to filter
+#
+# domains that are known to be present in spam
+#
+if header :contains ["from", "received"] [".ru",".jp", ".kr", ".pt",
+ ".pl",".at",".cz",".cn",".lu" ]
+{
+ fileinto "INBOX.Junk Mail.discard";
+ stop;
+}
+
+
+#
+# Annoying newsletters that won't unsubscribe me, reject
+#
+
+if anyof (
+ #annoying newsletters
+ header :contains ["from"] "VistaPrintNews", # 2003
+ header :contains ["from"] "newsletter@briantracyintl.com", # 2003
+ header :contains ["from"] "info@yogalist.com", # 2003
+ header :contains ["from"] "The Angela Larson Real Estate Team",
+ header :contains ["from"] "Brian Tracy"
+ )
+#---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+
+{
+ reject "I HAVE TRIED TO UNSUBSCRIBE; I DO NOT WANT YOUR NEWSLETTER; PLEASE UNSUBSCRIBE ME";
+ stop;
+}
+
+
+
+
+#
+# Suspected zeta.net user from/to Zeta Institute, NY - reject
+#
+#
+#
+if header :contains ["X-Delivered-to","from"]
+ [
+ # aaaaNEW_ENTRIES_ABOVE ###################################
+ "neville@zeta.net",
+ "animika@zeta.net",
+ "linda@zeta.net",
+ "jerry@zeta.net",
+ "adamS@zeta.net",
+ "lkdamon@zeta.net",
+ "AdamS@zeta.net",
+ "DConnor@zeta.net",
+ "LOUISR@zeta.net",
+
+ # Start of Alpha #############################################
+ "Allanv@zeta.net",
+ "AmberJ@zeta.net",
+ "DANDERSON@zeta.net",
+ "Jonas@zeta.net",
+ "KarenE@zeta.net",
+ "J.R.C.@zeta.net", # check to see if this is working
+ "PMackey@zeta.net",
+
+ "adrienne@zeta.net","alpha@zeta.net","amina@zeta.net",
+ "anamika@zeta.net",
+ "claborca@zeta.net","communications@zeta.net",
+ "cz241@zeta.net",
+ "dee@zeta.net",
+ "ellenb@zeta.net","evis@zeta.net",
+ "frivera@zeta.net",
+ "gblack@zeta.net","gbrown@zeta.net","george@zeta.net","grace@zeta.net",
+ "happygolucky@zeta.net","hsp@zeta.net",
+ "ila@zeta.net",
+ "jacqueline_fenatifa@zeta.net","jlengler@zeta.net",
+ "joel@zeta.net","jolsen@zeta.net", "jsherman@zeta.net",
+ "kronjeklandish@zeta.net","kwilcox@zeta.net","bettyb@zeta.net",
+ "laurie@zeta.net","llmansell@zeta.net",
+ "louise@zeta.net","lzollo@zeta.net",
+ "mcraft@zeta.net","meganB@zeta.net","mwezi@zeta.net",
+ "nanwile@zeta.net",
+ "zetasound@zeta.net",
+ "peter@zeta.net",
+ "randi@zeta.net", "rcbackus@zeta.net", "registration@zeta.net",
+ "registration@omgea.org",
+ "rtaylor@zeta.net",
+ "sdonnarumma@zeta.net","stephanR@zeta.net","suzanne@zeta.net","suzzane@zeta.net",
+ "taryngaughan_dn@zeta.net"
+ # zzzzEND_OF_LIST####
+ ] #end of Xdelivered-to list for possible zeta institute users
+
+{
+ reject text:
+ ERROR: Your email has not been delivered.
+
+ You have reached the mailer at zeta.net
+
+ Perhaps you want to send to Zeta Institute in DillyDally, NY, USA?
+
+ Use USER@zeta.net for them
+
+ or try registration@zeta.net
+ Check the website at http://www.zeta.net/zeta/contact/
+ Call Registration at 1 800 944 1001.
+
+ or use this information:
+
+ Zeta Institute
+ 150 River Drive
+ DillyDally, NY 12666
+ Registration: 800-900-0000
+ Ph: 845-200-0000
+ Fax: 845-200-0001
+ registration@zeta.net
+
+ sincerely, POSTMASTER
+.
+;
+ fileinto "Inbox.Junk Mail.ezeta";
+ stop;
+ }
+#---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+
+# +Move messages into folders
+#
+# Process other messages into separate folders
+#
+ # newsletters and mail lists
+if header :contains ["subject"]
+ [ "newsletter", "[tc-ieee-", "[icntc",
+ "JUG News", "Xdesksoftware",
+ "announcement" ]
+{
+ fileinto "INBOX.Newsletters";
+} elsif header :contains ["from","subject"] ["Anthony Robbins"] {
+ fileinto "INBOX.Newsletters";
+} elsif header :contains ["from","subject"] ["MN Entrepreneurs","ME!"] {
+ fileinto "INBOX.Newsletters";
+} elsif header :contains ["from","received"] "adc.apple.com" {
+ fileinto "INBOX.Newsletters";
+} elsif header :contains "from" "wnewadmn@ieee.org" {
+ fileinto "INBOX.Newsletters";
+} elsif header :contains "from" "@lb.bcentral.com" { # techworthy@lb.bcentral.com
+ fileinto "INBOX.Newsletters";
+} elsif header :contains "from" "announcement@netbriefings.com" { #st paul company
+ fileinto "INBOX.Newsletters";
+} elsif header :contains "from" "newsletter@eletters.extremetech.com" { #semi-annoying rag
+ fileinto "INBOX.Newsletters";
+#---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+
+# my newsletter throw-away addresses
+} elsif header :contains "to" ["microcenter@zeta.net","nmha@zeta.net"] {
+ fileinto "INBOX.Newsletters";
+
+#---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+
+#
+# Alerts mailbox
+} elsif header :contains ["subject", "from"]
+ [
+ "Alert", # F-Prot virus alert service, matches:
+ # "FRISK Virus Alert"
+ # or use s:FRISK Virus Alert:
+ # or use f:support@f-prot.com
+ "Payment", # Alerts from other payments
+ "credit.services@target.com", # Target Card Payments
+ "notify@quickbase.com" # Tic Talkers Database changes
+ ]
+{
+ fileinto "INBOX.Alerts";
+ stop;
+}
+
+# +Announcements from Dave Rolm, forward
+#
+# Perl Announcements from Dave Rolm
+if header :contains "from" "dave@other.org"
+{
+ fileinto "Inbox";
+ keep;
+}
+#---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+
+#######################################################################
+#### END OF SIEVE SCRIPT by Matthew Johnson - MRJ Solutions, Inc. #####
+################ email me at mailto:mattjohnson2005@gmail.com #
+
diff --git a/pigeonhole/examples/mklose.sieve b/pigeonhole/examples/mklose.sieve
new file mode 100644
index 0000000..598cffb
--- /dev/null
+++ b/pigeonhole/examples/mklose.sieve
@@ -0,0 +1,303 @@
+# Example Sieve Script
+# Author: Michael Klose
+# URL: http://wiki.fastmail.fm/index.php?title=MichaelKloseSieveScript
+
+require ["fileinto", "reject", "vacation", "regex", "relational", "comparator-i;ascii-numeric"];
+
+# Experimental
+
+# End experimental
+
+
+
+# ----------------------------------------------
+# Discard messages (high Spam values)
+# ----------------------------------------------
+
+if anyof
+ (
+ allof
+ (
+ #Spam score > 17?
+ #We have to check the sign and the value separately: ascii-numeric, defined at http://www.ietf.org/rfc/rfc2244.txt, doesn't see minus signs or decimal points ("-" or ".").
+ header :value "ge" :comparator "i;ascii-numeric" "X-Spam-Score" "17",
+ not header :contains "X-Spam-Score" "-",
+
+ not header :contains ["to","cc"]
+ [
+ "@my-domain.de",
+ "myemail@myotherdomain.us",
+ "myotheremail@myotherdomain.us",
+ "myotheremail2@myotherdomain.us"
+ # Do not discard stuff going to me - gets filed into Junk later
+ ],
+ not header :contains "from"
+ [
+ "lockergnome.com",
+ "Excite@info.excite.com" # gets filed into Junk later
+ ]
+
+
+ ),
+ allof
+ (
+ header :contains "X-LinkName" "hotmail", # OR anything from Hotmail with low spam
+ allof
+ (
+ header :value "ge" :comparator "i;ascii-numeric" "X-Spam-Score" "7",
+ not header :contains "X-Spam-Score" "-"
+ )
+ ),
+
+ # Black List
+
+ header :contains "from"
+ [
+ "ahbbcom@cncorn.com",
+ "Darg. B."
+ ],
+
+ # Chinese Encoding at BEGINNING of Subject
+
+ allof
+ (
+ anyof
+ (
+ header :regex "Subject" "^=\\?(gb|GB)2312\\?", # Chinese ecoding at subject
+ header :regex "Subject" "^=\\?big5\\?", # Other kind of Chinese mail
+
+ # Chinese content type
+
+ header :contains "Content-Type"
+ [
+ "GB2312",
+ "big5"
+ ]
+ ),
+ not anyof
+ (
+ #Spam score > -4? <sic> - ascii-numeric ignores the ".9"!. -Or is this correct?
+ #We have to check the sign and the value separately: ascii-numeric, defined at http://www.ietf.org/rfc/rfc2244.txt, doesn't see minus signs or decimal points ("-" or ".").
+
+ header :contains "X-Spam-Score" "-",
+ header :value "lt" :comparator "i;ascii-numeric" "X-Spam-Score" "4"
+ )
+ )
+ )
+
+{
+
+
+ # discard;
+
+ if header :contains "X-LinkName" "hotmail"
+ { discard; }
+ else
+ { fileinto "INBOX.Junk.Reject"; }
+ # I used to reject this stuff, but I wanted to know what I was rejecting, and this stuck.
+ stop;
+}
+
+
+
+# Addresses that need to be forwarded to a different domain here before spam checking
+# ******************************Michael - I don't understand what you're doing here! -elvey
+# REPLY: this here is actually used to forward stuff addressed to my sister (using my domain)
+# to her - without using one of the own-domain aliases.
+
+if header :contains ["to", "cc"]
+ [
+ "bla@blabla.de",
+ "bla2@blabla.us",
+ "bla3@blabla.us"
+ ]
+ {
+ redirect "otheremailaddress@something.com";
+ redirect "anotheremailadress@something.com";
+ stop;
+ }
+
+
+# File into a folder before Spam filtering
+
+if header :contains ["to","cc"]
+ [
+ "important@mydomain.us",
+ "important2@mydomain.us"
+ ]
+ {
+ fileinto "Inbox.Important";
+ stop;
+ }
+
+
+
+# -------------------------------------------
+# Filing rules
+# -------------------------------------------
+
+
+# Pre-SPAM
+
+
+if size :over 750K
+ {
+ fileinto "INBOX.largemail";
+ stop;
+ }
+
+
+if header :contains "from"
+ [
+
+# White list 1 (with SMS notification)
+
+ "Fred Bloggs",
+ "f.bloggs@hotmail.com",
+ "myboss@somecompany.com",
+ "Trisha",
+ "endofauction@ebay.de" # I want to know about end of auctions
+ ]
+ {
+ fileinto "Inbox";
+
+ # Send an SMS
+ redirect "smsgateway@somegateway.de";
+ keep;
+
+ stop;
+ }
+
+ # Advertising I want to receive, which normally ends up in the SPAM filter
+
+ if anyof
+ (
+ header :contains "from"
+
+ [
+
+# Advertising whitelist
+
+ "Mark Libbert",
+ "newsletter@snapfish.dom"
+ ],
+ header :contains "Return-Path" "mailings@gmx.dom"
+ )
+ { fileinto "INBOX.Ads"; }
+ elsif header :contains "from"
+ [
+ "newsletter@neuseelandhaus.dom",
+ "Lockergnome",
+ "CNET News.com"
+ ]
+ { fileinto "INBOX.Newsletter";
+
+
+
+# Spam protection
+
+
+} elsif anyof
+ (
+
+ #Spam assasin
+ allof
+ (
+ header :value "ge" :comparator "i;ascii-numeric" "X-Spam-Score" "6",
+ not header :contains "X-Spam-Score" "-",
+ not anyof # White list
+ (
+ header :contains "From" # Whitelist From addresses
+ [
+ "CNN Quick News",
+ "FastMail.FM Support",
+ "lockergnome.com"
+ ]
+ )
+ ),
+
+ # User defined
+
+ # Filter out Femalename1234z12@ spam (base64 encoded)
+ allof
+ (
+ header :regex "From" "alpha:{2,}digit:{2,}alpha:+digit:{2,}@",
+ header :contains "Content-Type" "multipart/mixed"
+ ),
+ # Filter our Spam with invalid headers. You can see this because FM adds
+ # @fastmail.fm to them. For safty, check that mklose@ @michael-klose mkmail@gmx do
+ # not appear
+
+ # Mklose: addition: The only negative side effect I have seen of the condition below
+ # is that it catches the FM newsletters. So far I find them in the spam occasionly
+ # but since they are so few, I have never bothered changing this to not catch them.
+
+ allof
+ (
+ header :contains "To" "@fastmail.fm", # I do not have a fastmail address # This doesn't catch BCC's; you should be checking the envelop instead. -elvey
+ not header :contains ["To", "CC", "Reply-To"] ["klose","mkmail@gmx.dom", "chaospower"]
+ )
+ )
+ {
+ fileinto "INBOX.Junk";
+ stop;
+ }
+
+
+# Post Spam-protection
+
+ elsif header :contains ["to", "cc"] "gpc@gnu.dom" {
+ fileinto "INBOX.GPC";
+} elsif header :contains ["to", "cc"] "alfs\-discuss@linuxfromscratch.dom" {
+ fileinto "INBOX.LFS-Support.ALFS";
+} elsif header :contains "subject" "(usagi\-users" {
+ fileinto "INBOX.Usagi";
+} elsif anyof (header :contains "Subject" "\[eplus-de\]", header :contains "Reply-To" "eplus-de") {
+ fileinto "INBOX.E-Plus";
+} elsif header :contains ["to", "cc"] "lfs\-support@linuxfromscratch.dom" {
+ fileinto "INBOX.LFS-Support";
+} elsif header :contains ["to", "cc"] "netdev@oss.sgi.dom" {
+ fileinto "INBOX.NetDev";
+} elsif header :contains ["to", "cc"] "lfs\-dev@linuxfromscratch.dom" {
+ fileinto "INBOX.LFS-DEV";
+} elsif header :contains "from" "GMX Best Price" {
+ fileinto "INBOX.Werbung";
+} elsif header :contains "subject" "RHN Errata Alert" {
+ fileinto "INBOX.Notifications";
+} elsif header :contains "from"
+ [
+ "EmailDiscussions.com Mailer",
+ "help1@dungorm.dom"
+ ] {
+ fileinto "INBOX.Notifications";
+} elsif header :contains "subject" "\[Gaim\-commits\]" {
+ fileinto "INBOX.Notifications";
+} elsif header :contains "subject" "\[Bug" {
+ fileinto "INBOX.Notifications.Bugzilla";
+} elsif header :contains "X-LinkName" "hotmail" {
+ fileinto "INBOX.Old Hotmail.new";
+}
+
+
+# -----------------------------------------------------------------------
+# SMS notifications and forwarding
+# -----------------------------------------------------------------------
+
+if allof
+ (
+ header :contains "to" ["@mydomain1.de","email@mydomain2.us","email2@somedomain"],
+ not header :contains "from"
+ [
+
+# This avoids sending SMS notifications if I am the sender
+
+ "@mydomain1.de",
+ "myotheremail@somedomain.de",
+ "myotheremail@someotherdomain.de"
+ ]
+ )
+ {
+ redirect "smsgateway@somegateway.com";
+ keep;
+ }
+
diff --git a/pigeonhole/examples/relational.rfc5231.sieve b/pigeonhole/examples/relational.rfc5231.sieve
new file mode 100644
index 0000000..81c66d3
--- /dev/null
+++ b/pigeonhole/examples/relational.rfc5231.sieve
@@ -0,0 +1,33 @@
+require ["relational", "comparator-i;ascii-numeric", "fileinto"];
+
+if header :value "lt" :comparator "i;ascii-numeric"
+ ["x-priority"] ["3"]
+{
+ fileinto "Priority";
+}
+
+elsif address :count "gt" :comparator "i;ascii-numeric"
+ ["to"] ["5"]
+{
+ # everything with more than 5 recipients in the "to" field
+ # is considered SPAM
+ fileinto "SPAM";
+}
+
+elsif address :value "gt" :all :comparator "i;ascii-casemap"
+ ["from"] ["M"]
+{
+ fileinto "From N-Z";
+} else {
+ fileinto "From A-M";
+}
+
+if allof (
+ address :count "eq" :comparator "i;ascii-numeric"
+ ["to", "cc"] ["1"] ,
+ address :all :comparator "i;ascii-casemap"
+ ["to", "cc"] ["me@foo.example.com"] )
+{
+ fileinto "Only me";
+}
+
diff --git a/pigeonhole/examples/rfc3028.sieve b/pigeonhole/examples/rfc3028.sieve
new file mode 100644
index 0000000..e8f6972
--- /dev/null
+++ b/pigeonhole/examples/rfc3028.sieve
@@ -0,0 +1,58 @@
+#
+# Example Sieve Filter
+# Declare any optional features or extension used by the script
+#
+require ["fileinto", "reject"];
+
+#
+# Reject any large messages (note that the four leading dots get
+# "stuffed" to three)
+#
+if size :over 1M
+ {
+ reject text:
+Please do not send me large attachments.
+Put your file on a server and send me the URL.
+Thank you.
+.... Fred
+.
+;
+ stop;
+ }
+#
+
+# Handle messages from known mailing lists
+# Move messages from IETF filter discussion list to filter folder
+#
+if header :is "Sender" "owner-ietf-mta-filters@imc.org"
+ {
+ fileinto "filter"; # move to "filter" folder
+ }
+#
+# Keep all messages to or from people in my company
+#
+elsif address :domain :is ["From", "To"] "example.com"
+ {
+ keep; # keep in "In" folder
+ }
+
+#
+# Try and catch unsolicited email. If a message is not to me,
+# or it contains a subject known to be spam, file it away.
+#
+elsif anyof (not address :all :contains
+ ["To", "Cc", "Bcc"] "me@example.com",
+ header :matches "subject"
+ ["*make*money*fast*", "*university*dipl*mas*"])
+ {
+ # If message header does not contain my address,
+ # it's from a list.
+ fileinto "spam"; # move to "spam" folder
+ }
+ else
+ {
+ # Move all other (non-company) mail to "personal"
+ # folder.
+ fileinto "personal";
+ }
+
diff --git a/pigeonhole/examples/sanjay.sieve b/pigeonhole/examples/sanjay.sieve
new file mode 100644
index 0000000..1a4d622
--- /dev/null
+++ b/pigeonhole/examples/sanjay.sieve
@@ -0,0 +1,171 @@
+# Example Sieve Script
+# Author: SanjaySheth
+# URL: http://wiki.fastmail.fm/index.php?title=SanjaySieveSpamFilter
+
+require "fileinto";
+
+if anyof (
+
+ # Blacklisted sender domains
+ header :contains ["from", "Received", "X-Sender", "Sender",
+ "To","CC","Subject","X-Mail-from"]
+ [ "123greetings", "allfreewebsite.com",
+ "new-fields.com","atlasrewards","azogle.com",
+ "bannerport.net","bettingextreme.com","bigemailoffers.com",
+ "BlingMail.com",
+ "beyondoffers.net", ".biz ", ".biz]",
+ "cavalrymail.com","ciol.com","citywire.co.uk",
+ "cosmicclick.com",
+ "consumergamblingreport","creativemailoffers.com","creativeoffers.com",
+ "daily-promotions.com",
+ "dailypromo.","dailypromotions.",
+ "dandyoffers","dlbdirect",
+ "e54.org", "email-specials.net","email-ware.com","emailoffersondemand",
+ "emailbargain.com","emailofferz","emailrewardz","etoll.net","emailvalues.com",
+ "evaluemarketing.com","exitrequest.com",
+ "fantastic-bargain.com","fpsamplesmail.com","freelotto",
+ "findtv.com", "freddysfabulousfinds.com",
+ "genuinerewards.com",
+ "hotdailydeal.com","hulamediamail","hy-e.net",
+ "inboxbargains.com","idealemail.com",
+ "jackpot.com","jpmailer.com",
+ "lolita","lund.com.br",
+ "mafgroup.com","mailasia.com","mailtonic.net","migada.com","ms83.com",
+ "nationaloffers.com","nexdeals.com ",
+ "offercatch.com","offermagnet.com","offerservice.net","offertime.com",
+ "offersdaily.net","optnetwork.net",
+ "ombramarketing.com","on-line-offers.com","outblaze.com",
+ "permissionpass","primetimedirect.net","productsontheweb.net",
+ "rapid-e.net","recessionspecials", "redmoss","remit2india",
+ "sampleoffers.com","savingsmansion.com","sendoutmail.com","simpleoffers.com",
+ "specialdailydeals4u.com","Select-Point.net",
+ "speedyvalues.com","sportsoffers","sporttime.info","suntekglobal.com",
+ "superstorespecials.com", "synapseconnect","sunsetterawnings.com",
+ "thefreesamplenews","truemail.net",
+ "ub-kool","ultimatesports.info","uniquemailoffers","utopiad.com",
+ "unixlovers.net",
+ "valuesdirect","virtualoffers.net",
+ "wagerzine", "webdpoffrz",
+ "yestshirt.com",
+ "z-offer.com", "zipido.com"
+ ],
+
+ # Blacklisted ip subnets due to excessive spam from them
+ header :contains "Received"
+ [ "[4.63.221.224",
+ "[24.244.141.112",
+ "[61.171.253.177",
+ "[63.123.149.", "[63.209.206.", "(63.233.30.73", "[63.251.200.",
+ "[64.41.183.","[64.49.250.", "[64.57.188.", "[64.57.221.",
+ "[64.62.204.",
+ "[64.70.17.", "[64.70.44.", "[64.70.53.",
+ "[64.39.27.6", "[64.39.27.7","[64.191.25.","[64.191.36.",
+ "[64.191.9.",
+ "[64.125.181.", "[64.191.123.", "[64.191.23.", "[64.239.182.",
+ "[65.211.3.",
+ "[66.46.150.", "[66.62.162.", "[66.118.170.", "[66.129.124.",
+ "[66.205.217.", "[66.216.111.", "[66.239.204.",
+ "[67.86.69.",
+ "[80.34.206.", "[80.80.98.",
+ "[81.72.233.13",
+ "[128.242.120.",
+ "[157.238.18",
+ "[168.234.195.18]",
+ "[193.253.198.57",
+ "[194.25.83.1",
+ "[200.24.129.", "[200.161.203.",
+ "[202.164.182.76]","[202.57.69.116",
+ "[203.19.220.","[203.22.104.","[203.22.105.",
+ "[204.188.52.",
+ "[205.153.154.203",
+ "[206.26.195.", "[206.154.33.","[206.169.178",
+ "[207.142.3.",
+ "[208.46.5.","[208.187.",
+ "[209.164.27.","[209.236.",
+ "[210.90.75.129]",
+ "[211.101.138.199","[211.185.7.125]","[211.239.231.",
+ "[212.240.95.",
+ "[213.47.250.139", "[213.225.61.",
+ "[216.22.79.","[216.39.115.","[216.99.240.",
+ "[216.126.32.", "[216.187.123.","[217.36.124.53",
+ "[218.145.25","[218.52.71.103","[218.158.136.115",
+ "[218.160.42.74", "[218.242.112.4]"
+ ],
+
+ # Blacklisted SpamAssassin flags
+ header :contains ["SPAM", "X-Spam-hits"]
+ ["ADDRESSES_ON_CD","ACT_NOW","ADULT_SITE", "ALL_CAP_PORN",
+ "AMATEUR_PORN", "AS_SEEN_ON",
+ "BAD_CREDIT", "BALANCE_FOR_LONG_20K", "BARELY_LEGAL", "BEEN_TURNED_DOWN",
+ "BANG_GUARANTEE", "BANG_MONEY","BASE64_ENC_TEXT",
+ "BAYES_99","BAYES_90",
+ "BE_BOSS", "BEST_PORN", "BULK_EMAIL",
+ "CASINO", "CONSOLIDATE_DEBT", "COPY_ACCURATELY", "COPY_DVD",
+ "DIET", "DO_IT_TODAY","DOMAIN_4U2",
+ "EMAIL_MARKETING","EMAIL_ROT13", "EXPECT_TO_EARN","EARN_MONEY",
+ "FIND_ANYTHING", "FORGED_AOL_RCVD",
+ "FORGED_HOTMAIL_RCVD", "FORGED_YAHOO_RCVD",
+ "FORGED_RCVD_TRAIL", "FORGED_JUNO_RCVD",
+ "FORGED_MUA_",
+ "FREE_MONEY","FREE_PORN",
+ "GENTLE_FEROCITY", "GET_PAID", "GUARANTEED_STUFF", "GUARANTEED_100_PERCENT",
+ "HAIR_LOSS", "HIDDEN_ASSETS", "HGH,", "HOME_EMPLOYMENT","HOT_NASTY","HTTP_ESCAPED_HOST",
+ "HTTP_USERNAME_USED","HTML_FONT_INVISIBLE",
+ "IMPOTENCE","INVALID_MSGID","INVESTMENT",
+ "LESBIAN","LIVE_PORN","LOSE_POUNDS",
+ "MARKETING_PARTNERS", "MORTGAGE_OBFU", "MORTGAGE_RATES",
+ "NIGERIAN_SCAM", "NIGERIAN_TRANSACTION_1", "NIGERIAN_BODY", "NUMERIC_HTTP_ADDR",
+ "NO_MX_FOR_FROM","NO_DNS_FOR_FROM",
+ "OBFUSCATING_COMMENT", "ONLINE_PHARMACY",
+ "PENIS_ENLARGE",
+ "PREST_NON_ACCREDITED", "PURE_PROFIT","PORN_4",
+ "RCVD_IN_DSBL", "RCVD_IN_OSIRUSOFT_COM","RCVD_IN_BL_SPAMCOP_NET", "RCVD_IN_SBL",
+ "RCVD_IN_MULTIHOP_DSBL", "RCVD_IN_RELAYS_ORDB_ORG", "RCVD_IN_UNCONFIRMED_DSBL",
+ "RCVD_FAKE_HELO_DOTCOM", "RCVD_IN_RFCI", "RCVD_IN_NJABL","RCVD_IN_SORBS",
+ "REFINANCE", "REVERSE_AGING",
+ "SAVE_ON_INSURANCE","SPAM_REDIRECTOR", "STOCK_ALERT", "STOCK_PICK", "STRONG_BUY",
+ "SEE_FOR_YOURSELF", "SUPPLIES_LIMITED",
+ "THE_BEST_RATE","TONER",
+ "UNSECURED_CREDIT",
+ "VACATION_SCAM", "VIAGRA", "VJESTIKA",
+ "WHILE_SUPPLIES", "WORK_AT_HOME",
+ "X_OSIRU_DUL", "X_OSIRU_SPAMWARE_SITE", "X_OSIRU_SPAM_SRC"
+ ],
+
+
+ # Blacklisted subjects
+
+ header :contains ["From","Subject"]
+ [" penis ",
+ "ADV:", "adult dvd", "adult movie", "adultdirect", "adultemail",
+ "background check", "bankrupt", "boobs", "business opportunity","big@boss.com",
+ "casino", "cash guarantee",
+ "debt free", "diet bread", "ebay secrets", "erection",
+ "financial freedom", "free credit",
+ "gambl", "gov grants", "jackpot",
+ "life insurance", "lottery", "lotto",
+ "mortgage", "nude", "OTCBB",
+ "penis", "porn", "promotion", "proven System",
+ " rape ",
+ " sex ", "skin resurfacing", "special offer",
+ "ultimate software", "viagra", "V1AGRA", "vivatrim",
+ "win money","work from home", "xxx"
+ ],
+
+ # often spam emails to multiple addresses with same name & different domain
+ header :matches ["To","CC"]
+ ["*fastmail*fastmail*fastmail*fastmail*fastmail*"],
+
+ # Almost all emails from these domains is spam (at least for me)
+ header :contains ["from", "received"]
+ [".ru ",".jp ", ".kr ", ".pt ",".pl ",".at ",".cz ",
+ ".ru>",".jp>", ".kr>", ".pt>", ".pl>",".at>",".cz>"],
+
+ # Really high SpamAssassin scores (15.0+)
+ header :matches ["X-Spam-score","X-Remote-Spam-score"] [
+ "1?.?", "2?.?", "3?.?", "4?.?", "5?.?", "6?.?" # 10.0 to 69.9
+ ]
+) {
+ fileinto "INBOX.Spam.discard";
+ stop;
+}
diff --git a/pigeonhole/examples/sieve_examples.sieve b/pigeonhole/examples/sieve_examples.sieve
new file mode 100644
index 0000000..6e7ca17
--- /dev/null
+++ b/pigeonhole/examples/sieve_examples.sieve
@@ -0,0 +1,73 @@
+# Example Sieve Script
+# Author: unknown
+# URL: http://wiki.fastmail.fm/index.php?title=MoreSieveExamples
+
+require ["fileinto", "reject"];
+
+###BYPASSES###
+
+if anyof (
+ header :contains ["From"] "friend1",
+ header :contains ["From"] "friend12",
+ header :contains ["From"] "friend3",
+ header :contains ["From"] "friendsdomanin",
+ header :contains ["Subject"] "elephant" ##a safeword
+ )
+ {
+ fileinto "INBOX";
+ stop;
+ }
+
+###BIG MESSAGE PROTECTION
+if size :over 5000K {
+ reject "Message over 5MB size limit. Please contact me before sending this.";
+}
+
+##SPAM FILTERING##
+if header :contains ["X-Spam"] "high" {
+ discard;
+ stop;
+}
+if header :contains ["X-Spam-Flag"] "HIGH" {
+ discard;
+ stop;
+}
+if header :contains ["X-Spam"] "spam" {
+ fileinto "INBOX.spam"; #emails forwarded from my unviersity account get SA tagged like this
+ stop;
+}
+if header :contains ["X-Spam-Flag"] "YES" {
+ fileinto "INBOX.spam";
+ stop;
+}
+
+####LOCAL SPAM RULES#######
+if header :contains ["From"] "bannerport" { discard; stop; } ##keyword filters for when SA doesn't quite catch them
+if header :contains ["To"] "MATT NOONE" { discard; stop; }
+###AUTO management rules###
+
+####Student Digest stuff#### ### Examples of boolean OR rules
+if anyof (
+ header :contains ["X-BeenThere"] "student-digest@list.xxx.edu",
+ header :contains ["X-BeenThere"] "firstyear-digest@list.xxx.edu",
+ header :contains ["X-BeenThere"] "secondyear-digest@list.xxx.edu",
+ header :contains ["X-BeenThere"] "thirdyear-digest@list.xxx.edu",
+ header :contains ["X-BeenThere"] "fourthyear-digest@list.xxx.edu"
+ )
+ {
+ fileinto "INBOX.lists.digests";
+ stop;
+ }
+if allof ( ###A Boolean AND rule
+ header :contains ["From"] "buddy1",
+ header :contains ["To"] "myotheraddress"
+ )
+ {
+ fileinto "INBOX.scc.annoy";
+ stop;
+ }
+
+#other local rules
+if header :contains ["Subject"] "helmreich" { fileinto "INBOX.lists.helmreich"; stop; }
+if header :contains ["Subject"] "helmcomm" { fileinto "INBOX.lists.helmreich"; stop; }
+if header :contains ["Subject"] "packeteer" { fileinto "INBOX.lists"; stop; }
diff --git a/pigeonhole/examples/subaddress.rfc5233.sieve b/pigeonhole/examples/subaddress.rfc5233.sieve
new file mode 100644
index 0000000..9e0177c
--- /dev/null
+++ b/pigeonhole/examples/subaddress.rfc5233.sieve
@@ -0,0 +1,23 @@
+require ["envelope", "subaddress", "fileinto"];
+
+# In this example the same user account receives mail for both
+# "ken@example.com" and "postmaster@example.com"
+
+# File all messages to postmaster into a single mailbox,
+# ignoring the :detail part.
+if envelope :user "to" "postmaster" {
+ fileinto "inbox.postmaster";
+ stop;
+}
+
+# File mailing list messages (subscribed as "ken+mta-filters").
+if envelope :detail "to" "mta-filters" {
+ fileinto "inbox.ietf-mta-filters";
+}
+
+# Redirect all mail sent to "ken+foo".
+if envelope :detail "to" "foo" {
+ redirect "ken@example.net";
+}
+
+
diff --git a/pigeonhole/examples/vacation.sieve b/pigeonhole/examples/vacation.sieve
new file mode 100644
index 0000000..660b9c5
--- /dev/null
+++ b/pigeonhole/examples/vacation.sieve
@@ -0,0 +1,23 @@
+require ["fileinto","reject", "vacation"];
+if allof (header :contains "X-Spam-Flag" "YES")
+{
+ discard ;
+}
+
+elsif allof (header :contains "subject" "<quation>")
+{
+vacation
+:addresses "<name@domain.ru>"
+:subject "<Answear>"
+:mime "MIME-Version: 1.0
+Content-Type: text/html; charset=KOI8-R
+Content-Transfer-Encoding: 7bit
+<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
+<HTML><HEAD><META http-equiv=Content-Type content=\"text/html; charset=windows-KOI8-R\">
+</HEAD><BODY>123</BODY></HTML>";
+ discard ;
+}
+else
+{
+ keep;
+}
diff --git a/pigeonhole/examples/vivil.sieve b/pigeonhole/examples/vivil.sieve
new file mode 100644
index 0000000..bce7507
--- /dev/null
+++ b/pigeonhole/examples/vivil.sieve
@@ -0,0 +1,94 @@
+# Example Sieve Script
+# Author: Vivil
+# URL: http://wiki.fastmail.fm/index.php?title=Vivil
+# Removed unused notify require
+
+# *************************************************************************
+require ["envelope", "fileinto", "reject", "vacation", "regex", "relational",
+"comparator-i;ascii-numeric"];
+
+
+if size :over 2048K {
+ reject "Message not delivered; size over limit accepted by recipient";
+ stop;
+}
+
+#because of the use of elsif below, none of the "stop;"'s below are needed, but they're good 'defensive programming'. Only the one above is actually needed.
+
+redirect "login@gmail.dom";
+
+if header :contains ["from","cc"]
+[
+ "from-begin@beginbeginbeginbeginbeginbeginbeginbeginbegin.fr",
+ "sex.com newsletter",
+ "ad@gator.com",
+ "newsletter@takecareof.com",
+ "from-end@endendendendendendendendendendendendendendendend.fr"
+]
+{
+ discard;
+ stop;
+}
+
+elsif header :contains ["from"]
+[
+ "mygirlfriend-who-use-incredimail@foo.dom"
+]
+{
+ fileinto "INBOX.PRIORITY";
+ stop;
+}
+
+#use of "to" field detection next lines is ONLY USEFUL FOR DOMAIN NAME OWNERS if you forward your mail to your fastmail account, some virus/spam send mail to well known addresses as info@willemijns.dom i never use...
+
+elsif header :contains ["to","cc"]
+[
+ "to-begin@beginbeginbeginbeginbeginbeginbeginbeginbegin.fr",
+ "FTPsebastien@willemijns.dom",
+ "info@willemijns.dom",
+ "webmaster@willemijns.dom",
+ "to-end@endendendendendendendendendendendendendendendend.fr"
+]
+{
+ discard;
+ stop;
+}
+
+elsif header :contains ["subject"]
+[
+ "subject-begin@beginbeginbeginbeginbeginbeginbeginbeginbegin.fr",
+ "Undeliverable mail: Registration is accepted",
+ "subject-end@endendendendendendendendendendendendendendendend.fr"
+]
+{
+ discard;
+ stop;
+}
+elsif header :value "ge" :comparator "i;ascii-numeric" ["X-Spam-score"] ["6"] {
+ fileinto "INBOX.Junk Mail";
+ stop;
+}
+elsif header :contains "from" "reflector@launay.dom" {
+ fileinto "INBOX.TEST";
+ stop;
+}
+elsif header :contains "from" "do-not-reply@franconews.dom" {
+ fileinto "INBOX.TEST";
+ stop;
+}
+elsif header :contains "from" "devnull@news.telefonica.dom" {
+ fileinto "INBOX.TEST";
+ stop;
+}
+elsif header :contains ["to"] ["sebastien@willemijns.dom"] {
+ fileinto "INBOX.PRIORITY";
+ stop;
+}
+elsif header :contains ["to"] ["seb@willemijns.dom"] {
+ fileinto "INBOX.PRIORITY";
+ stop;
+}
+else {
+ fileinto "INBOX";
+}
+# ********************************************************************
diff --git a/pigeonhole/install-sh b/pigeonhole/install-sh
new file mode 100755
index 0000000..ec298b5
--- /dev/null
+++ b/pigeonhole/install-sh
@@ -0,0 +1,541 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2020-11-14.01; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# 'make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+tab=' '
+nl='
+'
+IFS=" $tab$nl"
+
+# Set DOITPROG to "echo" to test this script.
+
+doit=${DOITPROG-}
+doit_exec=${doit:-exec}
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+# Create dirs (including intermediate dirs) using mode 755.
+# This is like GNU 'install' as of coreutils 8.32 (2020).
+mkdir_umask=22
+
+backupsuffix=
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+is_target_a_directory=possibly
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
+
+ -c (ignored)
+ -C install only if different (preserve data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -p pass -p to $cpprog.
+ -s $stripprog installed files.
+ -S SUFFIX attempt to back up existing files, with suffix SUFFIX.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+
+By default, rm is invoked with -f; when overridden with RMPROG,
+it's up to you to specify -f if you want it.
+
+If -S is not specified, no backups are attempted.
+
+Email bug reports to bug-automake@gnu.org.
+Automake home page: https://www.gnu.org/software/automake/
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
+
+ -C) copy_on_change=true;;
+
+ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ case $mode in
+ *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
+
+ -o) chowncmd="$chownprog $2"
+ shift;;
+
+ -p) cpprog="$cpprog -p";;
+
+ -s) stripcmd=$stripprog;;
+
+ -S) backupsuffix="$2"
+ shift;;
+
+ -t)
+ is_target_a_directory=always
+ dst_arg=$2
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ shift;;
+
+ -T) is_target_a_directory=never;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+ shift
+done
+
+# We allow the use of options -d and -T together, by making -d
+# take the precedence; this is for compatibility with GNU install.
+
+if test -n "$dir_arg"; then
+ if test -n "$dst_arg"; then
+ echo "$0: target directory not allowed when installing a directory." >&2
+ exit 1
+ fi
+fi
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call 'install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ if test $# -gt 1 || test "$is_target_a_directory" = always; then
+ if test ! -d "$dst_arg"; then
+ echo "$0: $dst_arg: Is not a directory." >&2
+ exit 1
+ fi
+ fi
+fi
+
+if test -z "$dir_arg"; then
+ do_exit='(exit $ret); exit $ret'
+ trap "ret=129; $do_exit" 1
+ trap "ret=130; $do_exit" 2
+ trap "ret=141; $do_exit" 13
+ trap "ret=143; $do_exit" 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names problematic for 'test' and other utilities.
+ case $src in
+ -* | [=\(\)!]) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ # Don't chown directories that already exist.
+ if test $dstdir_status = 0; then
+ chowncmd=""
+ fi
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+ dst=$dst_arg
+
+ # If destination is a directory, append the input filename.
+ if test -d "$dst"; then
+ if test "$is_target_a_directory" = never; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dstbase=`basename "$src"`
+ case $dst in
+ */) dst=$dst$dstbase;;
+ *) dst=$dst/$dstbase;;
+ esac
+ dstdir_status=0
+ else
+ dstdir=`dirname "$dst"`
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ case $dstdir in
+ */) dstdirslash=$dstdir;;
+ *) dstdirslash=$dstdir/;;
+ esac
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ # The $RANDOM variable is not portable (e.g., dash). Use it
+ # here however when possible just to lower collision chance.
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+
+ trap '
+ ret=$?
+ rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
+ exit $ret
+ ' 0
+
+ # Because "mkdir -p" follows existing symlinks and we likely work
+ # directly in world-writeable /tmp, make sure that the '$tmpdir'
+ # directory is successfully created first before we actually test
+ # 'mkdir -p'.
+ if (umask $mkdir_umask &&
+ $mkdirprog $mkdir_mode "$tmpdir" &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ test_tmpdir="$tmpdir/a"
+ ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
+ fi
+ trap '' 0;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ [-=\(\)!]*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ oIFS=$IFS
+ IFS=/
+ set -f
+ set fnord $dstdir
+ shift
+ set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test X"$d" = X && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=${dstdirslash}_inst.$$_
+ rmtmp=${dstdirslash}_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask &&
+ { test -z "$stripcmd" || {
+ # Create $dsttmp read-write so that cp doesn't create it read-only,
+ # which would cause strip to fail.
+ if test -z "$doit"; then
+ : >"$dsttmp" # No need to fork-exec 'touch'.
+ else
+ $doit touch "$dsttmp"
+ fi
+ }
+ } &&
+ $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+ set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ set +f &&
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # If $backupsuffix is set, and the file being installed
+ # already exists, attempt a backup. Don't worry if it fails,
+ # e.g., if mv doesn't support -f.
+ if test -n "$backupsuffix" && test -f "$dst"; then
+ $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
+ fi
+
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/pigeonhole/ltmain.sh b/pigeonhole/ltmain.sh
new file mode 100755
index 0000000..21e5e07
--- /dev/null
+++ b/pigeonhole/ltmain.sh
@@ -0,0 +1,11251 @@
+#! /bin/sh
+## DO NOT EDIT - This file generated from ./build-aux/ltmain.in
+## by inline-source v2014-01-03.01
+
+# libtool (GNU libtool) 2.4.6
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION="2.4.6 Debian-2.4.6-15"
+package_revision=2.4.6
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# Run './libtool --help' for help with using this script from the
+# command line.
+
+
+## ------------------------------- ##
+## User overridable command paths. ##
+## ------------------------------- ##
+
+# After configure completes, it has a better idea of some of the
+# shell tools we need than the defaults used by the functions shared
+# with bootstrap, so set those here where they can still be over-
+# ridden by the user, but otherwise take precedence.
+
+: ${AUTOCONF="autoconf"}
+: ${AUTOMAKE="automake"}
+
+
+## -------------------------- ##
+## Source external libraries. ##
+## -------------------------- ##
+
+# Much of our low-level functionality needs to be sourced from external
+# libraries, which are installed to $pkgauxdir.
+
+# Set a version string for this script.
+scriptversion=2015-01-20.17; # UTC
+
+# General shell script boiler plate, and helper functions.
+# Written by Gary V. Vaughan, 2004
+
+# Copyright (C) 2004-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# As a special exception to the GNU General Public License, if you distribute
+# this file as part of a program or library that is built using GNU Libtool,
+# you may include this file under the same distribution terms that you use
+# for the rest of that program.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Please report bugs or propose patches to gary@gnu.org.
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# Evaluate this file near the top of your script to gain access to
+# the functions and variables defined here:
+#
+# . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh
+#
+# If you need to override any of the default environment variable
+# settings, do that before evaluating this file.
+
+
+## -------------------- ##
+## Shell normalisation. ##
+## -------------------- ##
+
+# Some shells need a little help to be as Bourne compatible as possible.
+# Before doing anything else, make sure all that help has been provided!
+
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac
+fi
+
+# NLS nuisances: We save the old values in case they are required later.
+_G_user_locale=
+_G_safe_locale=
+for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+ eval "if test set = \"\${$_G_var+set}\"; then
+ save_$_G_var=\$$_G_var
+ $_G_var=C
+ export $_G_var
+ _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\"
+ _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\"
+ fi"
+done
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Make sure IFS has a sensible default
+sp=' '
+nl='
+'
+IFS="$sp $nl"
+
+# There are apparently some retarded systems that use ';' as a PATH separator!
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+
+## ------------------------- ##
+## Locate command utilities. ##
+## ------------------------- ##
+
+
+# func_executable_p FILE
+# ----------------------
+# Check that FILE is an executable regular file.
+func_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+}
+
+
+# func_path_progs PROGS_LIST CHECK_FUNC [PATH]
+# --------------------------------------------
+# Search for either a program that responds to --version with output
+# containing "GNU", or else returned by CHECK_FUNC otherwise, by
+# trying all the directories in PATH with each of the elements of
+# PROGS_LIST.
+#
+# CHECK_FUNC should accept the path to a candidate program, and
+# set $func_check_prog_result if it truncates its output less than
+# $_G_path_prog_max characters.
+func_path_progs ()
+{
+ _G_progs_list=$1
+ _G_check_func=$2
+ _G_PATH=${3-"$PATH"}
+
+ _G_path_prog_max=0
+ _G_path_prog_found=false
+ _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:}
+ for _G_dir in $_G_PATH; do
+ IFS=$_G_save_IFS
+ test -z "$_G_dir" && _G_dir=.
+ for _G_prog_name in $_G_progs_list; do
+ for _exeext in '' .EXE; do
+ _G_path_prog=$_G_dir/$_G_prog_name$_exeext
+ func_executable_p "$_G_path_prog" || continue
+ case `"$_G_path_prog" --version 2>&1` in
+ *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;;
+ *) $_G_check_func $_G_path_prog
+ func_path_progs_result=$func_check_prog_result
+ ;;
+ esac
+ $_G_path_prog_found && break 3
+ done
+ done
+ done
+ IFS=$_G_save_IFS
+ test -z "$func_path_progs_result" && {
+ echo "no acceptable sed could be found in \$PATH" >&2
+ exit 1
+ }
+}
+
+
+# We want to be able to use the functions in this file before configure
+# has figured out where the best binaries are kept, which means we have
+# to search for them ourselves - except when the results are already set
+# where we skip the searches.
+
+# Unless the user overrides by setting SED, search the path for either GNU
+# sed, or the sed that truncates its output the least.
+test -z "$SED" && {
+ _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for _G_i in 1 2 3 4 5 6 7; do
+ _G_sed_script=$_G_sed_script$nl$_G_sed_script
+ done
+ echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed
+ _G_sed_script=
+
+ func_check_prog_sed ()
+ {
+ _G_path_prog=$1
+
+ _G_count=0
+ printf 0123456789 >conftest.in
+ while :
+ do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo '' >> conftest.nl
+ "$_G_path_prog" -f conftest.sed <conftest.nl >conftest.out 2>/dev/null || break
+ diff conftest.out conftest.nl >/dev/null 2>&1 || break
+ _G_count=`expr $_G_count + 1`
+ if test "$_G_count" -gt "$_G_path_prog_max"; then
+ # Best one so far, save it but keep looking for a better one
+ func_check_prog_result=$_G_path_prog
+ _G_path_prog_max=$_G_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test 10 -lt "$_G_count" && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out
+ }
+
+ func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin
+ rm -f conftest.sed
+ SED=$func_path_progs_result
+}
+
+
+# Unless the user overrides by setting GREP, search the path for either GNU
+# grep, or the grep that truncates its output the least.
+test -z "$GREP" && {
+ func_check_prog_grep ()
+ {
+ _G_path_prog=$1
+
+ _G_count=0
+ _G_path_prog_max=0
+ printf 0123456789 >conftest.in
+ while :
+ do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo 'GREP' >> conftest.nl
+ "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' <conftest.nl >conftest.out 2>/dev/null || break
+ diff conftest.out conftest.nl >/dev/null 2>&1 || break
+ _G_count=`expr $_G_count + 1`
+ if test "$_G_count" -gt "$_G_path_prog_max"; then
+ # Best one so far, save it but keep looking for a better one
+ func_check_prog_result=$_G_path_prog
+ _G_path_prog_max=$_G_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test 10 -lt "$_G_count" && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out
+ }
+
+ func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin
+ GREP=$func_path_progs_result
+}
+
+
+## ------------------------------- ##
+## User overridable command paths. ##
+## ------------------------------- ##
+
+# All uppercase variable names are used for environment variables. These
+# variables can be overridden by the user before calling a script that
+# uses them if a suitable command of that name is not already available
+# in the command search PATH.
+
+: ${CP="cp -f"}
+: ${ECHO="printf %s\n"}
+: ${EGREP="$GREP -E"}
+: ${FGREP="$GREP -F"}
+: ${LN_S="ln -s"}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+
+
+## -------------------- ##
+## Useful sed snippets. ##
+## -------------------- ##
+
+sed_dirname='s|/[^/]*$||'
+sed_basename='s|^.*/||'
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
+
+# Same as above, but do not quote variable references.
+sed_double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution that turns a string into a regex matching for the
+# string literally.
+sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g'
+
+# Sed substitution that converts a w32 file name or path
+# that contains forward slashes, into one that contains
+# (escaped) backslashes. A very naive implementation.
+sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+
+# Re-'\' parameter expansions in output of sed_double_quote_subst that
+# were '\'-ed in input to the same. If an odd number of '\' preceded a
+# '$' in input to sed_double_quote_subst, that '$' was protected from
+# expansion. Since each input '\' is now two '\'s, look for any number
+# of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'.
+_G_bs='\\'
+_G_bs2='\\\\'
+_G_bs4='\\\\\\\\'
+_G_dollar='\$'
+sed_double_backslash="\
+ s/$_G_bs4/&\\
+/g
+ s/^$_G_bs2$_G_dollar/$_G_bs&/
+ s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g
+ s/\n//g"
+
+
+## ----------------- ##
+## Global variables. ##
+## ----------------- ##
+
+# Except for the global variables explicitly listed below, the following
+# functions in the '^func_' namespace, and the '^require_' namespace
+# variables initialised in the 'Resource management' section, sourcing
+# this file will not pollute your global namespace with anything
+# else. There's no portable way to scope variables in Bourne shell
+# though, so actually running these functions will sometimes place
+# results into a variable named after the function, and often use
+# temporary variables in the '^_G_' namespace. If you are careful to
+# avoid using those namespaces casually in your sourcing script, things
+# should continue to work as you expect. And, of course, you can freely
+# overwrite any of the functions or variables defined here before
+# calling anything to customize them.
+
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake.
+
+# Allow overriding, eg assuming that you follow the convention of
+# putting '$debug_cmd' at the start of all your functions, you can get
+# bash to show function call trace with:
+#
+# debug_cmd='echo "${FUNCNAME[0]} $*" >&2' bash your-script-name
+debug_cmd=${debug_cmd-":"}
+exit_cmd=:
+
+# By convention, finish your script with:
+#
+# exit $exit_status
+#
+# so that you can set exit_status to non-zero if you want to indicate
+# something went wrong during execution without actually bailing out at
+# the point of failure.
+exit_status=$EXIT_SUCCESS
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath=$0
+
+# The name of this program.
+progname=`$ECHO "$progpath" |$SED "$sed_basename"`
+
+# Make sure we have an absolute progpath for reexecution:
+case $progpath in
+ [\\/]*|[A-Za-z]:\\*) ;;
+ *[\\/]*)
+ progdir=`$ECHO "$progpath" |$SED "$sed_dirname"`
+ progdir=`cd "$progdir" && pwd`
+ progpath=$progdir/$progname
+ ;;
+ *)
+ _G_IFS=$IFS
+ IFS=${PATH_SEPARATOR-:}
+ for progdir in $PATH; do
+ IFS=$_G_IFS
+ test -x "$progdir/$progname" && break
+ done
+ IFS=$_G_IFS
+ test -n "$progdir" || progdir=`pwd`
+ progpath=$progdir/$progname
+ ;;
+esac
+
+
+## ----------------- ##
+## Standard options. ##
+## ----------------- ##
+
+# The following options affect the operation of the functions defined
+# below, and should be set appropriately depending on run-time para-
+# meters passed on the command line.
+
+opt_dry_run=false
+opt_quiet=false
+opt_verbose=false
+
+# Categories 'all' and 'none' are always available. Append any others
+# you will pass as the first argument to func_warning from your own
+# code.
+warning_categories=
+
+# By default, display warnings according to 'opt_warning_types'. Set
+# 'warning_func' to ':' to elide all warnings, or func_fatal_error to
+# treat the next displayed warning as a fatal error.
+warning_func=func_warn_and_continue
+
+# Set to 'all' to display all warnings, 'none' to suppress all
+# warnings, or a space delimited list of some subset of
+# 'warning_categories' to display only the listed warnings.
+opt_warning_types=all
+
+
+## -------------------- ##
+## Resource management. ##
+## -------------------- ##
+
+# This section contains definitions for functions that each ensure a
+# particular resource (a file, or a non-empty configuration variable for
+# example) is available, and if appropriate to extract default values
+# from pertinent package files. Call them using their associated
+# 'require_*' variable to ensure that they are executed, at most, once.
+#
+# It's entirely deliberate that calling these functions can set
+# variables that don't obey the namespace limitations obeyed by the rest
+# of this file, in order that that they be as useful as possible to
+# callers.
+
+
+# require_term_colors
+# -------------------
+# Allow display of bold text on terminals that support it.
+require_term_colors=func_require_term_colors
+func_require_term_colors ()
+{
+ $debug_cmd
+
+ test -t 1 && {
+ # COLORTERM and USE_ANSI_COLORS environment variables take
+ # precedence, because most terminfo databases neglect to describe
+ # whether color sequences are supported.
+ test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"}
+
+ if test 1 = "$USE_ANSI_COLORS"; then
+ # Standard ANSI escape sequences
+ tc_reset=''
+ tc_bold=''; tc_standout=''
+ tc_red=''; tc_green=''
+ tc_blue=''; tc_cyan=''
+ else
+ # Otherwise trust the terminfo database after all.
+ test -n "`tput sgr0 2>/dev/null`" && {
+ tc_reset=`tput sgr0`
+ test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold`
+ tc_standout=$tc_bold
+ test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso`
+ test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1`
+ test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2`
+ test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4`
+ test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5`
+ }
+ fi
+ }
+
+ require_term_colors=:
+}
+
+
+## ----------------- ##
+## Function library. ##
+## ----------------- ##
+
+# This section contains a variety of useful functions to call in your
+# scripts. Take note of the portable wrappers for features provided by
+# some modern shells, which will fall back to slower equivalents on
+# less featureful shells.
+
+
+# func_append VAR VALUE
+# ---------------------
+# Append VALUE onto the existing contents of VAR.
+
+ # We should try to minimise forks, especially on Windows where they are
+ # unreasonably slow, so skip the feature probes when bash or zsh are
+ # being used:
+ if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then
+ : ${_G_HAVE_ARITH_OP="yes"}
+ : ${_G_HAVE_XSI_OPS="yes"}
+ # The += operator was introduced in bash 3.1
+ case $BASH_VERSION in
+ [12].* | 3.0 | 3.0*) ;;
+ *)
+ : ${_G_HAVE_PLUSEQ_OP="yes"}
+ ;;
+ esac
+ fi
+
+ # _G_HAVE_PLUSEQ_OP
+ # Can be empty, in which case the shell is probed, "yes" if += is
+ # useable or anything else if it does not work.
+ test -z "$_G_HAVE_PLUSEQ_OP" \
+ && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \
+ && _G_HAVE_PLUSEQ_OP=yes
+
+if test yes = "$_G_HAVE_PLUSEQ_OP"
+then
+ # This is an XSI compatible shell, allowing a faster implementation...
+ eval 'func_append ()
+ {
+ $debug_cmd
+
+ eval "$1+=\$2"
+ }'
+else
+ # ...otherwise fall back to using expr, which is often a shell builtin.
+ func_append ()
+ {
+ $debug_cmd
+
+ eval "$1=\$$1\$2"
+ }
+fi
+
+
+# func_append_quoted VAR VALUE
+# ----------------------------
+# Quote VALUE and append to the end of shell variable VAR, separated
+# by a space.
+if test yes = "$_G_HAVE_PLUSEQ_OP"; then
+ eval 'func_append_quoted ()
+ {
+ $debug_cmd
+
+ func_quote_for_eval "$2"
+ eval "$1+=\\ \$func_quote_for_eval_result"
+ }'
+else
+ func_append_quoted ()
+ {
+ $debug_cmd
+
+ func_quote_for_eval "$2"
+ eval "$1=\$$1\\ \$func_quote_for_eval_result"
+ }
+fi
+
+
+# func_append_uniq VAR VALUE
+# --------------------------
+# Append unique VALUE onto the existing contents of VAR, assuming
+# entries are delimited by the first character of VALUE. For example:
+#
+# func_append_uniq options " --another-option option-argument"
+#
+# will only append to $options if " --another-option option-argument "
+# is not already present somewhere in $options already (note spaces at
+# each end implied by leading space in second argument).
+func_append_uniq ()
+{
+ $debug_cmd
+
+ eval _G_current_value='`$ECHO $'$1'`'
+ _G_delim=`expr "$2" : '\(.\)'`
+
+ case $_G_delim$_G_current_value$_G_delim in
+ *"$2$_G_delim"*) ;;
+ *) func_append "$@" ;;
+ esac
+}
+
+
+# func_arith TERM...
+# ------------------
+# Set func_arith_result to the result of evaluating TERMs.
+ test -z "$_G_HAVE_ARITH_OP" \
+ && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \
+ && _G_HAVE_ARITH_OP=yes
+
+if test yes = "$_G_HAVE_ARITH_OP"; then
+ eval 'func_arith ()
+ {
+ $debug_cmd
+
+ func_arith_result=$(( $* ))
+ }'
+else
+ func_arith ()
+ {
+ $debug_cmd
+
+ func_arith_result=`expr "$@"`
+ }
+fi
+
+
+# func_basename FILE
+# ------------------
+# Set func_basename_result to FILE with everything up to and including
+# the last / stripped.
+if test yes = "$_G_HAVE_XSI_OPS"; then
+ # If this shell supports suffix pattern removal, then use it to avoid
+ # forking. Hide the definitions single quotes in case the shell chokes
+ # on unsupported syntax...
+ _b='func_basename_result=${1##*/}'
+ _d='case $1 in
+ */*) func_dirname_result=${1%/*}$2 ;;
+ * ) func_dirname_result=$3 ;;
+ esac'
+
+else
+ # ...otherwise fall back to using sed.
+ _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`'
+ _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"`
+ if test "X$func_dirname_result" = "X$1"; then
+ func_dirname_result=$3
+ else
+ func_append func_dirname_result "$2"
+ fi'
+fi
+
+eval 'func_basename ()
+{
+ $debug_cmd
+
+ '"$_b"'
+}'
+
+
+# func_dirname FILE APPEND NONDIR_REPLACEMENT
+# -------------------------------------------
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+eval 'func_dirname ()
+{
+ $debug_cmd
+
+ '"$_d"'
+}'
+
+
+# func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT
+# --------------------------------------------------------
+# Perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# For efficiency, we do not delegate to the functions above but instead
+# duplicate the functionality here.
+eval 'func_dirname_and_basename ()
+{
+ $debug_cmd
+
+ '"$_b"'
+ '"$_d"'
+}'
+
+
+# func_echo ARG...
+# ----------------
+# Echo program name prefixed message.
+func_echo ()
+{
+ $debug_cmd
+
+ _G_message=$*
+
+ func_echo_IFS=$IFS
+ IFS=$nl
+ for _G_line in $_G_message; do
+ IFS=$func_echo_IFS
+ $ECHO "$progname: $_G_line"
+ done
+ IFS=$func_echo_IFS
+}
+
+
+# func_echo_all ARG...
+# --------------------
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO "$*"
+}
+
+
+# func_echo_infix_1 INFIX ARG...
+# ------------------------------
+# Echo program name, followed by INFIX on the first line, with any
+# additional lines not showing INFIX.
+func_echo_infix_1 ()
+{
+ $debug_cmd
+
+ $require_term_colors
+
+ _G_infix=$1; shift
+ _G_indent=$_G_infix
+ _G_prefix="$progname: $_G_infix: "
+ _G_message=$*
+
+ # Strip color escape sequences before counting printable length
+ for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan"
+ do
+ test -n "$_G_tc" && {
+ _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"`
+ _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"`
+ }
+ done
+ _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes
+
+ func_echo_infix_1_IFS=$IFS
+ IFS=$nl
+ for _G_line in $_G_message; do
+ IFS=$func_echo_infix_1_IFS
+ $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2
+ _G_prefix=$_G_indent
+ done
+ IFS=$func_echo_infix_1_IFS
+}
+
+
+# func_error ARG...
+# -----------------
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+ $debug_cmd
+
+ $require_term_colors
+
+ func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2
+}
+
+
+# func_fatal_error ARG...
+# -----------------------
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+ $debug_cmd
+
+ func_error "$*"
+ exit $EXIT_FAILURE
+}
+
+
+# func_grep EXPRESSION FILENAME
+# -----------------------------
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+ $debug_cmd
+
+ $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_len STRING
+# ---------------
+# Set func_len_result to the length of STRING. STRING may not
+# start with a hyphen.
+ test -z "$_G_HAVE_XSI_OPS" \
+ && (eval 'x=a/b/c;
+ test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
+ && _G_HAVE_XSI_OPS=yes
+
+if test yes = "$_G_HAVE_XSI_OPS"; then
+ eval 'func_len ()
+ {
+ $debug_cmd
+
+ func_len_result=${#1}
+ }'
+else
+ func_len ()
+ {
+ $debug_cmd
+
+ func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
+ }
+fi
+
+
+# func_mkdir_p DIRECTORY-PATH
+# ---------------------------
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+ $debug_cmd
+
+ _G_directory_path=$1
+ _G_dir_list=
+
+ if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then
+
+ # Protect directory names starting with '-'
+ case $_G_directory_path in
+ -*) _G_directory_path=./$_G_directory_path ;;
+ esac
+
+ # While some portion of DIR does not yet exist...
+ while test ! -d "$_G_directory_path"; do
+ # ...make a list in topmost first order. Use a colon delimited
+ # list incase some portion of path contains whitespace.
+ _G_dir_list=$_G_directory_path:$_G_dir_list
+
+ # If the last portion added has no slash in it, the list is done
+ case $_G_directory_path in */*) ;; *) break ;; esac
+
+ # ...otherwise throw away the child directory and loop
+ _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"`
+ done
+ _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'`
+
+ func_mkdir_p_IFS=$IFS; IFS=:
+ for _G_dir in $_G_dir_list; do
+ IFS=$func_mkdir_p_IFS
+ # mkdir can fail with a 'File exist' error if two processes
+ # try to create one of the directories concurrently. Don't
+ # stop in that case!
+ $MKDIR "$_G_dir" 2>/dev/null || :
+ done
+ IFS=$func_mkdir_p_IFS
+
+ # Bail out if we (or some other process) failed to create a directory.
+ test -d "$_G_directory_path" || \
+ func_fatal_error "Failed to create '$1'"
+ fi
+}
+
+
+# func_mktempdir [BASENAME]
+# -------------------------
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible. If
+# given, BASENAME is the basename for that directory.
+func_mktempdir ()
+{
+ $debug_cmd
+
+ _G_template=${TMPDIR-/tmp}/${1-$progname}
+
+ if test : = "$opt_dry_run"; then
+ # Return a directory name, but don't create it in dry-run mode
+ _G_tmpdir=$_G_template-$$
+ else
+
+ # If mktemp works, use that first and foremost
+ _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null`
+
+ if test ! -d "$_G_tmpdir"; then
+ # Failing that, at least try and use $RANDOM to avoid a race
+ _G_tmpdir=$_G_template-${RANDOM-0}$$
+
+ func_mktempdir_umask=`umask`
+ umask 0077
+ $MKDIR "$_G_tmpdir"
+ umask $func_mktempdir_umask
+ fi
+
+ # If we're not in dry-run mode, bomb out on failure
+ test -d "$_G_tmpdir" || \
+ func_fatal_error "cannot create temporary directory '$_G_tmpdir'"
+ fi
+
+ $ECHO "$_G_tmpdir"
+}
+
+
+# func_normal_abspath PATH
+# ------------------------
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+func_normal_abspath ()
+{
+ $debug_cmd
+
+ # These SED scripts presuppose an absolute path with a trailing slash.
+ _G_pathcar='s|^/\([^/]*\).*$|\1|'
+ _G_pathcdr='s|^/[^/]*||'
+ _G_removedotparts=':dotsl
+ s|/\./|/|g
+ t dotsl
+ s|/\.$|/|'
+ _G_collapseslashes='s|/\{1,\}|/|g'
+ _G_finalslash='s|/*$|/|'
+
+ # Start from root dir and reassemble the path.
+ func_normal_abspath_result=
+ func_normal_abspath_tpath=$1
+ func_normal_abspath_altnamespace=
+ case $func_normal_abspath_tpath in
+ "")
+ # Empty path, that just means $cwd.
+ func_stripname '' '/' "`pwd`"
+ func_normal_abspath_result=$func_stripname_result
+ return
+ ;;
+ # The next three entries are used to spot a run of precisely
+ # two leading slashes without using negated character classes;
+ # we take advantage of case's first-match behaviour.
+ ///*)
+ # Unusual form of absolute path, do nothing.
+ ;;
+ //*)
+ # Not necessarily an ordinary path; POSIX reserves leading '//'
+ # and for example Cygwin uses it to access remote file shares
+ # over CIFS/SMB, so we conserve a leading double slash if found.
+ func_normal_abspath_altnamespace=/
+ ;;
+ /*)
+ # Absolute path, do nothing.
+ ;;
+ *)
+ # Relative path, prepend $cwd.
+ func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+ ;;
+ esac
+
+ # Cancel out all the simple stuff to save iterations. We also want
+ # the path to end with a slash for ease of parsing, so make sure
+ # there is one (and only one) here.
+ func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"`
+ while :; do
+ # Processed it all yet?
+ if test / = "$func_normal_abspath_tpath"; then
+ # If we ascended to the root using ".." the result may be empty now.
+ if test -z "$func_normal_abspath_result"; then
+ func_normal_abspath_result=/
+ fi
+ break
+ fi
+ func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$_G_pathcar"`
+ func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$_G_pathcdr"`
+ # Figure out what to do with it
+ case $func_normal_abspath_tcomponent in
+ "")
+ # Trailing empty path component, ignore it.
+ ;;
+ ..)
+ # Parent dir; strip last assembled component from result.
+ func_dirname "$func_normal_abspath_result"
+ func_normal_abspath_result=$func_dirname_result
+ ;;
+ *)
+ # Actual path component, append it.
+ func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent"
+ ;;
+ esac
+ done
+ # Restore leading double-slash if one was found on entry.
+ func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+
+# func_notquiet ARG...
+# --------------------
+# Echo program name prefixed message only when not in quiet mode.
+func_notquiet ()
+{
+ $debug_cmd
+
+ $opt_quiet || func_echo ${1+"$@"}
+
+ # A bug in bash halts the script if the last line of a function
+ # fails when set -e is in force, so we need another command to
+ # work around that:
+ :
+}
+
+
+# func_relative_path SRCDIR DSTDIR
+# --------------------------------
+# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR.
+func_relative_path ()
+{
+ $debug_cmd
+
+ func_relative_path_result=
+ func_normal_abspath "$1"
+ func_relative_path_tlibdir=$func_normal_abspath_result
+ func_normal_abspath "$2"
+ func_relative_path_tbindir=$func_normal_abspath_result
+
+ # Ascend the tree starting from libdir
+ while :; do
+ # check if we have found a prefix of bindir
+ case $func_relative_path_tbindir in
+ $func_relative_path_tlibdir)
+ # found an exact match
+ func_relative_path_tcancelled=
+ break
+ ;;
+ $func_relative_path_tlibdir*)
+ # found a matching prefix
+ func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+ func_relative_path_tcancelled=$func_stripname_result
+ if test -z "$func_relative_path_result"; then
+ func_relative_path_result=.
+ fi
+ break
+ ;;
+ *)
+ func_dirname $func_relative_path_tlibdir
+ func_relative_path_tlibdir=$func_dirname_result
+ if test -z "$func_relative_path_tlibdir"; then
+ # Have to descend all the way to the root!
+ func_relative_path_result=../$func_relative_path_result
+ func_relative_path_tcancelled=$func_relative_path_tbindir
+ break
+ fi
+ func_relative_path_result=../$func_relative_path_result
+ ;;
+ esac
+ done
+
+ # Now calculate path; take care to avoid doubling-up slashes.
+ func_stripname '' '/' "$func_relative_path_result"
+ func_relative_path_result=$func_stripname_result
+ func_stripname '/' '/' "$func_relative_path_tcancelled"
+ if test -n "$func_stripname_result"; then
+ func_append func_relative_path_result "/$func_stripname_result"
+ fi
+
+ # Normalisation. If bindir is libdir, return '.' else relative path.
+ if test -n "$func_relative_path_result"; then
+ func_stripname './' '' "$func_relative_path_result"
+ func_relative_path_result=$func_stripname_result
+ fi
+
+ test -n "$func_relative_path_result" || func_relative_path_result=.
+
+ :
+}
+
+
+# func_quote_for_eval ARG...
+# --------------------------
+# Aesthetically quote ARGs to be evaled later.
+# This function returns two values:
+# i) func_quote_for_eval_result
+# double-quoted, suitable for a subsequent eval
+# ii) func_quote_for_eval_unquoted_result
+# has all characters that are still active within double
+# quotes backslashified.
+func_quote_for_eval ()
+{
+ $debug_cmd
+
+ func_quote_for_eval_unquoted_result=
+ func_quote_for_eval_result=
+ while test 0 -lt $#; do
+ case $1 in
+ *[\\\`\"\$]*)
+ _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;;
+ *)
+ _G_unquoted_arg=$1 ;;
+ esac
+ if test -n "$func_quote_for_eval_unquoted_result"; then
+ func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg"
+ else
+ func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg"
+ fi
+
+ case $_G_unquoted_arg in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting, command substitution and variable expansion
+ # for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ _G_quoted_arg=\"$_G_unquoted_arg\"
+ ;;
+ *)
+ _G_quoted_arg=$_G_unquoted_arg
+ ;;
+ esac
+
+ if test -n "$func_quote_for_eval_result"; then
+ func_append func_quote_for_eval_result " $_G_quoted_arg"
+ else
+ func_append func_quote_for_eval_result "$_G_quoted_arg"
+ fi
+ shift
+ done
+}
+
+
+# func_quote_for_expand ARG
+# -------------------------
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+ $debug_cmd
+
+ case $1 in
+ *[\\\`\"]*)
+ _G_arg=`$ECHO "$1" | $SED \
+ -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;;
+ *)
+ _G_arg=$1 ;;
+ esac
+
+ case $_G_arg in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting and command substitution for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ _G_arg=\"$_G_arg\"
+ ;;
+ esac
+
+ func_quote_for_expand_result=$_G_arg
+}
+
+
+# func_stripname PREFIX SUFFIX NAME
+# ---------------------------------
+# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+if test yes = "$_G_HAVE_XSI_OPS"; then
+ eval 'func_stripname ()
+ {
+ $debug_cmd
+
+ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+ # positional parameters, so assign one to ordinary variable first.
+ func_stripname_result=$3
+ func_stripname_result=${func_stripname_result#"$1"}
+ func_stripname_result=${func_stripname_result%"$2"}
+ }'
+else
+ func_stripname ()
+ {
+ $debug_cmd
+
+ case $2 in
+ .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;;
+ *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;;
+ esac
+ }
+fi
+
+
+# func_show_eval CMD [FAIL_EXP]
+# -----------------------------
+# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is
+# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+ $debug_cmd
+
+ _G_cmd=$1
+ _G_fail_exp=${2-':'}
+
+ func_quote_for_expand "$_G_cmd"
+ eval "func_notquiet $func_quote_for_expand_result"
+
+ $opt_dry_run || {
+ eval "$_G_cmd"
+ _G_status=$?
+ if test 0 -ne "$_G_status"; then
+ eval "(exit $_G_status); $_G_fail_exp"
+ fi
+ }
+}
+
+
+# func_show_eval_locale CMD [FAIL_EXP]
+# ------------------------------------
+# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is
+# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it. Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+ $debug_cmd
+
+ _G_cmd=$1
+ _G_fail_exp=${2-':'}
+
+ $opt_quiet || {
+ func_quote_for_expand "$_G_cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+
+ $opt_dry_run || {
+ eval "$_G_user_locale
+ $_G_cmd"
+ _G_status=$?
+ eval "$_G_safe_locale"
+ if test 0 -ne "$_G_status"; then
+ eval "(exit $_G_status); $_G_fail_exp"
+ fi
+ }
+}
+
+
+# func_tr_sh
+# ----------
+# Turn $1 into a string suitable for a shell variable name.
+# Result is stored in $func_tr_sh_result. All characters
+# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
+# if $1 begins with a digit, a '_' is prepended as well.
+func_tr_sh ()
+{
+ $debug_cmd
+
+ case $1 in
+ [0-9]* | *[!a-zA-Z0-9_]*)
+ func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'`
+ ;;
+ * )
+ func_tr_sh_result=$1
+ ;;
+ esac
+}
+
+
+# func_verbose ARG...
+# -------------------
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+ $debug_cmd
+
+ $opt_verbose && func_echo "$*"
+
+ :
+}
+
+
+# func_warn_and_continue ARG...
+# -----------------------------
+# Echo program name prefixed warning message to standard error.
+func_warn_and_continue ()
+{
+ $debug_cmd
+
+ $require_term_colors
+
+ func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2
+}
+
+
+# func_warning CATEGORY ARG...
+# ----------------------------
+# Echo program name prefixed warning message to standard error. Warning
+# messages can be filtered according to CATEGORY, where this function
+# elides messages where CATEGORY is not listed in the global variable
+# 'opt_warning_types'.
+func_warning ()
+{
+ $debug_cmd
+
+ # CATEGORY must be in the warning_categories list!
+ case " $warning_categories " in
+ *" $1 "*) ;;
+ *) func_internal_error "invalid warning category '$1'" ;;
+ esac
+
+ _G_category=$1
+ shift
+
+ case " $opt_warning_types " in
+ *" $_G_category "*) $warning_func ${1+"$@"} ;;
+ esac
+}
+
+
+# func_sort_ver VER1 VER2
+# -----------------------
+# 'sort -V' is not generally available.
+# Note this deviates from the version comparison in automake
+# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a
+# but this should suffice as we won't be specifying old
+# version formats or redundant trailing .0 in bootstrap.conf.
+# If we did want full compatibility then we should probably
+# use m4_version_compare from autoconf.
+func_sort_ver ()
+{
+ $debug_cmd
+
+ printf '%s\n%s\n' "$1" "$2" \
+ | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n
+}
+
+# func_lt_ver PREV CURR
+# ---------------------
+# Return true if PREV and CURR are in the correct order according to
+# func_sort_ver, otherwise false. Use it like this:
+#
+# func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..."
+func_lt_ver ()
+{
+ $debug_cmd
+
+ test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q`
+}
+
+
+# Local variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-time-zone: "UTC"
+# End:
+#! /bin/sh
+
+# Set a version string for this script.
+scriptversion=2015-10-07.11; # UTC
+
+# A portable, pluggable option parser for Bourne shell.
+# Written by Gary V. Vaughan, 2010
+
+# Copyright (C) 2010-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Please report bugs or propose patches to gary@gnu.org.
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# This file is a library for parsing options in your shell scripts along
+# with assorted other useful supporting features that you can make use
+# of too.
+#
+# For the simplest scripts you might need only:
+#
+# #!/bin/sh
+# . relative/path/to/funclib.sh
+# . relative/path/to/options-parser
+# scriptversion=1.0
+# func_options ${1+"$@"}
+# eval set dummy "$func_options_result"; shift
+# ...rest of your script...
+#
+# In order for the '--version' option to work, you will need to have a
+# suitably formatted comment like the one at the top of this file
+# starting with '# Written by ' and ending with '# warranty; '.
+#
+# For '-h' and '--help' to work, you will also need a one line
+# description of your script's purpose in a comment directly above the
+# '# Written by ' line, like the one at the top of this file.
+#
+# The default options also support '--debug', which will turn on shell
+# execution tracing (see the comment above debug_cmd below for another
+# use), and '--verbose' and the func_verbose function to allow your script
+# to display verbose messages only when your user has specified
+# '--verbose'.
+#
+# After sourcing this file, you can plug processing for additional
+# options by amending the variables from the 'Configuration' section
+# below, and following the instructions in the 'Option parsing'
+# section further down.
+
+## -------------- ##
+## Configuration. ##
+## -------------- ##
+
+# You should override these variables in your script after sourcing this
+# file so that they reflect the customisations you have added to the
+# option parser.
+
+# The usage line for option parsing errors and the start of '-h' and
+# '--help' output messages. You can embed shell variables for delayed
+# expansion at the time the message is displayed, but you will need to
+# quote other shell meta-characters carefully to prevent them being
+# expanded when the contents are evaled.
+usage='$progpath [OPTION]...'
+
+# Short help message in response to '-h' and '--help'. Add to this or
+# override it after sourcing this library to reflect the full set of
+# options your script accepts.
+usage_message="\
+ --debug enable verbose shell tracing
+ -W, --warnings=CATEGORY
+ report the warnings falling in CATEGORY [all]
+ -v, --verbose verbosely report processing
+ --version print version information and exit
+ -h, --help print short or long help message and exit
+"
+
+# Additional text appended to 'usage_message' in response to '--help'.
+long_help_message="
+Warning categories include:
+ 'all' show all warnings
+ 'none' turn off all the warnings
+ 'error' warnings are treated as fatal errors"
+
+# Help message printed before fatal option parsing errors.
+fatal_help="Try '\$progname --help' for more information."
+
+
+
+## ------------------------- ##
+## Hook function management. ##
+## ------------------------- ##
+
+# This section contains functions for adding, removing, and running hooks
+# to the main code. A hook is just a named list of of function, that can
+# be run in order later on.
+
+# func_hookable FUNC_NAME
+# -----------------------
+# Declare that FUNC_NAME will run hooks added with
+# 'func_add_hook FUNC_NAME ...'.
+func_hookable ()
+{
+ $debug_cmd
+
+ func_append hookable_fns " $1"
+}
+
+
+# func_add_hook FUNC_NAME HOOK_FUNC
+# ---------------------------------
+# Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must
+# first have been declared "hookable" by a call to 'func_hookable'.
+func_add_hook ()
+{
+ $debug_cmd
+
+ case " $hookable_fns " in
+ *" $1 "*) ;;
+ *) func_fatal_error "'$1' does not accept hook functions." ;;
+ esac
+
+ eval func_append ${1}_hooks '" $2"'
+}
+
+
+# func_remove_hook FUNC_NAME HOOK_FUNC
+# ------------------------------------
+# Remove HOOK_FUNC from the list of functions called by FUNC_NAME.
+func_remove_hook ()
+{
+ $debug_cmd
+
+ eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`'
+}
+
+
+# func_run_hooks FUNC_NAME [ARG]...
+# ---------------------------------
+# Run all hook functions registered to FUNC_NAME.
+# It is assumed that the list of hook functions contains nothing more
+# than a whitespace-delimited list of legal shell function names, and
+# no effort is wasted trying to catch shell meta-characters or preserve
+# whitespace.
+func_run_hooks ()
+{
+ $debug_cmd
+
+ _G_rc_run_hooks=false
+
+ case " $hookable_fns " in
+ *" $1 "*) ;;
+ *) func_fatal_error "'$1' does not support hook funcions.n" ;;
+ esac
+
+ eval _G_hook_fns=\$$1_hooks; shift
+
+ for _G_hook in $_G_hook_fns; do
+ if eval $_G_hook '"$@"'; then
+ # store returned options list back into positional
+ # parameters for next 'cmd' execution.
+ eval _G_hook_result=\$${_G_hook}_result
+ eval set dummy "$_G_hook_result"; shift
+ _G_rc_run_hooks=:
+ fi
+ done
+
+ $_G_rc_run_hooks && func_run_hooks_result=$_G_hook_result
+}
+
+
+
+## --------------- ##
+## Option parsing. ##
+## --------------- ##
+
+# In order to add your own option parsing hooks, you must accept the
+# full positional parameter list in your hook function, you may remove/edit
+# any options that you action, and then pass back the remaining unprocessed
+# options in '<hooked_function_name>_result', escaped suitably for
+# 'eval'. In this case you also must return $EXIT_SUCCESS to let the
+# hook's caller know that it should pay attention to
+# '<hooked_function_name>_result'. Returning $EXIT_FAILURE signalizes that
+# arguments are left untouched by the hook and therefore caller will ignore the
+# result variable.
+#
+# Like this:
+#
+# my_options_prep ()
+# {
+# $debug_cmd
+#
+# # Extend the existing usage message.
+# usage_message=$usage_message'
+# -s, --silent don'\''t print informational messages
+# '
+# # No change in '$@' (ignored completely by this hook). There is
+# # no need to do the equivalent (but slower) action:
+# # func_quote_for_eval ${1+"$@"}
+# # my_options_prep_result=$func_quote_for_eval_result
+# false
+# }
+# func_add_hook func_options_prep my_options_prep
+#
+#
+# my_silent_option ()
+# {
+# $debug_cmd
+#
+# args_changed=false
+#
+# # Note that for efficiency, we parse as many options as we can
+# # recognise in a loop before passing the remainder back to the
+# # caller on the first unrecognised argument we encounter.
+# while test $# -gt 0; do
+# opt=$1; shift
+# case $opt in
+# --silent|-s) opt_silent=:
+# args_changed=:
+# ;;
+# # Separate non-argument short options:
+# -s*) func_split_short_opt "$_G_opt"
+# set dummy "$func_split_short_opt_name" \
+# "-$func_split_short_opt_arg" ${1+"$@"}
+# shift
+# args_changed=:
+# ;;
+# *) # Make sure the first unrecognised option "$_G_opt"
+# # is added back to "$@", we could need that later
+# # if $args_changed is true.
+# set dummy "$_G_opt" ${1+"$@"}; shift; break ;;
+# esac
+# done
+#
+# if $args_changed; then
+# func_quote_for_eval ${1+"$@"}
+# my_silent_option_result=$func_quote_for_eval_result
+# fi
+#
+# $args_changed
+# }
+# func_add_hook func_parse_options my_silent_option
+#
+#
+# my_option_validation ()
+# {
+# $debug_cmd
+#
+# $opt_silent && $opt_verbose && func_fatal_help "\
+# '--silent' and '--verbose' options are mutually exclusive."
+#
+# false
+# }
+# func_add_hook func_validate_options my_option_validation
+#
+# You'll also need to manually amend $usage_message to reflect the extra
+# options you parse. It's preferable to append if you can, so that
+# multiple option parsing hooks can be added safely.
+
+
+# func_options_finish [ARG]...
+# ----------------------------
+# Finishing the option parse loop (call 'func_options' hooks ATM).
+func_options_finish ()
+{
+ $debug_cmd
+
+ _G_func_options_finish_exit=false
+ if func_run_hooks func_options ${1+"$@"}; then
+ func_options_finish_result=$func_run_hooks_result
+ _G_func_options_finish_exit=:
+ fi
+
+ $_G_func_options_finish_exit
+}
+
+
+# func_options [ARG]...
+# ---------------------
+# All the functions called inside func_options are hookable. See the
+# individual implementations for details.
+func_hookable func_options
+func_options ()
+{
+ $debug_cmd
+
+ _G_rc_options=false
+
+ for my_func in options_prep parse_options validate_options options_finish
+ do
+ if eval func_$my_func '${1+"$@"}'; then
+ eval _G_res_var='$'"func_${my_func}_result"
+ eval set dummy "$_G_res_var" ; shift
+ _G_rc_options=:
+ fi
+ done
+
+ # Save modified positional parameters for caller. As a top-level
+ # options-parser function we always need to set the 'func_options_result'
+ # variable (regardless the $_G_rc_options value).
+ if $_G_rc_options; then
+ func_options_result=$_G_res_var
+ else
+ func_quote_for_eval ${1+"$@"}
+ func_options_result=$func_quote_for_eval_result
+ fi
+
+ $_G_rc_options
+}
+
+
+# func_options_prep [ARG]...
+# --------------------------
+# All initialisations required before starting the option parse loop.
+# Note that when calling hook functions, we pass through the list of
+# positional parameters. If a hook function modifies that list, and
+# needs to propagate that back to rest of this script, then the complete
+# modified list must be put in 'func_run_hooks_result' before
+# returning $EXIT_SUCCESS (otherwise $EXIT_FAILURE is returned).
+func_hookable func_options_prep
+func_options_prep ()
+{
+ $debug_cmd
+
+ # Option defaults:
+ opt_verbose=false
+ opt_warning_types=
+
+ _G_rc_options_prep=false
+ if func_run_hooks func_options_prep ${1+"$@"}; then
+ _G_rc_options_prep=:
+ # save modified positional parameters for caller
+ func_options_prep_result=$func_run_hooks_result
+ fi
+
+ $_G_rc_options_prep
+}
+
+
+# func_parse_options [ARG]...
+# ---------------------------
+# The main option parsing loop.
+func_hookable func_parse_options
+func_parse_options ()
+{
+ $debug_cmd
+
+ func_parse_options_result=
+
+ _G_rc_parse_options=false
+ # this just eases exit handling
+ while test $# -gt 0; do
+ # Defer to hook functions for initial option parsing, so they
+ # get priority in the event of reusing an option name.
+ if func_run_hooks func_parse_options ${1+"$@"}; then
+ eval set dummy "$func_run_hooks_result"; shift
+ _G_rc_parse_options=:
+ fi
+
+ # Break out of the loop if we already parsed every option.
+ test $# -gt 0 || break
+
+ _G_match_parse_options=:
+ _G_opt=$1
+ shift
+ case $_G_opt in
+ --debug|-x) debug_cmd='set -x'
+ func_echo "enabling shell trace mode"
+ $debug_cmd
+ ;;
+
+ --no-warnings|--no-warning|--no-warn)
+ set dummy --warnings none ${1+"$@"}
+ shift
+ ;;
+
+ --warnings|--warning|-W)
+ if test $# = 0 && func_missing_arg $_G_opt; then
+ _G_rc_parse_options=:
+ break
+ fi
+ case " $warning_categories $1" in
+ *" $1 "*)
+ # trailing space prevents matching last $1 above
+ func_append_uniq opt_warning_types " $1"
+ ;;
+ *all)
+ opt_warning_types=$warning_categories
+ ;;
+ *none)
+ opt_warning_types=none
+ warning_func=:
+ ;;
+ *error)
+ opt_warning_types=$warning_categories
+ warning_func=func_fatal_error
+ ;;
+ *)
+ func_fatal_error \
+ "unsupported warning category: '$1'"
+ ;;
+ esac
+ shift
+ ;;
+
+ --verbose|-v) opt_verbose=: ;;
+ --version) func_version ;;
+ -\?|-h) func_usage ;;
+ --help) func_help ;;
+
+ # Separate optargs to long options (plugins may need this):
+ --*=*) func_split_equals "$_G_opt"
+ set dummy "$func_split_equals_lhs" \
+ "$func_split_equals_rhs" ${1+"$@"}
+ shift
+ ;;
+
+ # Separate optargs to short options:
+ -W*)
+ func_split_short_opt "$_G_opt"
+ set dummy "$func_split_short_opt_name" \
+ "$func_split_short_opt_arg" ${1+"$@"}
+ shift
+ ;;
+
+ # Separate non-argument short options:
+ -\?*|-h*|-v*|-x*)
+ func_split_short_opt "$_G_opt"
+ set dummy "$func_split_short_opt_name" \
+ "-$func_split_short_opt_arg" ${1+"$@"}
+ shift
+ ;;
+
+ --) _G_rc_parse_options=: ; break ;;
+ -*) func_fatal_help "unrecognised option: '$_G_opt'" ;;
+ *) set dummy "$_G_opt" ${1+"$@"}; shift
+ _G_match_parse_options=false
+ break
+ ;;
+ esac
+
+ $_G_match_parse_options && _G_rc_parse_options=:
+ done
+
+
+ if $_G_rc_parse_options; then
+ # save modified positional parameters for caller
+ func_quote_for_eval ${1+"$@"}
+ func_parse_options_result=$func_quote_for_eval_result
+ fi
+
+ $_G_rc_parse_options
+}
+
+
+# func_validate_options [ARG]...
+# ------------------------------
+# Perform any sanity checks on option settings and/or unconsumed
+# arguments.
+func_hookable func_validate_options
+func_validate_options ()
+{
+ $debug_cmd
+
+ _G_rc_validate_options=false
+
+ # Display all warnings if -W was not given.
+ test -n "$opt_warning_types" || opt_warning_types=" $warning_categories"
+
+ if func_run_hooks func_validate_options ${1+"$@"}; then
+ # save modified positional parameters for caller
+ func_validate_options_result=$func_run_hooks_result
+ _G_rc_validate_options=:
+ fi
+
+ # Bail if the options were screwed!
+ $exit_cmd $EXIT_FAILURE
+
+ $_G_rc_validate_options
+}
+
+
+
+## ----------------- ##
+## Helper functions. ##
+## ----------------- ##
+
+# This section contains the helper functions used by the rest of the
+# hookable option parser framework in ascii-betical order.
+
+
+# func_fatal_help ARG...
+# ----------------------
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+ $debug_cmd
+
+ eval \$ECHO \""Usage: $usage"\"
+ eval \$ECHO \""$fatal_help"\"
+ func_error ${1+"$@"}
+ exit $EXIT_FAILURE
+}
+
+
+# func_help
+# ---------
+# Echo long help message to standard output and exit.
+func_help ()
+{
+ $debug_cmd
+
+ func_usage_message
+ $ECHO "$long_help_message"
+ exit 0
+}
+
+
+# func_missing_arg ARGNAME
+# ------------------------
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+ $debug_cmd
+
+ func_error "Missing argument for '$1'."
+ exit_cmd=exit
+}
+
+
+# func_split_equals STRING
+# ------------------------
+# Set func_split_equals_lhs and func_split_equals_rhs shell variables after
+# splitting STRING at the '=' sign.
+test -z "$_G_HAVE_XSI_OPS" \
+ && (eval 'x=a/b/c;
+ test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
+ && _G_HAVE_XSI_OPS=yes
+
+if test yes = "$_G_HAVE_XSI_OPS"
+then
+ # This is an XSI compatible shell, allowing a faster implementation...
+ eval 'func_split_equals ()
+ {
+ $debug_cmd
+
+ func_split_equals_lhs=${1%%=*}
+ func_split_equals_rhs=${1#*=}
+ test "x$func_split_equals_lhs" = "x$1" \
+ && func_split_equals_rhs=
+ }'
+else
+ # ...otherwise fall back to using expr, which is often a shell builtin.
+ func_split_equals ()
+ {
+ $debug_cmd
+
+ func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'`
+ func_split_equals_rhs=
+ test "x$func_split_equals_lhs" = "x$1" \
+ || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'`
+ }
+fi #func_split_equals
+
+
+# func_split_short_opt SHORTOPT
+# -----------------------------
+# Set func_split_short_opt_name and func_split_short_opt_arg shell
+# variables after splitting SHORTOPT after the 2nd character.
+if test yes = "$_G_HAVE_XSI_OPS"
+then
+ # This is an XSI compatible shell, allowing a faster implementation...
+ eval 'func_split_short_opt ()
+ {
+ $debug_cmd
+
+ func_split_short_opt_arg=${1#??}
+ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}
+ }'
+else
+ # ...otherwise fall back to using expr, which is often a shell builtin.
+ func_split_short_opt ()
+ {
+ $debug_cmd
+
+ func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'`
+ func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'`
+ }
+fi #func_split_short_opt
+
+
+# func_usage
+# ----------
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+ $debug_cmd
+
+ func_usage_message
+ $ECHO "Run '$progname --help |${PAGER-more}' for full usage"
+ exit 0
+}
+
+
+# func_usage_message
+# ------------------
+# Echo short help message to standard output.
+func_usage_message ()
+{
+ $debug_cmd
+
+ eval \$ECHO \""Usage: $usage"\"
+ echo
+ $SED -n 's|^# ||
+ /^Written by/{
+ x;p;x
+ }
+ h
+ /^Written by/q' < "$progpath"
+ echo
+ eval \$ECHO \""$usage_message"\"
+}
+
+
+# func_version
+# ------------
+# Echo version message to standard output and exit.
+func_version ()
+{
+ $debug_cmd
+
+ printf '%s\n' "$progname $scriptversion"
+ $SED -n '
+ /(C)/!b go
+ :more
+ /\./!{
+ N
+ s|\n# | |
+ b more
+ }
+ :go
+ /^# Written by /,/# warranty; / {
+ s|^# ||
+ s|^# *$||
+ s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2|
+ p
+ }
+ /^# Written by / {
+ s|^# ||
+ p
+ }
+ /^warranty; /q' < "$progpath"
+
+ exit $?
+}
+
+
+# Local variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-time-zone: "UTC"
+# End:
+
+# Set a version string.
+scriptversion='(GNU libtool) 2.4.6'
+
+
+# func_echo ARG...
+# ----------------
+# Libtool also displays the current mode in messages, so override
+# funclib.sh func_echo with this custom definition.
+func_echo ()
+{
+ $debug_cmd
+
+ _G_message=$*
+
+ func_echo_IFS=$IFS
+ IFS=$nl
+ for _G_line in $_G_message; do
+ IFS=$func_echo_IFS
+ $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line"
+ done
+ IFS=$func_echo_IFS
+}
+
+
+# func_warning ARG...
+# -------------------
+# Libtool warnings are not categorized, so override funclib.sh
+# func_warning with this simpler definition.
+func_warning ()
+{
+ $debug_cmd
+
+ $warning_func ${1+"$@"}
+}
+
+
+## ---------------- ##
+## Options parsing. ##
+## ---------------- ##
+
+# Hook in the functions to make sure our own options are parsed during
+# the option parsing loop.
+
+usage='$progpath [OPTION]... [MODE-ARG]...'
+
+# Short help message in response to '-h'.
+usage_message="Options:
+ --config show all configuration variables
+ --debug enable verbose shell tracing
+ -n, --dry-run display commands without modifying any files
+ --features display basic configuration information and exit
+ --mode=MODE use operation mode MODE
+ --no-warnings equivalent to '-Wnone'
+ --preserve-dup-deps don't remove duplicate dependency libraries
+ --quiet, --silent don't print informational messages
+ --tag=TAG use configuration variables from tag TAG
+ -v, --verbose print more informational messages than default
+ --version print version information
+ -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all]
+ -h, --help, --help-all print short, long, or detailed help message
+"
+
+# Additional text appended to 'usage_message' in response to '--help'.
+func_help ()
+{
+ $debug_cmd
+
+ func_usage_message
+ $ECHO "$long_help_message
+
+MODE must be one of the following:
+
+ clean remove files from the build directory
+ compile compile a source file into a libtool object
+ execute automatically set library path, then run a program
+ finish complete the installation of libtool libraries
+ install install libraries or executables
+ link create a library or an executable
+ uninstall remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE. When passed as first option,
+'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that.
+Try '$progname --help --mode=MODE' for a more detailed description of MODE.
+
+When reporting a bug, please describe a test case to reproduce it and
+include the following information:
+
+ host-triplet: $host
+ shell: $SHELL
+ compiler: $LTCC
+ compiler flags: $LTCFLAGS
+ linker: $LD (gnu? $with_gnu_ld)
+ version: $progname $scriptversion Debian-2.4.6-15
+ automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q`
+ autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q`
+
+Report bugs to <bug-libtool@gnu.org>.
+GNU libtool home page: <http://www.gnu.org/s/libtool/>.
+General help using GNU software: <http://www.gnu.org/gethelp/>."
+ exit 0
+}
+
+
+# func_lo2o OBJECT-NAME
+# ---------------------
+# Transform OBJECT-NAME from a '.lo' suffix to the platform specific
+# object suffix.
+
+lo2o=s/\\.lo\$/.$objext/
+o2lo=s/\\.$objext\$/.lo/
+
+if test yes = "$_G_HAVE_XSI_OPS"; then
+ eval 'func_lo2o ()
+ {
+ case $1 in
+ *.lo) func_lo2o_result=${1%.lo}.$objext ;;
+ * ) func_lo2o_result=$1 ;;
+ esac
+ }'
+
+ # func_xform LIBOBJ-OR-SOURCE
+ # ---------------------------
+ # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise)
+ # suffix to a '.lo' libtool-object suffix.
+ eval 'func_xform ()
+ {
+ func_xform_result=${1%.*}.lo
+ }'
+else
+ # ...otherwise fall back to using sed.
+ func_lo2o ()
+ {
+ func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"`
+ }
+
+ func_xform ()
+ {
+ func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'`
+ }
+fi
+
+
+# func_fatal_configuration ARG...
+# -------------------------------
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+ func__fatal_error ${1+"$@"} \
+ "See the $PACKAGE documentation for more information." \
+ "Fatal configuration error."
+}
+
+
+# func_config
+# -----------
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+ re_begincf='^# ### BEGIN LIBTOOL'
+ re_endcf='^# ### END LIBTOOL'
+
+ # Default configuration.
+ $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+ # Now print the configurations for the tags.
+ for tagname in $taglist; do
+ $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+ done
+
+ exit $?
+}
+
+
+# func_features
+# -------------
+# Display the features supported by this script.
+func_features ()
+{
+ echo "host: $host"
+ if test yes = "$build_libtool_libs"; then
+ echo "enable shared libraries"
+ else
+ echo "disable shared libraries"
+ fi
+ if test yes = "$build_old_libs"; then
+ echo "enable static libraries"
+ else
+ echo "disable static libraries"
+ fi
+
+ exit $?
+}
+
+
+# func_enable_tag TAGNAME
+# -----------------------
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag. We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+ # Global variable:
+ tagname=$1
+
+ re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+ re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+ sed_extractcf=/$re_begincf/,/$re_endcf/p
+
+ # Validate tagname.
+ case $tagname in
+ *[!-_A-Za-z0-9,/]*)
+ func_fatal_error "invalid tag name: $tagname"
+ ;;
+ esac
+
+ # Don't test for the "default" C tag, as we know it's
+ # there but not specially marked.
+ case $tagname in
+ CC) ;;
+ *)
+ if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+ taglist="$taglist $tagname"
+
+ # Evaluate the configuration. Be careful to quote the path
+ # and the sed script, to avoid splitting on whitespace, but
+ # also don't use non-portable quotes within backquotes within
+ # quotes we have to do it in 2 steps:
+ extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+ eval "$extractedcf"
+ else
+ func_error "ignoring unknown tag $tagname"
+ fi
+ ;;
+ esac
+}
+
+
+# func_check_version_match
+# ------------------------
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+ if test "$package_revision" != "$macro_revision"; then
+ if test "$VERSION" != "$macro_version"; then
+ if test -z "$macro_version"; then
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+ else
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+ fi
+ else
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+ fi
+
+ exit $EXIT_MISMATCH
+ fi
+}
+
+
+# libtool_options_prep [ARG]...
+# -----------------------------
+# Preparation for options parsed by libtool.
+libtool_options_prep ()
+{
+ $debug_mode
+
+ # Option defaults:
+ opt_config=false
+ opt_dlopen=
+ opt_dry_run=false
+ opt_help=false
+ opt_mode=
+ opt_preserve_dup_deps=false
+ opt_quiet=false
+
+ nonopt=
+ preserve_args=
+
+ _G_rc_lt_options_prep=:
+
+ # Shorthand for --mode=foo, only valid as the first argument
+ case $1 in
+ clean|clea|cle|cl)
+ shift; set dummy --mode clean ${1+"$@"}; shift
+ ;;
+ compile|compil|compi|comp|com|co|c)
+ shift; set dummy --mode compile ${1+"$@"}; shift
+ ;;
+ execute|execut|execu|exec|exe|ex|e)
+ shift; set dummy --mode execute ${1+"$@"}; shift
+ ;;
+ finish|finis|fini|fin|fi|f)
+ shift; set dummy --mode finish ${1+"$@"}; shift
+ ;;
+ install|instal|insta|inst|ins|in|i)
+ shift; set dummy --mode install ${1+"$@"}; shift
+ ;;
+ link|lin|li|l)
+ shift; set dummy --mode link ${1+"$@"}; shift
+ ;;
+ uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+ shift; set dummy --mode uninstall ${1+"$@"}; shift
+ ;;
+ *)
+ _G_rc_lt_options_prep=false
+ ;;
+ esac
+
+ if $_G_rc_lt_options_prep; then
+ # Pass back the list of options.
+ func_quote_for_eval ${1+"$@"}
+ libtool_options_prep_result=$func_quote_for_eval_result
+ fi
+
+ $_G_rc_lt_options_prep
+}
+func_add_hook func_options_prep libtool_options_prep
+
+
+# libtool_parse_options [ARG]...
+# ---------------------------------
+# Provide handling for libtool specific options.
+libtool_parse_options ()
+{
+ $debug_cmd
+
+ _G_rc_lt_parse_options=false
+
+ # Perform our own loop to consume as many options as possible in
+ # each iteration.
+ while test $# -gt 0; do
+ _G_match_lt_parse_options=:
+ _G_opt=$1
+ shift
+ case $_G_opt in
+ --dry-run|--dryrun|-n)
+ opt_dry_run=:
+ ;;
+
+ --config) func_config ;;
+
+ --dlopen|-dlopen)
+ opt_dlopen="${opt_dlopen+$opt_dlopen
+}$1"
+ shift
+ ;;
+
+ --preserve-dup-deps)
+ opt_preserve_dup_deps=: ;;
+
+ --features) func_features ;;
+
+ --finish) set dummy --mode finish ${1+"$@"}; shift ;;
+
+ --help) opt_help=: ;;
+
+ --help-all) opt_help=': help-all' ;;
+
+ --mode) test $# = 0 && func_missing_arg $_G_opt && break
+ opt_mode=$1
+ case $1 in
+ # Valid mode arguments:
+ clean|compile|execute|finish|install|link|relink|uninstall) ;;
+
+ # Catch anything else as an error
+ *) func_error "invalid argument for $_G_opt"
+ exit_cmd=exit
+ break
+ ;;
+ esac
+ shift
+ ;;
+
+ --no-silent|--no-quiet)
+ opt_quiet=false
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ --no-warnings|--no-warning|--no-warn)
+ opt_warning=false
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ --no-verbose)
+ opt_verbose=false
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ --silent|--quiet)
+ opt_quiet=:
+ opt_verbose=false
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ --tag) test $# = 0 && func_missing_arg $_G_opt && break
+ opt_tag=$1
+ func_append preserve_args " $_G_opt $1"
+ func_enable_tag "$1"
+ shift
+ ;;
+
+ --verbose|-v) opt_quiet=false
+ opt_verbose=:
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ # An option not handled by this hook function:
+ *) set dummy "$_G_opt" ${1+"$@"} ; shift
+ _G_match_lt_parse_options=false
+ break
+ ;;
+ esac
+ $_G_match_lt_parse_options && _G_rc_lt_parse_options=:
+ done
+
+ if $_G_rc_lt_parse_options; then
+ # save modified positional parameters for caller
+ func_quote_for_eval ${1+"$@"}
+ libtool_parse_options_result=$func_quote_for_eval_result
+ fi
+
+ $_G_rc_lt_parse_options
+}
+func_add_hook func_parse_options libtool_parse_options
+
+
+
+# libtool_validate_options [ARG]...
+# ---------------------------------
+# Perform any sanity checks on option settings and/or unconsumed
+# arguments.
+libtool_validate_options ()
+{
+ # save first non-option argument
+ if test 0 -lt $#; then
+ nonopt=$1
+ shift
+ fi
+
+ # preserve --debug
+ test : = "$debug_cmd" || func_append preserve_args " --debug"
+
+ case $host in
+ # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452
+ # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788
+ *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*)
+ # don't eliminate duplications in $postdeps and $predeps
+ opt_duplicate_compiler_generated_deps=:
+ ;;
+ *)
+ opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
+ ;;
+ esac
+
+ $opt_help || {
+ # Sanity checks first:
+ func_check_version_match
+
+ test yes != "$build_libtool_libs" \
+ && test yes != "$build_old_libs" \
+ && func_fatal_configuration "not configured to build any kind of library"
+
+ # Darwin sucks
+ eval std_shrext=\"$shrext_cmds\"
+
+ # Only execute mode is allowed to have -dlopen flags.
+ if test -n "$opt_dlopen" && test execute != "$opt_mode"; then
+ func_error "unrecognized option '-dlopen'"
+ $ECHO "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Change the help message to a mode-specific one.
+ generic_help=$help
+ help="Try '$progname --help --mode=$opt_mode' for more information."
+ }
+
+ # Pass back the unparsed argument list
+ func_quote_for_eval ${1+"$@"}
+ libtool_validate_options_result=$func_quote_for_eval_result
+}
+func_add_hook func_validate_options libtool_validate_options
+
+
+# Process options as early as possible so that --help and --version
+# can return quickly.
+func_options ${1+"$@"}
+eval set dummy "$func_options_result"; shift
+
+
+
+## ----------- ##
+## Main. ##
+## ----------- ##
+
+magic='%%%MAGIC variable%%%'
+magic_exe='%%%MAGIC EXE variable%%%'
+
+# Global variables.
+extracted_archives=
+extracted_serial=0
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end. This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# func_generated_by_libtool
+# True iff stdin has been generated by Libtool. This function is only
+# a basic sanity check; it will hardly flush out determined imposters.
+func_generated_by_libtool_p ()
+{
+ $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_p file
+# True iff FILE is a libtool '.la' library or '.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+ test -f "$1" &&
+ $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool '.la' library or '.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs. To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway. Works if 'file' does not exist.
+func_lalib_unsafe_p ()
+{
+ lalib_p=no
+ if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+ for lalib_p_l in 1 2 3 4
+ do
+ read lalib_p_line
+ case $lalib_p_line in
+ \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+ esac
+ done
+ exec 0<&5 5<&-
+ fi
+ test yes = "$lalib_p"
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+ test -f "$1" &&
+ $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+ func_ltwrapper_exec_suffix=
+ case $1 in
+ *.exe) ;;
+ *) func_ltwrapper_exec_suffix=.exe ;;
+ esac
+ $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+ func_dirname_and_basename "$1" "" "."
+ func_stripname '' '.exe' "$func_basename_result"
+ func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+ func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+ $debug_cmd
+
+ save_ifs=$IFS; IFS='~'
+ for cmd in $1; do
+ IFS=$sp$nl
+ eval cmd=\"$cmd\"
+ IFS=$save_ifs
+ func_show_eval "$cmd" "${2-:}"
+ done
+ IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)! Also, sourcing
+# 'FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+ $debug_cmd
+
+ case $1 in
+ */* | *\\*) . "$1" ;;
+ *) . "./$1" ;;
+ esac
+}
+
+
+# func_resolve_sysroot PATH
+# Replace a leading = in PATH with a sysroot. Store the result into
+# func_resolve_sysroot_result
+func_resolve_sysroot ()
+{
+ func_resolve_sysroot_result=$1
+ case $func_resolve_sysroot_result in
+ =*)
+ func_stripname '=' '' "$func_resolve_sysroot_result"
+ func_resolve_sysroot_result=$lt_sysroot$func_stripname_result
+ ;;
+ esac
+}
+
+# func_replace_sysroot PATH
+# If PATH begins with the sysroot, replace it with = and
+# store the result into func_replace_sysroot_result.
+func_replace_sysroot ()
+{
+ case $lt_sysroot:$1 in
+ ?*:"$lt_sysroot"*)
+ func_stripname "$lt_sysroot" '' "$1"
+ func_replace_sysroot_result='='$func_stripname_result
+ ;;
+ *)
+ # Including no sysroot.
+ func_replace_sysroot_result=$1
+ ;;
+ esac
+}
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+ $debug_cmd
+
+ if test -n "$available_tags" && test -z "$tagname"; then
+ CC_quoted=
+ for arg in $CC; do
+ func_append_quoted CC_quoted "$arg"
+ done
+ CC_expanded=`func_echo_all $CC`
+ CC_quoted_expanded=`func_echo_all $CC_quoted`
+ case $@ in
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when configure was run.
+ " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+ # Blanks at the start of $base_compile will cause this to fail
+ # if we don't check for them as well.
+ *)
+ for z in $available_tags; do
+ if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+ CC_quoted=
+ for arg in $CC; do
+ # Double-quote args containing other shell metacharacters.
+ func_append_quoted CC_quoted "$arg"
+ done
+ CC_expanded=`func_echo_all $CC`
+ CC_quoted_expanded=`func_echo_all $CC_quoted`
+ case "$@ " in
+ " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+ # The compiler in the base compile command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ func_echo "unable to infer tagged configuration"
+ func_fatal_error "specify a tag with '--tag'"
+# else
+# func_verbose "using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+ write_libobj=$1
+ if test yes = "$build_libtool_libs"; then
+ write_lobj=\'$2\'
+ else
+ write_lobj=none
+ fi
+
+ if test yes = "$build_old_libs"; then
+ write_oldobj=\'$3\'
+ else
+ write_oldobj=none
+ fi
+
+ $opt_dry_run || {
+ cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+ $MV "${write_libobj}T" "$write_libobj"
+ }
+}
+
+
+##################################################
+# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS #
+##################################################
+
+# func_convert_core_file_wine_to_w32 ARG
+# Helper function used by file name conversion functions when $build is *nix,
+# and $host is mingw, cygwin, or some other w32 environment. Relies on a
+# correctly configured wine environment available, with the winepath program
+# in $build's $PATH.
+#
+# ARG is the $build file name to be converted to w32 format.
+# Result is available in $func_convert_core_file_wine_to_w32_result, and will
+# be empty on error (or when ARG is empty)
+func_convert_core_file_wine_to_w32 ()
+{
+ $debug_cmd
+
+ func_convert_core_file_wine_to_w32_result=$1
+ if test -n "$1"; then
+ # Unfortunately, winepath does not exit with a non-zero error code, so we
+ # are forced to check the contents of stdout. On the other hand, if the
+ # command is not found, the shell will set an exit code of 127 and print
+ # *an error message* to stdout. So we must check for both error code of
+ # zero AND non-empty stdout, which explains the odd construction:
+ func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null`
+ if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then
+ func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
+ $SED -e "$sed_naive_backslashify"`
+ else
+ func_convert_core_file_wine_to_w32_result=
+ fi
+ fi
+}
+# end: func_convert_core_file_wine_to_w32
+
+
+# func_convert_core_path_wine_to_w32 ARG
+# Helper function used by path conversion functions when $build is *nix, and
+# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
+# configured wine environment available, with the winepath program in $build's
+# $PATH. Assumes ARG has no leading or trailing path separator characters.
+#
+# ARG is path to be converted from $build format to win32.
+# Result is available in $func_convert_core_path_wine_to_w32_result.
+# Unconvertible file (directory) names in ARG are skipped; if no directory names
+# are convertible, then the result may be empty.
+func_convert_core_path_wine_to_w32 ()
+{
+ $debug_cmd
+
+ # unfortunately, winepath doesn't convert paths, only file names
+ func_convert_core_path_wine_to_w32_result=
+ if test -n "$1"; then
+ oldIFS=$IFS
+ IFS=:
+ for func_convert_core_path_wine_to_w32_f in $1; do
+ IFS=$oldIFS
+ func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
+ if test -n "$func_convert_core_file_wine_to_w32_result"; then
+ if test -z "$func_convert_core_path_wine_to_w32_result"; then
+ func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result
+ else
+ func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
+ fi
+ fi
+ done
+ IFS=$oldIFS
+ fi
+}
+# end: func_convert_core_path_wine_to_w32
+
+
+# func_cygpath ARGS...
+# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when
+# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2)
+# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or
+# (2), returns the Cygwin file name or path in func_cygpath_result (input
+# file name or path is assumed to be in w32 format, as previously converted
+# from $build's *nix or MSYS format). In case (3), returns the w32 file name
+# or path in func_cygpath_result (input file name or path is assumed to be in
+# Cygwin format). Returns an empty string on error.
+#
+# ARGS are passed to cygpath, with the last one being the file name or path to
+# be converted.
+#
+# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH
+# environment variable; do not put it in $PATH.
+func_cygpath ()
+{
+ $debug_cmd
+
+ if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
+ func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
+ if test "$?" -ne 0; then
+ # on failure, ensure result is empty
+ func_cygpath_result=
+ fi
+ else
+ func_cygpath_result=
+ func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'"
+ fi
+}
+#end: func_cygpath
+
+
+# func_convert_core_msys_to_w32 ARG
+# Convert file name or path ARG from MSYS format to w32 format. Return
+# result in func_convert_core_msys_to_w32_result.
+func_convert_core_msys_to_w32 ()
+{
+ $debug_cmd
+
+ # awkward: cmd appends spaces to result
+ func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
+ $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"`
+}
+#end: func_convert_core_msys_to_w32
+
+
+# func_convert_file_check ARG1 ARG2
+# Verify that ARG1 (a file name in $build format) was converted to $host
+# format in ARG2. Otherwise, emit an error message, but continue (resetting
+# func_to_host_file_result to ARG1).
+func_convert_file_check ()
+{
+ $debug_cmd
+
+ if test -z "$2" && test -n "$1"; then
+ func_error "Could not determine host file name corresponding to"
+ func_error " '$1'"
+ func_error "Continuing, but uninstalled executables may not work."
+ # Fallback:
+ func_to_host_file_result=$1
+ fi
+}
+# end func_convert_file_check
+
+
+# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH
+# Verify that FROM_PATH (a path in $build format) was converted to $host
+# format in TO_PATH. Otherwise, emit an error message, but continue, resetting
+# func_to_host_file_result to a simplistic fallback value (see below).
+func_convert_path_check ()
+{
+ $debug_cmd
+
+ if test -z "$4" && test -n "$3"; then
+ func_error "Could not determine the host path corresponding to"
+ func_error " '$3'"
+ func_error "Continuing, but uninstalled executables may not work."
+ # Fallback. This is a deliberately simplistic "conversion" and
+ # should not be "improved". See libtool.info.
+ if test "x$1" != "x$2"; then
+ lt_replace_pathsep_chars="s|$1|$2|g"
+ func_to_host_path_result=`echo "$3" |
+ $SED -e "$lt_replace_pathsep_chars"`
+ else
+ func_to_host_path_result=$3
+ fi
+ fi
+}
+# end func_convert_path_check
+
+
+# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
+# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT
+# and appending REPL if ORIG matches BACKPAT.
+func_convert_path_front_back_pathsep ()
+{
+ $debug_cmd
+
+ case $4 in
+ $1 ) func_to_host_path_result=$3$func_to_host_path_result
+ ;;
+ esac
+ case $4 in
+ $2 ) func_append func_to_host_path_result "$3"
+ ;;
+ esac
+}
+# end func_convert_path_front_back_pathsep
+
+
+##################################################
+# $build to $host FILE NAME CONVERSION FUNCTIONS #
+##################################################
+# invoked via '$to_host_file_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# Result will be available in $func_to_host_file_result.
+
+
+# func_to_host_file ARG
+# Converts the file name ARG from $build format to $host format. Return result
+# in func_to_host_file_result.
+func_to_host_file ()
+{
+ $debug_cmd
+
+ $to_host_file_cmd "$1"
+}
+# end func_to_host_file
+
+
+# func_to_tool_file ARG LAZY
+# converts the file name ARG from $build format to toolchain format. Return
+# result in func_to_tool_file_result. If the conversion in use is listed
+# in (the comma separated) LAZY, no conversion takes place.
+func_to_tool_file ()
+{
+ $debug_cmd
+
+ case ,$2, in
+ *,"$to_tool_file_cmd",*)
+ func_to_tool_file_result=$1
+ ;;
+ *)
+ $to_tool_file_cmd "$1"
+ func_to_tool_file_result=$func_to_host_file_result
+ ;;
+ esac
+}
+# end func_to_tool_file
+
+
+# func_convert_file_noop ARG
+# Copy ARG to func_to_host_file_result.
+func_convert_file_noop ()
+{
+ func_to_host_file_result=$1
+}
+# end func_convert_file_noop
+
+
+# func_convert_file_msys_to_w32 ARG
+# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper. Returns result in
+# func_to_host_file_result.
+func_convert_file_msys_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_file_result=$1
+ if test -n "$1"; then
+ func_convert_core_msys_to_w32 "$1"
+ func_to_host_file_result=$func_convert_core_msys_to_w32_result
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_w32
+
+
+# func_convert_file_cygwin_to_w32 ARG
+# Convert file name ARG from Cygwin to w32 format. Returns result in
+# func_to_host_file_result.
+func_convert_file_cygwin_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_file_result=$1
+ if test -n "$1"; then
+ # because $build is cygwin, we call "the" cygpath in $PATH; no need to use
+ # LT_CYGPATH in this case.
+ func_to_host_file_result=`cygpath -m "$1"`
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_cygwin_to_w32
+
+
+# func_convert_file_nix_to_w32 ARG
+# Convert file name ARG from *nix to w32 format. Requires a wine environment
+# and a working winepath. Returns result in func_to_host_file_result.
+func_convert_file_nix_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_file_result=$1
+ if test -n "$1"; then
+ func_convert_core_file_wine_to_w32 "$1"
+ func_to_host_file_result=$func_convert_core_file_wine_to_w32_result
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_w32
+
+
+# func_convert_file_msys_to_cygwin ARG
+# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_file_msys_to_cygwin ()
+{
+ $debug_cmd
+
+ func_to_host_file_result=$1
+ if test -n "$1"; then
+ func_convert_core_msys_to_w32 "$1"
+ func_cygpath -u "$func_convert_core_msys_to_w32_result"
+ func_to_host_file_result=$func_cygpath_result
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_cygwin
+
+
+# func_convert_file_nix_to_cygwin ARG
+# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed
+# in a wine environment, working winepath, and LT_CYGPATH set. Returns result
+# in func_to_host_file_result.
+func_convert_file_nix_to_cygwin ()
+{
+ $debug_cmd
+
+ func_to_host_file_result=$1
+ if test -n "$1"; then
+ # convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
+ func_convert_core_file_wine_to_w32 "$1"
+ func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
+ func_to_host_file_result=$func_cygpath_result
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_cygwin
+
+
+#############################################
+# $build to $host PATH CONVERSION FUNCTIONS #
+#############################################
+# invoked via '$to_host_path_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# The result will be available in $func_to_host_path_result.
+#
+# Path separators are also converted from $build format to $host format. If
+# ARG begins or ends with a path separator character, it is preserved (but
+# converted to $host format) on output.
+#
+# All path conversion functions are named using the following convention:
+# file name conversion function : func_convert_file_X_to_Y ()
+# path conversion function : func_convert_path_X_to_Y ()
+# where, for any given $build/$host combination the 'X_to_Y' value is the
+# same. If conversion functions are added for new $build/$host combinations,
+# the two new functions must follow this pattern, or func_init_to_host_path_cmd
+# will break.
+
+
+# func_init_to_host_path_cmd
+# Ensures that function "pointer" variable $to_host_path_cmd is set to the
+# appropriate value, based on the value of $to_host_file_cmd.
+to_host_path_cmd=
+func_init_to_host_path_cmd ()
+{
+ $debug_cmd
+
+ if test -z "$to_host_path_cmd"; then
+ func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
+ to_host_path_cmd=func_convert_path_$func_stripname_result
+ fi
+}
+
+
+# func_to_host_path ARG
+# Converts the path ARG from $build format to $host format. Return result
+# in func_to_host_path_result.
+func_to_host_path ()
+{
+ $debug_cmd
+
+ func_init_to_host_path_cmd
+ $to_host_path_cmd "$1"
+}
+# end func_to_host_path
+
+
+# func_convert_path_noop ARG
+# Copy ARG to func_to_host_path_result.
+func_convert_path_noop ()
+{
+ func_to_host_path_result=$1
+}
+# end func_convert_path_noop
+
+
+# func_convert_path_msys_to_w32 ARG
+# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper. Returns result in
+# func_to_host_path_result.
+func_convert_path_msys_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_path_result=$1
+ if test -n "$1"; then
+ # Remove leading and trailing path separator characters from ARG. MSYS
+ # behavior is inconsistent here; cygpath turns them into '.;' and ';.';
+ # and winepath ignores them completely.
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+ func_to_host_path_result=$func_convert_core_msys_to_w32_result
+ func_convert_path_check : ";" \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+ fi
+}
+# end func_convert_path_msys_to_w32
+
+
+# func_convert_path_cygwin_to_w32 ARG
+# Convert path ARG from Cygwin to w32 format. Returns result in
+# func_to_host_file_result.
+func_convert_path_cygwin_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_path_result=$1
+ if test -n "$1"; then
+ # See func_convert_path_msys_to_w32:
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"`
+ func_convert_path_check : ";" \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+ fi
+}
+# end func_convert_path_cygwin_to_w32
+
+
+# func_convert_path_nix_to_w32 ARG
+# Convert path ARG from *nix to w32 format. Requires a wine environment and
+# a working winepath. Returns result in func_to_host_file_result.
+func_convert_path_nix_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_path_result=$1
+ if test -n "$1"; then
+ # See func_convert_path_msys_to_w32:
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+ func_to_host_path_result=$func_convert_core_path_wine_to_w32_result
+ func_convert_path_check : ";" \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+ fi
+}
+# end func_convert_path_nix_to_w32
+
+
+# func_convert_path_msys_to_cygwin ARG
+# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_path_msys_to_cygwin ()
+{
+ $debug_cmd
+
+ func_to_host_path_result=$1
+ if test -n "$1"; then
+ # See func_convert_path_msys_to_w32:
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+ func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
+ func_to_host_path_result=$func_cygpath_result
+ func_convert_path_check : : \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+ fi
+}
+# end func_convert_path_msys_to_cygwin
+
+
+# func_convert_path_nix_to_cygwin ARG
+# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a
+# a wine environment, working winepath, and LT_CYGPATH set. Returns result in
+# func_to_host_file_result.
+func_convert_path_nix_to_cygwin ()
+{
+ $debug_cmd
+
+ func_to_host_path_result=$1
+ if test -n "$1"; then
+ # Remove leading and trailing path separator characters from
+ # ARG. msys behavior is inconsistent here, cygpath turns them
+ # into '.;' and ';.', and winepath ignores them completely.
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+ func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
+ func_to_host_path_result=$func_cygpath_result
+ func_convert_path_check : : \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+ fi
+}
+# end func_convert_path_nix_to_cygwin
+
+
+# func_dll_def_p FILE
+# True iff FILE is a Windows DLL '.def' file.
+# Keep in sync with _LT_DLL_DEF_P in libtool.m4
+func_dll_def_p ()
+{
+ $debug_cmd
+
+ func_dll_def_p_tmp=`$SED -n \
+ -e 's/^[ ]*//' \
+ -e '/^\(;.*\)*$/d' \
+ -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \
+ -e q \
+ "$1"`
+ test DEF = "$func_dll_def_p_tmp"
+}
+
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+ $debug_cmd
+
+ # Get the compilation command and the source file.
+ base_compile=
+ srcfile=$nonopt # always keep a non-empty value in "srcfile"
+ suppress_opt=yes
+ suppress_output=
+ arg_mode=normal
+ libobj=
+ later=
+ pie_flag=
+
+ for arg
+ do
+ case $arg_mode in
+ arg )
+ # do not "continue". Instead, add this to base_compile
+ lastarg=$arg
+ arg_mode=normal
+ ;;
+
+ target )
+ libobj=$arg
+ arg_mode=normal
+ continue
+ ;;
+
+ normal )
+ # Accept any command-line options.
+ case $arg in
+ -o)
+ test -n "$libobj" && \
+ func_fatal_error "you cannot specify '-o' more than once"
+ arg_mode=target
+ continue
+ ;;
+
+ -pie | -fpie | -fPIE)
+ func_append pie_flag " $arg"
+ continue
+ ;;
+
+ -shared | -static | -prefer-pic | -prefer-non-pic)
+ func_append later " $arg"
+ continue
+ ;;
+
+ -no-suppress)
+ suppress_opt=no
+ continue
+ ;;
+
+ -Xcompiler)
+ arg_mode=arg # the next one goes into the "base_compile" arg list
+ continue # The current "srcfile" will either be retained or
+ ;; # replaced later. I would guess that would be a bug.
+
+ -Wc,*)
+ func_stripname '-Wc,' '' "$arg"
+ args=$func_stripname_result
+ lastarg=
+ save_ifs=$IFS; IFS=,
+ for arg in $args; do
+ IFS=$save_ifs
+ func_append_quoted lastarg "$arg"
+ done
+ IFS=$save_ifs
+ func_stripname ' ' '' "$lastarg"
+ lastarg=$func_stripname_result
+
+ # Add the arguments to base_compile.
+ func_append base_compile " $lastarg"
+ continue
+ ;;
+
+ *)
+ # Accept the current argument as the source file.
+ # The previous "srcfile" becomes the current argument.
+ #
+ lastarg=$srcfile
+ srcfile=$arg
+ ;;
+ esac # case $arg
+ ;;
+ esac # case $arg_mode
+
+ # Aesthetically quote the previous argument.
+ func_append_quoted base_compile "$lastarg"
+ done # for arg
+
+ case $arg_mode in
+ arg)
+ func_fatal_error "you must specify an argument for -Xcompile"
+ ;;
+ target)
+ func_fatal_error "you must specify a target with '-o'"
+ ;;
+ *)
+ # Get the name of the library object.
+ test -z "$libobj" && {
+ func_basename "$srcfile"
+ libobj=$func_basename_result
+ }
+ ;;
+ esac
+
+ # Recognize several different file suffixes.
+ # If the user specifies -o file.o, it is replaced with file.lo
+ case $libobj in
+ *.[cCFSifmso] | \
+ *.ada | *.adb | *.ads | *.asm | \
+ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
+ func_xform "$libobj"
+ libobj=$func_xform_result
+ ;;
+ esac
+
+ case $libobj in
+ *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+ *)
+ func_fatal_error "cannot determine name of library object from '$libobj'"
+ ;;
+ esac
+
+ func_infer_tag $base_compile
+
+ for arg in $later; do
+ case $arg in
+ -shared)
+ test yes = "$build_libtool_libs" \
+ || func_fatal_configuration "cannot build a shared library"
+ build_old_libs=no
+ continue
+ ;;
+
+ -static)
+ build_libtool_libs=no
+ build_old_libs=yes
+ continue
+ ;;
+
+ -prefer-pic)
+ pic_mode=yes
+ continue
+ ;;
+
+ -prefer-non-pic)
+ pic_mode=no
+ continue
+ ;;
+ esac
+ done
+
+ func_quote_for_eval "$libobj"
+ test "X$libobj" != "X$func_quote_for_eval_result" \
+ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \
+ && func_warning "libobj name '$libobj' may not contain shell special characters."
+ func_dirname_and_basename "$obj" "/" ""
+ objname=$func_basename_result
+ xdir=$func_dirname_result
+ lobj=$xdir$objdir/$objname
+
+ test -z "$base_compile" && \
+ func_fatal_help "you must specify a compilation command"
+
+ # Delete any leftover library objects.
+ if test yes = "$build_old_libs"; then
+ removelist="$obj $lobj $libobj ${libobj}T"
+ else
+ removelist="$lobj $libobj ${libobj}T"
+ fi
+
+ # On Cygwin there's no "real" PIC flag so we must build both object types
+ case $host_os in
+ cygwin* | mingw* | pw32* | os2* | cegcc*)
+ pic_mode=default
+ ;;
+ esac
+ if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then
+ # non-PIC code in shared libraries is not supported
+ pic_mode=default
+ fi
+
+ # Calculate the filename of the output object if compiler does
+ # not support -o with -c
+ if test no = "$compiler_c_o"; then
+ output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext
+ lockfile=$output_obj.lock
+ else
+ output_obj=
+ need_locks=no
+ lockfile=
+ fi
+
+ # Lock this critical section if it is needed
+ # We use this script file to make the link, it avoids creating a new file
+ if test yes = "$need_locks"; then
+ until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+ func_echo "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ elif test warn = "$need_locks"; then
+ if test -f "$lockfile"; then
+ $ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+ func_append removelist " $output_obj"
+ $ECHO "$srcfile" > "$lockfile"
+ fi
+
+ $opt_dry_run || $RM $removelist
+ func_append removelist " $lockfile"
+ trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+ func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
+ srcfile=$func_to_tool_file_result
+ func_quote_for_eval "$srcfile"
+ qsrcfile=$func_quote_for_eval_result
+
+ # Only build a PIC object if we are building libtool libraries.
+ if test yes = "$build_libtool_libs"; then
+ # Without this assignment, base_compile gets emptied.
+ fbsd_hideous_sh_bug=$base_compile
+
+ if test no != "$pic_mode"; then
+ command="$base_compile $qsrcfile $pic_flag"
+ else
+ # Don't build PIC code
+ command="$base_compile $qsrcfile"
+ fi
+
+ func_mkdir_p "$xdir$objdir"
+
+ if test -z "$output_obj"; then
+ # Place PIC objects in $objdir
+ func_append command " -o $lobj"
+ fi
+
+ func_show_eval_locale "$command" \
+ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+ if test warn = "$need_locks" &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed, then go on to compile the next one
+ if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+ func_show_eval '$MV "$output_obj" "$lobj"' \
+ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+ fi
+
+ # Allow error messages only from the first compilation.
+ if test yes = "$suppress_opt"; then
+ suppress_output=' >/dev/null 2>&1'
+ fi
+ fi
+
+ # Only build a position-dependent object if we build old libraries.
+ if test yes = "$build_old_libs"; then
+ if test yes != "$pic_mode"; then
+ # Don't build PIC code
+ command="$base_compile $qsrcfile$pie_flag"
+ else
+ command="$base_compile $qsrcfile $pic_flag"
+ fi
+ if test yes = "$compiler_c_o"; then
+ func_append command " -o $obj"
+ fi
+
+ # Suppress compiler output if we already did a PIC compilation.
+ func_append command "$suppress_output"
+ func_show_eval_locale "$command" \
+ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+ if test warn = "$need_locks" &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed
+ if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+ func_show_eval '$MV "$output_obj" "$obj"' \
+ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+ fi
+ fi
+
+ $opt_dry_run || {
+ func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+ # Unlock the critical section if it was locked
+ if test no != "$need_locks"; then
+ removelist=$lockfile
+ $RM "$lockfile"
+ fi
+ }
+
+ exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+ test compile = "$opt_mode" && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+ # We need to display help for each of the modes.
+ case $opt_mode in
+ "")
+ # Generic help is extracted from the usage comments
+ # at the start of this file.
+ func_help
+ ;;
+
+ clean)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+ compile)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+ -o OUTPUT-FILE set the output file name to OUTPUT-FILE
+ -no-suppress do not suppress compiler output for multiple passes
+ -prefer-pic try to build PIC objects only
+ -prefer-non-pic try to build non-PIC objects only
+ -shared do not build a '.o' file suitable for static linking
+ -static only build a '.o' file suitable for static linking
+ -Wc,FLAG pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a 'standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix '.c' with the
+library object suffix, '.lo'."
+ ;;
+
+ execute)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+ -dlopen FILE add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to '-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+ ;;
+
+ finish)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges. Use
+the '--dry-run' option if you just want to see what would be executed."
+ ;;
+
+ install)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command. The first component should be
+either the 'install' or 'cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+ -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+ ;;
+
+ link)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+ -all-static do not do any dynamic linking at all
+ -avoid-version do not add a version suffix if possible
+ -bindir BINDIR specify path to binaries directory (for systems where
+ libraries must be found in the PATH setting at runtime)
+ -dlopen FILE '-dlpreopen' FILE if it cannot be dlopened at runtime
+ -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
+ -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+ -export-symbols SYMFILE
+ try to export only the symbols listed in SYMFILE
+ -export-symbols-regex REGEX
+ try to export only the symbols matching REGEX
+ -LLIBDIR search LIBDIR for required installed libraries
+ -lNAME OUTPUT-FILE requires the installed library libNAME
+ -module build a library that can dlopened
+ -no-fast-install disable the fast-install mode
+ -no-install link a not-installable executable
+ -no-undefined declare that a library does not refer to external symbols
+ -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
+ -objectlist FILE use a list of object files found in FILE to specify objects
+ -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes)
+ -precious-files-regex REGEX
+ don't remove output files matching REGEX
+ -release RELEASE specify package release information
+ -rpath LIBDIR the created library will eventually be installed in LIBDIR
+ -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
+ -shared only do dynamic linking of libtool libraries
+ -shrext SUFFIX override the standard shared library file extension
+ -static do not do any dynamic linking of uninstalled libtool libraries
+ -static-libtool-libs
+ do not do any dynamic linking of libtool libraries
+ -version-info CURRENT[:REVISION[:AGE]]
+ specify library version info [each variable defaults to 0]
+ -weak LIBNAME declare that the target provides the LIBNAME interface
+ -Wc,FLAG
+ -Xcompiler FLAG pass linker-specific FLAG directly to the compiler
+ -Wl,FLAG
+ -Xlinker FLAG pass linker-specific FLAG directly to the linker
+ -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with '-') are ignored.
+
+Every other argument is treated as a filename. Files ending in '.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in '.la', then a libtool library is created,
+only library objects ('.lo' files) may be specified, and '-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created
+using 'ar' and 'ranlib', or on Windows using 'lib'.
+
+If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file
+is created, otherwise an executable program is created."
+ ;;
+
+ uninstall)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+ *)
+ func_fatal_help "invalid operation mode '$opt_mode'"
+ ;;
+ esac
+
+ echo
+ $ECHO "Try '$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+ if test : = "$opt_help"; then
+ func_mode_help
+ else
+ {
+ func_help noexit
+ for opt_mode in compile link execute install finish uninstall clean; do
+ func_mode_help
+ done
+ } | $SED -n '1p; 2,$s/^Usage:/ or: /p'
+ {
+ func_help noexit
+ for opt_mode in compile link execute install finish uninstall clean; do
+ echo
+ func_mode_help
+ done
+ } |
+ $SED '1d
+ /^When reporting/,/^Report/{
+ H
+ d
+ }
+ $x
+ /information about other modes/d
+ /more detailed .*MODE/d
+ s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+ fi
+ exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+ $debug_cmd
+
+ # The first argument is the command name.
+ cmd=$nonopt
+ test -z "$cmd" && \
+ func_fatal_help "you must specify a COMMAND"
+
+ # Handle -dlopen flags immediately.
+ for file in $opt_dlopen; do
+ test -f "$file" \
+ || func_fatal_help "'$file' is not a file"
+
+ dir=
+ case $file in
+ *.la)
+ func_resolve_sysroot "$file"
+ file=$func_resolve_sysroot_result
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$file" \
+ || func_fatal_help "'$lib' is not a valid libtool archive"
+
+ # Read the libtool library.
+ dlname=
+ library_names=
+ func_source "$file"
+
+ # Skip this library if it cannot be dlopened.
+ if test -z "$dlname"; then
+ # Warn if it was a shared library.
+ test -n "$library_names" && \
+ func_warning "'$file' was not linked with '-export-dynamic'"
+ continue
+ fi
+
+ func_dirname "$file" "" "."
+ dir=$func_dirname_result
+
+ if test -f "$dir/$objdir/$dlname"; then
+ func_append dir "/$objdir"
+ else
+ if test ! -f "$dir/$dlname"; then
+ func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'"
+ fi
+ fi
+ ;;
+
+ *.lo)
+ # Just add the directory containing the .lo file.
+ func_dirname "$file" "" "."
+ dir=$func_dirname_result
+ ;;
+
+ *)
+ func_warning "'-dlopen' is ignored for non-libtool libraries and objects"
+ continue
+ ;;
+ esac
+
+ # Get the absolute pathname.
+ absdir=`cd "$dir" && pwd`
+ test -n "$absdir" && dir=$absdir
+
+ # Now add the directory to shlibpath_var.
+ if eval "test -z \"\$$shlibpath_var\""; then
+ eval "$shlibpath_var=\"\$dir\""
+ else
+ eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+ fi
+ done
+
+ # This variable tells wrapper scripts just to set shlibpath_var
+ # rather than running their programs.
+ libtool_execute_magic=$magic
+
+ # Check if any of the arguments is a wrapper script.
+ args=
+ for file
+ do
+ case $file in
+ -* | *.la | *.lo ) ;;
+ *)
+ # Do a test to see if this is really a libtool program.
+ if func_ltwrapper_script_p "$file"; then
+ func_source "$file"
+ # Transform arg to wrapped name.
+ file=$progdir/$program
+ elif func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ func_source "$func_ltwrapper_scriptname_result"
+ # Transform arg to wrapped name.
+ file=$progdir/$program
+ fi
+ ;;
+ esac
+ # Quote arguments (to preserve shell metacharacters).
+ func_append_quoted args "$file"
+ done
+
+ if $opt_dry_run; then
+ # Display what would be done.
+ if test -n "$shlibpath_var"; then
+ eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+ echo "export $shlibpath_var"
+ fi
+ $ECHO "$cmd$args"
+ exit $EXIT_SUCCESS
+ else
+ if test -n "$shlibpath_var"; then
+ # Export the shlibpath_var.
+ eval "export $shlibpath_var"
+ fi
+
+ # Restore saved environment variables
+ for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+ do
+ eval "if test \"\${save_$lt_var+set}\" = set; then
+ $lt_var=\$save_$lt_var; export $lt_var
+ else
+ $lt_unset $lt_var
+ fi"
+ done
+
+ # Now prepare to actually exec the command.
+ exec_cmd=\$cmd$args
+ fi
+}
+
+test execute = "$opt_mode" && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+ $debug_cmd
+
+ libs=
+ libdirs=
+ admincmds=
+
+ for opt in "$nonopt" ${1+"$@"}
+ do
+ if test -d "$opt"; then
+ func_append libdirs " $opt"
+
+ elif test -f "$opt"; then
+ if func_lalib_unsafe_p "$opt"; then
+ func_append libs " $opt"
+ else
+ func_warning "'$opt' is not a valid libtool archive"
+ fi
+
+ else
+ func_fatal_error "invalid argument '$opt'"
+ fi
+ done
+
+ if test -n "$libs"; then
+ if test -n "$lt_sysroot"; then
+ sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"`
+ sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;"
+ else
+ sysroot_cmd=
+ fi
+
+ # Remove sysroot references
+ if $opt_dry_run; then
+ for lib in $libs; do
+ echo "removing references to $lt_sysroot and '=' prefixes from $lib"
+ done
+ else
+ tmpdir=`func_mktempdir`
+ for lib in $libs; do
+ $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
+ > $tmpdir/tmp-la
+ mv -f $tmpdir/tmp-la $lib
+ done
+ ${RM}r "$tmpdir"
+ fi
+ fi
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ for libdir in $libdirs; do
+ if test -n "$finish_cmds"; then
+ # Do each command in the finish commands.
+ func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+ fi
+ if test -n "$finish_eval"; then
+ # Do the single finish_eval.
+ eval cmds=\"$finish_eval\"
+ $opt_dry_run || eval "$cmds" || func_append admincmds "
+ $cmds"
+ fi
+ done
+ fi
+
+ # Exit here if they wanted silent mode.
+ $opt_quiet && exit $EXIT_SUCCESS
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ echo "----------------------------------------------------------------------"
+ echo "Libraries have been installed in:"
+ for libdir in $libdirs; do
+ $ECHO " $libdir"
+ done
+ echo
+ echo "If you ever happen to want to link against installed libraries"
+ echo "in a given directory, LIBDIR, you must either use libtool, and"
+ echo "specify the full pathname of the library, or use the '-LLIBDIR'"
+ echo "flag during linking and do at least one of the following:"
+ if test -n "$shlibpath_var"; then
+ echo " - add LIBDIR to the '$shlibpath_var' environment variable"
+ echo " during execution"
+ fi
+ if test -n "$runpath_var"; then
+ echo " - add LIBDIR to the '$runpath_var' environment variable"
+ echo " during linking"
+ fi
+ if test -n "$hardcode_libdir_flag_spec"; then
+ libdir=LIBDIR
+ eval flag=\"$hardcode_libdir_flag_spec\"
+
+ $ECHO " - use the '$flag' linker flag"
+ fi
+ if test -n "$admincmds"; then
+ $ECHO " - have your system administrator run these commands:$admincmds"
+ fi
+ if test -f /etc/ld.so.conf; then
+ echo " - have your system administrator add LIBDIR to '/etc/ld.so.conf'"
+ fi
+ echo
+
+ echo "See any operating system documentation about shared libraries for"
+ case $host in
+ solaris2.[6789]|solaris2.1[0-9])
+ echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+ echo "pages."
+ ;;
+ *)
+ echo "more information, such as the ld(1) and ld.so(8) manual pages."
+ ;;
+ esac
+ echo "----------------------------------------------------------------------"
+ fi
+ exit $EXIT_SUCCESS
+}
+
+test finish = "$opt_mode" && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+ $debug_cmd
+
+ # There may be an optional sh(1) argument at the beginning of
+ # install_prog (especially on Windows NT).
+ if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" ||
+ # Allow the use of GNU shtool's install command.
+ case $nonopt in *shtool*) :;; *) false;; esac
+ then
+ # Aesthetically quote it.
+ func_quote_for_eval "$nonopt"
+ install_prog="$func_quote_for_eval_result "
+ arg=$1
+ shift
+ else
+ install_prog=
+ arg=$nonopt
+ fi
+
+ # The real first argument should be the name of the installation program.
+ # Aesthetically quote it.
+ func_quote_for_eval "$arg"
+ func_append install_prog "$func_quote_for_eval_result"
+ install_shared_prog=$install_prog
+ case " $install_prog " in
+ *[\\\ /]cp\ *) install_cp=: ;;
+ *) install_cp=false ;;
+ esac
+
+ # We need to accept at least all the BSD install flags.
+ dest=
+ files=
+ opts=
+ prev=
+ install_type=
+ isdir=false
+ stripme=
+ no_mode=:
+ for arg
+ do
+ arg2=
+ if test -n "$dest"; then
+ func_append files " $dest"
+ dest=$arg
+ continue
+ fi
+
+ case $arg in
+ -d) isdir=: ;;
+ -f)
+ if $install_cp; then :; else
+ prev=$arg
+ fi
+ ;;
+ -g | -m | -o)
+ prev=$arg
+ ;;
+ -s)
+ stripme=" -s"
+ continue
+ ;;
+ -*)
+ ;;
+ *)
+ # If the previous option needed an argument, then skip it.
+ if test -n "$prev"; then
+ if test X-m = "X$prev" && test -n "$install_override_mode"; then
+ arg2=$install_override_mode
+ no_mode=false
+ fi
+ prev=
+ else
+ dest=$arg
+ continue
+ fi
+ ;;
+ esac
+
+ # Aesthetically quote the argument.
+ func_quote_for_eval "$arg"
+ func_append install_prog " $func_quote_for_eval_result"
+ if test -n "$arg2"; then
+ func_quote_for_eval "$arg2"
+ fi
+ func_append install_shared_prog " $func_quote_for_eval_result"
+ done
+
+ test -z "$install_prog" && \
+ func_fatal_help "you must specify an install program"
+
+ test -n "$prev" && \
+ func_fatal_help "the '$prev' option requires an argument"
+
+ if test -n "$install_override_mode" && $no_mode; then
+ if $install_cp; then :; else
+ func_quote_for_eval "$install_override_mode"
+ func_append install_shared_prog " -m $func_quote_for_eval_result"
+ fi
+ fi
+
+ if test -z "$files"; then
+ if test -z "$dest"; then
+ func_fatal_help "no file or destination specified"
+ else
+ func_fatal_help "you must specify a destination"
+ fi
+ fi
+
+ # Strip any trailing slash from the destination.
+ func_stripname '' '/' "$dest"
+ dest=$func_stripname_result
+
+ # Check to see that the destination is a directory.
+ test -d "$dest" && isdir=:
+ if $isdir; then
+ destdir=$dest
+ destname=
+ else
+ func_dirname_and_basename "$dest" "" "."
+ destdir=$func_dirname_result
+ destname=$func_basename_result
+
+ # Not a directory, so check to see that there is only one file specified.
+ set dummy $files; shift
+ test "$#" -gt 1 && \
+ func_fatal_help "'$dest' is not a directory"
+ fi
+ case $destdir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ for file in $files; do
+ case $file in
+ *.lo) ;;
+ *)
+ func_fatal_help "'$destdir' must be an absolute directory name"
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic=$magic
+
+ staticlibs=
+ future_libdirs=
+ current_libdirs=
+ for file in $files; do
+
+ # Do each installation.
+ case $file in
+ *.$libext)
+ # Do the static libraries later.
+ func_append staticlibs " $file"
+ ;;
+
+ *.la)
+ func_resolve_sysroot "$file"
+ file=$func_resolve_sysroot_result
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$file" \
+ || func_fatal_help "'$file' is not a valid libtool archive"
+
+ library_names=
+ old_library=
+ relink_command=
+ func_source "$file"
+
+ # Add the libdir to current_libdirs if it is the destination.
+ if test "X$destdir" = "X$libdir"; then
+ case "$current_libdirs " in
+ *" $libdir "*) ;;
+ *) func_append current_libdirs " $libdir" ;;
+ esac
+ else
+ # Note the libdir as a future libdir.
+ case "$future_libdirs " in
+ *" $libdir "*) ;;
+ *) func_append future_libdirs " $libdir" ;;
+ esac
+ fi
+
+ func_dirname "$file" "/" ""
+ dir=$func_dirname_result
+ func_append dir "$objdir"
+
+ if test -n "$relink_command"; then
+ # Determine the prefix the user has applied to our future dir.
+ inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+ # Don't allow the user to place us outside of our expected
+ # location b/c this prevents finding dependent libraries that
+ # are installed to the same prefix.
+ # At present, this check doesn't affect windows .dll's that
+ # are installed into $libdir/../bin (currently, that works fine)
+ # but it's something to keep an eye on.
+ test "$inst_prefix_dir" = "$destdir" && \
+ func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir"
+
+ if test -n "$inst_prefix_dir"; then
+ # Stick the inst_prefix_dir data into the link command.
+ relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+ else
+ relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+ fi
+
+ func_warning "relinking '$file'"
+ func_show_eval "$relink_command" \
+ 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"'
+ fi
+
+ # See the names of the shared library.
+ set dummy $library_names; shift
+ if test -n "$1"; then
+ realname=$1
+ shift
+
+ srcname=$realname
+ test -n "$relink_command" && srcname=${realname}T
+
+ # Install the shared library and build the symlinks.
+ func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+ 'exit $?'
+ tstripme=$stripme
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ case $realname in
+ *.dll.a)
+ tstripme=
+ ;;
+ esac
+ ;;
+ os2*)
+ case $realname in
+ *_dll.a)
+ tstripme=
+ ;;
+ esac
+ ;;
+ esac
+ if test -n "$tstripme" && test -n "$striplib"; then
+ func_show_eval "$striplib $destdir/$realname" 'exit $?'
+ fi
+
+ if test "$#" -gt 0; then
+ # Delete the old symlinks, and create new ones.
+ # Try 'ln -sf' first, because the 'ln' binary might depend on
+ # the symlink we replace! Solaris /bin/ln does not understand -f,
+ # so we also need to try rm && ln -s.
+ for linkname
+ do
+ test "$linkname" != "$realname" \
+ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+ done
+ fi
+
+ # Do each command in the postinstall commands.
+ lib=$destdir/$realname
+ func_execute_cmds "$postinstall_cmds" 'exit $?'
+ fi
+
+ # Install the pseudo-library for information purposes.
+ func_basename "$file"
+ name=$func_basename_result
+ instname=$dir/${name}i
+ func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+ # Maybe install the static library, too.
+ test -n "$old_library" && func_append staticlibs " $dir/$old_library"
+ ;;
+
+ *.lo)
+ # Install (i.e. copy) a libtool object.
+
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile=$destdir/$destname
+ else
+ func_basename "$file"
+ destfile=$func_basename_result
+ destfile=$destdir/$destfile
+ fi
+
+ # Deduce the name of the destination old-style object file.
+ case $destfile in
+ *.lo)
+ func_lo2o "$destfile"
+ staticdest=$func_lo2o_result
+ ;;
+ *.$objext)
+ staticdest=$destfile
+ destfile=
+ ;;
+ *)
+ func_fatal_help "cannot copy a libtool object to '$destfile'"
+ ;;
+ esac
+
+ # Install the libtool object if requested.
+ test -n "$destfile" && \
+ func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+ # Install the old object if enabled.
+ if test yes = "$build_old_libs"; then
+ # Deduce the name of the old-style object file.
+ func_lo2o "$file"
+ staticobj=$func_lo2o_result
+ func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+ fi
+ exit $EXIT_SUCCESS
+ ;;
+
+ *)
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile=$destdir/$destname
+ else
+ func_basename "$file"
+ destfile=$func_basename_result
+ destfile=$destdir/$destfile
+ fi
+
+ # If the file is missing, and there is a .exe on the end, strip it
+ # because it is most likely a libtool script we actually want to
+ # install
+ stripped_ext=
+ case $file in
+ *.exe)
+ if test ! -f "$file"; then
+ func_stripname '' '.exe' "$file"
+ file=$func_stripname_result
+ stripped_ext=.exe
+ fi
+ ;;
+ esac
+
+ # Do a test to see if this is really a libtool program.
+ case $host in
+ *cygwin* | *mingw*)
+ if func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ wrapper=$func_ltwrapper_scriptname_result
+ else
+ func_stripname '' '.exe' "$file"
+ wrapper=$func_stripname_result
+ fi
+ ;;
+ *)
+ wrapper=$file
+ ;;
+ esac
+ if func_ltwrapper_script_p "$wrapper"; then
+ notinst_deplibs=
+ relink_command=
+
+ func_source "$wrapper"
+
+ # Check the variables that should have been set.
+ test -z "$generated_by_libtool_version" && \
+ func_fatal_error "invalid libtool wrapper script '$wrapper'"
+
+ finalize=:
+ for lib in $notinst_deplibs; do
+ # Check to see that each library is installed.
+ libdir=
+ if test -f "$lib"; then
+ func_source "$lib"
+ fi
+ libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'`
+ if test -n "$libdir" && test ! -f "$libfile"; then
+ func_warning "'$lib' has not been installed in '$libdir'"
+ finalize=false
+ fi
+ done
+
+ relink_command=
+ func_source "$wrapper"
+
+ outputname=
+ if test no = "$fast_install" && test -n "$relink_command"; then
+ $opt_dry_run || {
+ if $finalize; then
+ tmpdir=`func_mktempdir`
+ func_basename "$file$stripped_ext"
+ file=$func_basename_result
+ outputname=$tmpdir/$file
+ # Replace the output file specification.
+ relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+ $opt_quiet || {
+ func_quote_for_expand "$relink_command"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ if eval "$relink_command"; then :
+ else
+ func_error "error: relink '$file' with the above command before installing it"
+ $opt_dry_run || ${RM}r "$tmpdir"
+ continue
+ fi
+ file=$outputname
+ else
+ func_warning "cannot relink '$file'"
+ fi
+ }
+ else
+ # Install the binary that we compiled earlier.
+ file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+ fi
+ fi
+
+ # remove .exe since cygwin /usr/bin/install will append another
+ # one anyway
+ case $install_prog,$host in
+ */usr/bin/install*,*cygwin*)
+ case $file:$destfile in
+ *.exe:*.exe)
+ # this is ok
+ ;;
+ *.exe:*)
+ destfile=$destfile.exe
+ ;;
+ *:*.exe)
+ func_stripname '' '.exe' "$destfile"
+ destfile=$func_stripname_result
+ ;;
+ esac
+ ;;
+ esac
+ func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+ $opt_dry_run || if test -n "$outputname"; then
+ ${RM}r "$tmpdir"
+ fi
+ ;;
+ esac
+ done
+
+ for file in $staticlibs; do
+ func_basename "$file"
+ name=$func_basename_result
+
+ # Set up the ranlib parameters.
+ oldlib=$destdir/$name
+ func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+ tool_oldlib=$func_to_tool_file_result
+
+ func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+ if test -n "$stripme" && test -n "$old_striplib"; then
+ func_show_eval "$old_striplib $tool_oldlib" 'exit $?'
+ fi
+
+ # Do each command in the postinstall commands.
+ func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+ done
+
+ test -n "$future_libdirs" && \
+ func_warning "remember to run '$progname --finish$future_libdirs'"
+
+ if test -n "$current_libdirs"; then
+ # Maybe just do a dry run.
+ $opt_dry_run && current_libdirs=" -n$current_libdirs"
+ exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs'
+ else
+ exit $EXIT_SUCCESS
+ fi
+}
+
+test install = "$opt_mode" && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+ $debug_cmd
+
+ my_outputname=$1
+ my_originator=$2
+ my_pic_p=${3-false}
+ my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'`
+ my_dlsyms=
+
+ if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+ if test -n "$NM" && test -n "$global_symbol_pipe"; then
+ my_dlsyms=${my_outputname}S.c
+ else
+ func_error "not configured to extract global symbols from dlpreopened files"
+ fi
+ fi
+
+ if test -n "$my_dlsyms"; then
+ case $my_dlsyms in
+ "") ;;
+ *.c)
+ # Discover the nlist of each of the dlfiles.
+ nlist=$output_objdir/$my_outputname.nm
+
+ func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+ # Parse the name list into a source file.
+ func_verbose "creating $output_objdir/$my_dlsyms"
+
+ $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
+ relocations are performed -- see ld's documentation on pseudo-relocs. */
+# define LT_DLSYM_CONST
+#elif defined __osf__
+/* This system does not cope well with relocations in const data. */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
+
+/* External symbol declarations for the compiler. */\
+"
+
+ if test yes = "$dlself"; then
+ func_verbose "generating symbol list for '$output'"
+
+ $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+ # Add our own program objects to the symbol list.
+ progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ for progfile in $progfiles; do
+ func_to_tool_file "$progfile" func_convert_file_msys_to_w32
+ func_verbose "extracting global C symbols from '$func_to_tool_file_result'"
+ $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -n "$exclude_expsyms"; then
+ $opt_dry_run || {
+ eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ }
+ fi
+
+ if test -n "$export_symbols_regex"; then
+ $opt_dry_run || {
+ eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ }
+ fi
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ export_symbols=$output_objdir/$outputname.exp
+ $opt_dry_run || {
+ $RM $export_symbols
+ eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ }
+ else
+ $opt_dry_run || {
+ eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+ eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ }
+ fi
+ fi
+
+ for dlprefile in $dlprefiles; do
+ func_verbose "extracting global C symbols from '$dlprefile'"
+ func_basename "$dlprefile"
+ name=$func_basename_result
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ # if an import library, we need to obtain dlname
+ if func_win32_import_lib_p "$dlprefile"; then
+ func_tr_sh "$dlprefile"
+ eval "curr_lafile=\$libfile_$func_tr_sh_result"
+ dlprefile_dlbasename=
+ if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
+ # Use subshell, to avoid clobbering current variable values
+ dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
+ if test -n "$dlprefile_dlname"; then
+ func_basename "$dlprefile_dlname"
+ dlprefile_dlbasename=$func_basename_result
+ else
+ # no lafile. user explicitly requested -dlpreopen <import library>.
+ $sharedlib_from_linklib_cmd "$dlprefile"
+ dlprefile_dlbasename=$sharedlib_from_linklib_result
+ fi
+ fi
+ $opt_dry_run || {
+ if test -n "$dlprefile_dlbasename"; then
+ eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
+ else
+ func_warning "Could not compute DLL name from $name"
+ eval '$ECHO ": $name " >> "$nlist"'
+ fi
+ func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+ eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe |
+ $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
+ }
+ else # not an import lib
+ $opt_dry_run || {
+ eval '$ECHO ": $name " >> "$nlist"'
+ func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+ eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+ }
+ fi
+ ;;
+ *)
+ $opt_dry_run || {
+ eval '$ECHO ": $name " >> "$nlist"'
+ func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+ eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+ }
+ ;;
+ esac
+ done
+
+ $opt_dry_run || {
+ # Make sure we have at least an empty file.
+ test -f "$nlist" || : > "$nlist"
+
+ if test -n "$exclude_expsyms"; then
+ $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+ $MV "$nlist"T "$nlist"
+ fi
+
+ # Try sorting and uniquifying the output.
+ if $GREP -v "^: " < "$nlist" |
+ if sort -k 3 </dev/null >/dev/null 2>&1; then
+ sort -k 3
+ else
+ sort +2
+ fi |
+ uniq > "$nlist"S; then
+ :
+ else
+ $GREP -v "^: " < "$nlist" > "$nlist"S
+ fi
+
+ if test -f "$nlist"S; then
+ eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+ else
+ echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+ fi
+
+ func_show_eval '$RM "${nlist}I"'
+ if test -n "$global_symbol_to_import"; then
+ eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I'
+ fi
+
+ echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols. */
+typedef struct {
+ const char *name;
+ void *address;
+} lt_dlsymlist;
+extern LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];\
+"
+
+ if test -s "$nlist"I; then
+ echo >> "$output_objdir/$my_dlsyms" "\
+static void lt_syminit(void)
+{
+ LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols;
+ for (; symbol->name; ++symbol)
+ {"
+ $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms"
+ echo >> "$output_objdir/$my_dlsyms" "\
+ }
+}"
+ fi
+ echo >> "$output_objdir/$my_dlsyms" "\
+LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{ {\"$my_originator\", (void *) 0},"
+
+ if test -s "$nlist"I; then
+ echo >> "$output_objdir/$my_dlsyms" "\
+ {\"@INIT@\", (void *) &lt_syminit},"
+ fi
+
+ case $need_lib_prefix in
+ no)
+ eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+ ;;
+ *)
+ eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+ ;;
+ esac
+ echo >> "$output_objdir/$my_dlsyms" "\
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+ } # !$opt_dry_run
+
+ pic_flag_for_symtable=
+ case "$compile_command " in
+ *" -static "*) ;;
+ *)
+ case $host in
+ # compiling the symbol table file with pic_flag works around
+ # a FreeBSD bug that causes programs to crash when -lm is
+ # linked before any other PIC object. But we must not use
+ # pic_flag when linking with -static. The problem exists in
+ # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+ *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+ pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+ *-*-hpux*)
+ pic_flag_for_symtable=" $pic_flag" ;;
+ *)
+ $my_pic_p && pic_flag_for_symtable=" $pic_flag"
+ ;;
+ esac
+ ;;
+ esac
+ symtab_cflags=
+ for arg in $LTCFLAGS; do
+ case $arg in
+ -pie | -fpie | -fPIE) ;;
+ *) func_append symtab_cflags " $arg" ;;
+ esac
+ done
+
+ # Now compile the dynamic symbol file.
+ func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+ # Clean up the generated files.
+ func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"'
+
+ # Transform the symbol file into the correct name.
+ symfileobj=$output_objdir/${my_outputname}S.$objext
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ if test -f "$output_objdir/$my_outputname.def"; then
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+ else
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ fi
+ ;;
+ *)
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ ;;
+ esac
+ ;;
+ *)
+ func_fatal_error "unknown suffix for '$my_dlsyms'"
+ ;;
+ esac
+ else
+ # We keep going just in case the user didn't refer to
+ # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
+ # really was required.
+
+ # Nullify the symbol file.
+ compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+ fi
+}
+
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+ $debug_cmd
+
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
+ test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+ $debug_cmd
+
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
+ test -n "$func_cygming_ms_implib_tmp"
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+ $debug_cmd
+
+ win32_libid_type=unknown
+ win32_fileres=`file -L $1 2>/dev/null`
+ case $win32_fileres in
+ *ar\ archive\ import\ library*) # definitely import
+ win32_libid_type="x86 archive import"
+ ;;
+ *ar\ archive*) # could be an import, or static
+ # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
+ if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+ $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+ case $nm_interface in
+ "MS dumpbin")
+ if func_cygming_ms_implib_p "$1" ||
+ func_cygming_gnu_implib_p "$1"
+ then
+ win32_nmres=import
+ else
+ win32_nmres=
+ fi
+ ;;
+ *)
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
+ $SED -n -e '
+ 1,100{
+ / I /{
+ s|.*|import|
+ p
+ q
+ }
+ }'`
+ ;;
+ esac
+ case $win32_nmres in
+ import*) win32_libid_type="x86 archive import";;
+ *) win32_libid_type="x86 archive static";;
+ esac
+ fi
+ ;;
+ *DLL*)
+ win32_libid_type="x86 DLL"
+ ;;
+ *executable*) # but shell scripts are "executable" too...
+ case $win32_fileres in
+ *MS\ Windows\ PE\ Intel*)
+ win32_libid_type="x86 DLL"
+ ;;
+ esac
+ ;;
+ esac
+ $ECHO "$win32_libid_type"
+}
+
+# func_cygming_dll_for_implib ARG
+#
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+# Invoked by eval'ing the libtool variable
+# $sharedlib_from_linklib_cmd
+# Result is available in the variable
+# $sharedlib_from_linklib_result
+func_cygming_dll_for_implib ()
+{
+ $debug_cmd
+
+ sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
+}
+
+# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs
+#
+# The is the core of a fallback implementation of a
+# platform-specific function to extract the name of the
+# DLL associated with the specified import library LIBNAME.
+#
+# SECTION_NAME is either .idata$6 or .idata$7, depending
+# on the platform and compiler that created the implib.
+#
+# Echos the name of the DLL associated with the
+# specified import library.
+func_cygming_dll_for_implib_fallback_core ()
+{
+ $debug_cmd
+
+ match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
+ $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
+ $SED '/^Contents of section '"$match_literal"':/{
+ # Place marker at beginning of archive member dllname section
+ s/.*/====MARK====/
+ p
+ d
+ }
+ # These lines can sometimes be longer than 43 characters, but
+ # are always uninteresting
+ /:[ ]*file format pe[i]\{,1\}-/d
+ /^In archive [^:]*:/d
+ # Ensure marker is printed
+ /^====MARK====/p
+ # Remove all lines with less than 43 characters
+ /^.\{43\}/!d
+ # From remaining lines, remove first 43 characters
+ s/^.\{43\}//' |
+ $SED -n '
+ # Join marker and all lines until next marker into a single line
+ /^====MARK====/ b para
+ H
+ $ b para
+ b
+ :para
+ x
+ s/\n//g
+ # Remove the marker
+ s/^====MARK====//
+ # Remove trailing dots and whitespace
+ s/[\. \t]*$//
+ # Print
+ /./p' |
+ # we now have a list, one entry per line, of the stringified
+ # contents of the appropriate section of all members of the
+ # archive that possess that section. Heuristic: eliminate
+ # all those that have a first or second character that is
+ # a '.' (that is, objdump's representation of an unprintable
+ # character.) This should work for all archives with less than
+ # 0x302f exports -- but will fail for DLLs whose name actually
+ # begins with a literal '.' or a single character followed by
+ # a '.'.
+ #
+ # Of those that remain, print the first one.
+ $SED -e '/^\./d;/^.\./d;q'
+}
+
+# func_cygming_dll_for_implib_fallback ARG
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+#
+# This fallback implementation is for use when $DLLTOOL
+# does not support the --identify-strict option.
+# Invoked by eval'ing the libtool variable
+# $sharedlib_from_linklib_cmd
+# Result is available in the variable
+# $sharedlib_from_linklib_result
+func_cygming_dll_for_implib_fallback ()
+{
+ $debug_cmd
+
+ if func_cygming_gnu_implib_p "$1"; then
+ # binutils import library
+ sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
+ elif func_cygming_ms_implib_p "$1"; then
+ # ms-generated import library
+ sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
+ else
+ # unknown
+ sharedlib_from_linklib_result=
+ fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+ $debug_cmd
+
+ f_ex_an_ar_dir=$1; shift
+ f_ex_an_ar_oldlib=$1
+ if test yes = "$lock_old_archive_extraction"; then
+ lockfile=$f_ex_an_ar_oldlib.lock
+ until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+ func_echo "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ fi
+ func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+ 'stat=$?; rm -f "$lockfile"; exit $stat'
+ if test yes = "$lock_old_archive_extraction"; then
+ $opt_dry_run || rm -f "$lockfile"
+ fi
+ if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+ fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+ $debug_cmd
+
+ my_gentop=$1; shift
+ my_oldlibs=${1+"$@"}
+ my_oldobjs=
+ my_xlib=
+ my_xabs=
+ my_xdir=
+
+ for my_xlib in $my_oldlibs; do
+ # Extract the objects.
+ case $my_xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;;
+ *) my_xabs=`pwd`"/$my_xlib" ;;
+ esac
+ func_basename "$my_xlib"
+ my_xlib=$func_basename_result
+ my_xlib_u=$my_xlib
+ while :; do
+ case " $extracted_archives " in
+ *" $my_xlib_u "*)
+ func_arith $extracted_serial + 1
+ extracted_serial=$func_arith_result
+ my_xlib_u=lt$extracted_serial-$my_xlib ;;
+ *) break ;;
+ esac
+ done
+ extracted_archives="$extracted_archives $my_xlib_u"
+ my_xdir=$my_gentop/$my_xlib_u
+
+ func_mkdir_p "$my_xdir"
+
+ case $host in
+ *-darwin*)
+ func_verbose "Extracting $my_xabs"
+ # Do not bother doing anything if just a dry run
+ $opt_dry_run || {
+ darwin_orig_dir=`pwd`
+ cd $my_xdir || exit $?
+ darwin_archive=$my_xabs
+ darwin_curdir=`pwd`
+ func_basename "$darwin_archive"
+ darwin_base_archive=$func_basename_result
+ darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+ if test -n "$darwin_arches"; then
+ darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+ darwin_arch=
+ func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+ for darwin_arch in $darwin_arches; do
+ func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch"
+ $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive"
+ cd "unfat-$$/$darwin_base_archive-$darwin_arch"
+ func_extract_an_archive "`pwd`" "$darwin_base_archive"
+ cd "$darwin_curdir"
+ $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive"
+ done # $darwin_arches
+ ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+ darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u`
+ darwin_file=
+ darwin_files=
+ for darwin_file in $darwin_filelist; do
+ darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+ $LIPO -create -output "$darwin_file" $darwin_files
+ done # $darwin_filelist
+ $RM -rf unfat-$$
+ cd "$darwin_orig_dir"
+ else
+ cd $darwin_orig_dir
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ fi # $darwin_arches
+ } # !$opt_dry_run
+ ;;
+ *)
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ ;;
+ esac
+ my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+ done
+
+ func_extract_archives_result=$my_oldobjs
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable. Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take. If 'yes', then the emitted script
+# will assume that the directory where it is stored is
+# the $objdir directory. This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+ func_emit_wrapper_arg1=${1-no}
+
+ $ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version='$macro_version'
+ notinst_deplibs='$notinst_deplibs'
+else
+ # When we are sourced in execute mode, \$file and \$ECHO are already set.
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ file=\"\$0\""
+
+ qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+ $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+ ECHO=\"$qECHO\"
+ fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ that is used only on
+# windows platforms, and (c) all begin with the string "--lt-"
+# (application programs are unlikely to have options that match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+ lt_script_arg0=\$0
+ shift
+ for lt_opt
+ do
+ case \"\$lt_opt\" in
+ --lt-debug) lt_option_debug=1 ;;
+ --lt-dump-script)
+ lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+ test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+ lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+ cat \"\$lt_dump_D/\$lt_dump_F\"
+ exit 0
+ ;;
+ --lt-*)
+ \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+
+ # Print the debug banner immediately:
+ if test -n \"\$lt_option_debug\"; then
+ echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2
+ fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+ lt_dump_args_N=1;
+ for lt_arg
+ do
+ \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\"
+ lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+ done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+"
+ case $host in
+ # Backslashes separate directories on plain windows
+ *-*-mingw | *-*-os2* | *-cegcc*)
+ $ECHO "\
+ if test -n \"\$lt_option_debug\"; then
+ \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2
+ func_lt_dump_args \${1+\"\$@\"} 1>&2
+ fi
+ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+ ;;
+
+ *)
+ $ECHO "\
+ if test -n \"\$lt_option_debug\"; then
+ \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2
+ func_lt_dump_args \${1+\"\$@\"} 1>&2
+ fi
+ exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+ ;;
+ esac
+ $ECHO "\
+ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+ exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+ case \" \$* \" in
+ *\\ --lt-*)
+ for lt_wr_arg
+ do
+ case \$lt_wr_arg in
+ --lt-*) ;;
+ *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
+ esac
+ shift
+ done ;;
+ esac
+ func_exec_program_core \${1+\"\$@\"}
+}
+
+ # Parse options
+ func_parse_lt_options \"\$0\" \${1+\"\$@\"}
+
+ # Find the directory that this script lives in.
+ thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+ test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+ while test -n \"\$file\"; do
+ destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+ # If there was a directory component, then change thisdir.
+ if test \"x\$destdir\" != \"x\$file\"; then
+ case \"\$destdir\" in
+ [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+ *) thisdir=\"\$thisdir/\$destdir\" ;;
+ esac
+ fi
+
+ file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+ file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+ done
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+ if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+ # special case for '.'
+ if test \"\$thisdir\" = \".\"; then
+ thisdir=\`pwd\`
+ fi
+ # remove .libs from thisdir
+ case \"\$thisdir\" in
+ *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+ $objdir ) thisdir=. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=\`cd \"\$thisdir\" && pwd\`
+ test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+ if test yes = "$fast_install"; then
+ $ECHO "\
+ program=lt-'$outputname'$exeext
+ progdir=\"\$thisdir/$objdir\"
+
+ if test ! -f \"\$progdir/\$program\" ||
+ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\
+ test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+ file=\"\$\$-\$program\"
+
+ if test ! -d \"\$progdir\"; then
+ $MKDIR \"\$progdir\"
+ else
+ $RM \"\$progdir/\$file\"
+ fi"
+
+ $ECHO "\
+
+ # relink executable if necessary
+ if test -n \"\$relink_command\"; then
+ if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+ else
+ \$ECHO \"\$relink_command_output\" >&2
+ $RM \"\$progdir/\$file\"
+ exit 1
+ fi
+ fi
+
+ $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+ { $RM \"\$progdir/\$program\";
+ $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+ $RM \"\$progdir/\$file\"
+ fi"
+ else
+ $ECHO "\
+ program='$outputname'
+ progdir=\"\$thisdir/$objdir\"
+"
+ fi
+
+ $ECHO "\
+
+ if test -f \"\$progdir/\$program\"; then"
+
+ # fixup the dll searchpath if we need to.
+ #
+ # Fix the DLL searchpath if we need to. Do this before prepending
+ # to shlibpath, because on Windows, both are PATH and uninstalled
+ # libraries must come first.
+ if test -n "$dllsearchpath"; then
+ $ECHO "\
+ # Add the dll search path components to the executable PATH
+ PATH=$dllsearchpath:\$PATH
+"
+ fi
+
+ # Export our shlibpath_var if we have one.
+ if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ $ECHO "\
+ # Add our own library path to $shlibpath_var
+ $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+ # Some systems cannot cope with colon-terminated $shlibpath_var
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+ export $shlibpath_var
+"
+ fi
+
+ $ECHO "\
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ # Run the actual program with our arguments.
+ func_exec_program \${1+\"\$@\"}
+ fi
+ else
+ # The program doesn't exist.
+ \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2
+ \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+ \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+ exit 1
+ fi
+fi\
+"
+}
+
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+ cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+ Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+
+ The $output program cannot be directly executed until all the libtool
+ libraries that it depends on are installed.
+
+ This wrapper executable should never be moved out of the build directory.
+ If it is, it will not operate correctly.
+*/
+EOF
+ cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+# include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
+
+/* declarations of non-ANSI functions */
+#if defined __MINGW32__
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined __CYGWIN__
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined other_platform || defined ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined _MSC_VER
+# define setmode _setmode
+# define stat _stat
+# define chmod _chmod
+# define getcwd _getcwd
+# define putenv _putenv
+# define S_IXUSR _S_IEXEC
+#elif defined __MINGW32__
+# define setmode _setmode
+# define stat _stat
+# define chmod _chmod
+# define getcwd _getcwd
+# define putenv _putenv
+#elif defined __CYGWIN__
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined other platforms ... */
+#endif
+
+#if defined PATH_MAX
+# define LT_PATHMAX PATH_MAX
+#elif defined MAXPATHLEN
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \
+ defined __OS2__
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+# define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+# define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+ if (stale) { free (stale); stale = 0; } \
+} while (0)
+
+#if defined LT_DEBUGWRAPPER
+static int lt_debug = 1;
+#else
+static int lt_debug = 0;
+#endif
+
+const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_debugprintf (const char *file, int line, const char *fmt, ...);
+void lt_fatal (const char *file, int line, const char *message, ...);
+static const char *nonnull (const char *s);
+static const char *nonempty (const char *s);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+ cat <<EOF
+#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
+# define externally_visible volatile
+#else
+# define externally_visible __attribute__((externally_visible)) volatile
+#endif
+externally_visible const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+ if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ func_to_host_path "$temp_rpath"
+ cat <<EOF
+const char * LIB_PATH_VALUE = "$func_to_host_path_result";
+EOF
+ else
+ cat <<"EOF"
+const char * LIB_PATH_VALUE = "";
+EOF
+ fi
+
+ if test -n "$dllsearchpath"; then
+ func_to_host_path "$dllsearchpath:"
+ cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE = "$func_to_host_path_result";
+EOF
+ else
+ cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE = "";
+EOF
+ fi
+
+ if test yes = "$fast_install"; then
+ cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+ else
+ cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+ fi
+
+
+ cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX "--lt-"
+
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+static const char *dumpscript_opt = LTWRAPPER_OPTION_PREFIX "dump-script";
+static const char *debug_opt = LTWRAPPER_OPTION_PREFIX "debug";
+
+int
+main (int argc, char *argv[])
+{
+ char **newargz;
+ int newargc;
+ char *tmp_pathspec;
+ char *actual_cwrapper_path;
+ char *actual_cwrapper_name;
+ char *target_name;
+ char *lt_argv_zero;
+ int rval = 127;
+
+ int i;
+
+ program_name = (char *) xstrdup (base_name (argv[0]));
+ newargz = XMALLOC (char *, (size_t) argc + 1);
+
+ /* very simple arg parsing; don't want to rely on getopt
+ * also, copy all non cwrapper options to newargz, except
+ * argz[0], which is handled differently
+ */
+ newargc=0;
+ for (i = 1; i < argc; i++)
+ {
+ if (STREQ (argv[i], dumpscript_opt))
+ {
+EOF
+ case $host in
+ *mingw* | *cygwin* )
+ # make stdout use "unix" line endings
+ echo " setmode(1,_O_BINARY);"
+ ;;
+ esac
+
+ cat <<"EOF"
+ lt_dump_script (stdout);
+ return 0;
+ }
+ if (STREQ (argv[i], debug_opt))
+ {
+ lt_debug = 1;
+ continue;
+ }
+ if (STREQ (argv[i], ltwrapper_option_prefix))
+ {
+ /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+ namespace, but it is not one of the ones we know about and
+ have already dealt with, above (inluding dump-script), then
+ report an error. Otherwise, targets might begin to believe
+ they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+ namespace. The first time any user complains about this, we'll
+ need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+ or a configure.ac-settable value.
+ */
+ lt_fatal (__FILE__, __LINE__,
+ "unrecognized %s option: '%s'",
+ ltwrapper_option_prefix, argv[i]);
+ }
+ /* otherwise ... */
+ newargz[++newargc] = xstrdup (argv[i]);
+ }
+ newargz[++newargc] = NULL;
+
+EOF
+ cat <<EOF
+ /* The GNU banner must be the first non-error debug message */
+ lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE) $VERSION\n");
+EOF
+ cat <<"EOF"
+ lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
+ lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
+
+ tmp_pathspec = find_executable (argv[0]);
+ if (tmp_pathspec == NULL)
+ lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) found exe (before symlink chase) at: %s\n",
+ tmp_pathspec);
+
+ actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) found exe (after symlink chase) at: %s\n",
+ actual_cwrapper_path);
+ XFREE (tmp_pathspec);
+
+ actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
+ strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+ /* wrapper name transforms */
+ strendzap (actual_cwrapper_name, ".exe");
+ tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+ XFREE (actual_cwrapper_name);
+ actual_cwrapper_name = tmp_pathspec;
+ tmp_pathspec = 0;
+
+ /* target_name transforms -- use actual target program name; might have lt- prefix */
+ target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+ strendzap (target_name, ".exe");
+ tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+ XFREE (target_name);
+ target_name = tmp_pathspec;
+ tmp_pathspec = 0;
+
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) libtool target name: %s\n",
+ target_name);
+EOF
+
+ cat <<EOF
+ newargz[0] =
+ XMALLOC (char, (strlen (actual_cwrapper_path) +
+ strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+ strcpy (newargz[0], actual_cwrapper_path);
+ strcat (newargz[0], "$objdir");
+ strcat (newargz[0], "/");
+EOF
+
+ cat <<"EOF"
+ /* stop here, and copy so we don't have to do this twice */
+ tmp_pathspec = xstrdup (newargz[0]);
+
+ /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+ strcat (newargz[0], actual_cwrapper_name);
+
+ /* DO want the lt- prefix here if it exists, so use target_name */
+ lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+ XFREE (tmp_pathspec);
+ tmp_pathspec = NULL;
+EOF
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ {
+ char* p;
+ while ((p = strchr (newargz[0], '\\')) != NULL)
+ {
+ *p = '/';
+ }
+ while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+ {
+ *p = '/';
+ }
+ }
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+ XFREE (target_name);
+ XFREE (actual_cwrapper_path);
+ XFREE (actual_cwrapper_name);
+
+ lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+ lt_setenv ("DUALCASE", "1"); /* for MSK sh */
+ /* Update the DLL searchpath. EXE_PATH_VALUE ($dllsearchpath) must
+ be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath)
+ because on Windows, both *_VARNAMEs are PATH but uninstalled
+ libraries must come first. */
+ lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+ lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+
+ lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
+ nonnull (lt_argv_zero));
+ for (i = 0; i < newargc; i++)
+ {
+ lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
+ i, nonnull (newargz[i]));
+ }
+
+EOF
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ /* execv doesn't actually work on mingw as expected on unix */
+ newargz = prepare_spawn (newargz);
+ rval = (int) _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+ if (rval == -1)
+ {
+ /* failed to start process */
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) failed to launch target \"%s\": %s\n",
+ lt_argv_zero, nonnull (strerror (errno)));
+ return 127;
+ }
+ return rval;
+EOF
+ ;;
+ *)
+ cat <<"EOF"
+ execv (lt_argv_zero, newargz);
+ return rval; /* =127, but avoids unused variable warning */
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+ void *p = (void *) malloc (num);
+ if (!p)
+ lt_fatal (__FILE__, __LINE__, "memory exhausted");
+
+ return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+ return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+ string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+ const char *base;
+
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+ /* Skip over the disk name in MSDOS pathnames. */
+ if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+ name += 2;
+#endif
+
+ for (base = name; *name; name++)
+ if (IS_DIR_SEPARATOR (*name))
+ base = name + 1;
+ return base;
+}
+
+int
+check_executable (const char *path)
+{
+ struct stat st;
+
+ lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
+ nonempty (path));
+ if ((!path) || (!*path))
+ return 0;
+
+ if ((stat (path, &st) >= 0)
+ && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+ return 1;
+ else
+ return 0;
+}
+
+int
+make_executable (const char *path)
+{
+ int rval = 0;
+ struct stat st;
+
+ lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
+ nonempty (path));
+ if ((!path) || (!*path))
+ return 0;
+
+ if (stat (path, &st) >= 0)
+ {
+ rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+ }
+ return rval;
+}
+
+/* Searches for the full path of the wrapper. Returns
+ newly allocated full path name if found, NULL otherwise
+ Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+ int has_slash = 0;
+ const char *p;
+ const char *p_next;
+ /* static buffer for getcwd */
+ char tmp[LT_PATHMAX + 1];
+ size_t tmp_len;
+ char *concat_name;
+
+ lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
+ nonempty (wrapper));
+
+ if ((wrapper == NULL) || (*wrapper == '\0'))
+ return NULL;
+
+ /* Absolute path? */
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+ if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+ else
+ {
+#endif
+ if (IS_DIR_SEPARATOR (wrapper[0]))
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+ }
+#endif
+
+ for (p = wrapper; *p; p++)
+ if (*p == '/')
+ {
+ has_slash = 1;
+ break;
+ }
+ if (!has_slash)
+ {
+ /* no slashes; search PATH */
+ const char *path = getenv ("PATH");
+ if (path != NULL)
+ {
+ for (p = path; *p; p = p_next)
+ {
+ const char *q;
+ size_t p_len;
+ for (q = p; *q; q++)
+ if (IS_PATH_SEPARATOR (*q))
+ break;
+ p_len = (size_t) (q - p);
+ p_next = (*q == '\0' ? q : q + 1);
+ if (p_len == 0)
+ {
+ /* empty path: current directory */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+ nonnull (strerror (errno)));
+ tmp_len = strlen (tmp);
+ concat_name =
+ XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+ }
+ else
+ {
+ concat_name =
+ XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, p, p_len);
+ concat_name[p_len] = '/';
+ strcpy (concat_name + p_len + 1, wrapper);
+ }
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+ }
+ /* not found in PATH; assume curdir */
+ }
+ /* Relative path | not found in path: prepend cwd */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+ nonnull (strerror (errno)));
+ tmp_len = strlen (tmp);
+ concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+ return xstrdup (pathspec);
+#else
+ char buf[LT_PATHMAX];
+ struct stat s;
+ char *tmp_pathspec = xstrdup (pathspec);
+ char *p;
+ int has_symlinks = 0;
+ while (strlen (tmp_pathspec) && !has_symlinks)
+ {
+ lt_debugprintf (__FILE__, __LINE__,
+ "checking path component for symlinks: %s\n",
+ tmp_pathspec);
+ if (lstat (tmp_pathspec, &s) == 0)
+ {
+ if (S_ISLNK (s.st_mode) != 0)
+ {
+ has_symlinks = 1;
+ break;
+ }
+
+ /* search backwards for last DIR_SEPARATOR */
+ p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+ while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+ p--;
+ if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+ {
+ /* no more DIR_SEPARATORS left */
+ break;
+ }
+ *p = '\0';
+ }
+ else
+ {
+ lt_fatal (__FILE__, __LINE__,
+ "error accessing file \"%s\": %s",
+ tmp_pathspec, nonnull (strerror (errno)));
+ }
+ }
+ XFREE (tmp_pathspec);
+
+ if (!has_symlinks)
+ {
+ return xstrdup (pathspec);
+ }
+
+ tmp_pathspec = realpath (pathspec, buf);
+ if (tmp_pathspec == 0)
+ {
+ lt_fatal (__FILE__, __LINE__,
+ "could not follow symlinks for %s", pathspec);
+ }
+ return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+ size_t len, patlen;
+
+ assert (str != NULL);
+ assert (pat != NULL);
+
+ len = strlen (str);
+ patlen = strlen (pat);
+
+ if (patlen <= len)
+ {
+ str += len - patlen;
+ if (STREQ (str, pat))
+ *str = '\0';
+ }
+ return str;
+}
+
+void
+lt_debugprintf (const char *file, int line, const char *fmt, ...)
+{
+ va_list args;
+ if (lt_debug)
+ {
+ (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
+ va_start (args, fmt);
+ (void) vfprintf (stderr, fmt, args);
+ va_end (args);
+ }
+}
+
+static void
+lt_error_core (int exit_status, const char *file,
+ int line, const char *mode,
+ const char *message, va_list ap)
+{
+ fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
+ vfprintf (stderr, message, ap);
+ fprintf (stderr, ".\n");
+
+ if (exit_status >= 0)
+ exit (exit_status);
+}
+
+void
+lt_fatal (const char *file, int line, const char *message, ...)
+{
+ va_list ap;
+ va_start (ap, message);
+ lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
+ va_end (ap);
+}
+
+static const char *
+nonnull (const char *s)
+{
+ return s ? s : "(null)";
+}
+
+static const char *
+nonempty (const char *s)
+{
+ return (s && !*s) ? "(empty)" : nonnull (s);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_setenv) setting '%s' to '%s'\n",
+ nonnull (name), nonnull (value));
+ {
+#ifdef HAVE_SETENV
+ /* always make a copy, for consistency with !HAVE_SETENV */
+ char *str = xstrdup (value);
+ setenv (name, str, 1);
+#else
+ size_t len = strlen (name) + 1 + strlen (value) + 1;
+ char *str = XMALLOC (char, len);
+ sprintf (str, "%s=%s", name, value);
+ if (putenv (str) != EXIT_SUCCESS)
+ {
+ XFREE (str);
+ }
+#endif
+ }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+ char *new_value;
+ if (orig_value && *orig_value)
+ {
+ size_t orig_value_len = strlen (orig_value);
+ size_t add_len = strlen (add);
+ new_value = XMALLOC (char, add_len + orig_value_len + 1);
+ if (to_end)
+ {
+ strcpy (new_value, orig_value);
+ strcpy (new_value + orig_value_len, add);
+ }
+ else
+ {
+ strcpy (new_value, add);
+ strcpy (new_value + add_len, orig_value);
+ }
+ }
+ else
+ {
+ new_value = xstrdup (add);
+ }
+ return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+ nonnull (name), nonnull (value));
+
+ if (name && *name && value && *value)
+ {
+ char *new_value = lt_extend_str (getenv (name), value, 0);
+ /* some systems can't cope with a ':'-terminated path #' */
+ size_t len = strlen (new_value);
+ while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+ {
+ new_value[--len] = '\0';
+ }
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+ nonnull (name), nonnull (value));
+
+ if (name && *name && value && *value)
+ {
+ char *new_value = lt_extend_str (getenv (name), value, 0);
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ }
+}
+
+EOF
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+ Note that spawn() does not by itself call the command interpreter
+ (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+ ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&v);
+ v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+ }) ? "cmd.exe" : "command.com").
+ Instead it simply concatenates the arguments, separated by ' ', and calls
+ CreateProcess(). We must quote the arguments since Win32 CreateProcess()
+ interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+ special way:
+ - Space and tab are interpreted as delimiters. They are not treated as
+ delimiters if they are surrounded by double quotes: "...".
+ - Unescaped double quotes are removed from the input. Their only effect is
+ that within double quotes, space and tab are treated like normal
+ characters.
+ - Backslashes not followed by double quotes are not special.
+ - But 2*n+1 backslashes followed by a double quote become
+ n backslashes followed by a double quote (n >= 0):
+ \" -> "
+ \\\" -> \"
+ \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+ size_t argc;
+ char **new_argv;
+ size_t i;
+
+ /* Count number of arguments. */
+ for (argc = 0; argv[argc] != NULL; argc++)
+ ;
+
+ /* Allocate new argument vector. */
+ new_argv = XMALLOC (char *, argc + 1);
+
+ /* Put quoted arguments into the new argument vector. */
+ for (i = 0; i < argc; i++)
+ {
+ const char *string = argv[i];
+
+ if (string[0] == '\0')
+ new_argv[i] = xstrdup ("\"\"");
+ else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+ {
+ int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+ size_t length;
+ unsigned int backslashes;
+ const char *s;
+ char *quoted_string;
+ char *p;
+
+ length = 0;
+ backslashes = 0;
+ if (quote_around)
+ length++;
+ for (s = string; *s != '\0'; s++)
+ {
+ char c = *s;
+ if (c == '"')
+ length += backslashes + 1;
+ length++;
+ if (c == '\\')
+ backslashes++;
+ else
+ backslashes = 0;
+ }
+ if (quote_around)
+ length += backslashes + 1;
+
+ quoted_string = XMALLOC (char, length + 1);
+
+ p = quoted_string;
+ backslashes = 0;
+ if (quote_around)
+ *p++ = '"';
+ for (s = string; *s != '\0'; s++)
+ {
+ char c = *s;
+ if (c == '"')
+ {
+ unsigned int j;
+ for (j = backslashes + 1; j > 0; j--)
+ *p++ = '\\';
+ }
+ *p++ = c;
+ if (c == '\\')
+ backslashes++;
+ else
+ backslashes = 0;
+ }
+ if (quote_around)
+ {
+ unsigned int j;
+ for (j = backslashes; j > 0; j--)
+ *p++ = '\\';
+ *p++ = '"';
+ }
+ *p = '\0';
+
+ new_argv[i] = quoted_string;
+ }
+ else
+ new_argv[i] = (char *) string;
+ }
+ new_argv[argc] = NULL;
+
+ return new_argv;
+}
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+ func_emit_wrapper yes |
+ $SED -n -e '
+s/^\(.\{79\}\)\(..*\)/\1\
+\2/
+h
+s/\([\\"]\)/\\\1/g
+s/$/\\n/
+s/\([^\n]*\).*/ fputs ("\1", f);/p
+g
+D'
+ cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+ $debug_cmd
+
+ case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+ *import*) : ;;
+ *) false ;;
+ esac
+}
+
+# func_suncc_cstd_abi
+# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!!
+# Several compiler flags select an ABI that is incompatible with the
+# Cstd library. Avoid specifying it if any are in CXXFLAGS.
+func_suncc_cstd_abi ()
+{
+ $debug_cmd
+
+ case " $compile_command " in
+ *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*)
+ suncc_use_cstd_abi=no
+ ;;
+ *)
+ suncc_use_cstd_abi=yes
+ ;;
+ esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+ $debug_cmd
+
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ # It is impossible to link a dll without this setting, and
+ # we shouldn't force the makefile maintainer to figure out
+ # what system we are compiling for in order to pass an extra
+ # flag for every libtool invocation.
+ # allow_undefined=no
+
+ # FIXME: Unfortunately, there are problems with the above when trying
+ # to make a dll that has undefined symbols, in which case not
+ # even a static library is built. For now, we need to specify
+ # -no-undefined on the libtool link line when we can be certain
+ # that all symbols are satisfied, otherwise we get a static library.
+ allow_undefined=yes
+ ;;
+ *)
+ allow_undefined=yes
+ ;;
+ esac
+ libtool_args=$nonopt
+ base_compile="$nonopt $@"
+ compile_command=$nonopt
+ finalize_command=$nonopt
+
+ compile_rpath=
+ finalize_rpath=
+ compile_shlibpath=
+ finalize_shlibpath=
+ convenience=
+ old_convenience=
+ deplibs=
+ old_deplibs=
+ compiler_flags=
+ linker_flags=
+ dllsearchpath=
+ lib_search_path=`pwd`
+ inst_prefix_dir=
+ new_inherited_linker_flags=
+
+ avoid_version=no
+ bindir=
+ dlfiles=
+ dlprefiles=
+ dlself=no
+ export_dynamic=no
+ export_symbols=
+ export_symbols_regex=
+ generated=
+ libobjs=
+ ltlibs=
+ module=no
+ no_install=no
+ objs=
+ os2dllname=
+ non_pic_objects=
+ precious_files_regex=
+ prefer_static_libs=no
+ preload=false
+ prev=
+ prevarg=
+ release=
+ rpath=
+ xrpath=
+ perm_rpath=
+ temp_rpath=
+ thread_safe=no
+ vinfo=
+ vinfo_number=no
+ weak_libs=
+ single_module=$wl-single_module
+ func_infer_tag $base_compile
+
+ # We need to know -static, to get the right output filenames.
+ for arg
+ do
+ case $arg in
+ -shared)
+ test yes != "$build_libtool_libs" \
+ && func_fatal_configuration "cannot build a shared library"
+ build_old_libs=no
+ break
+ ;;
+ -all-static | -static | -static-libtool-libs)
+ case $arg in
+ -all-static)
+ if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then
+ func_warning "complete static linking is impossible in this configuration"
+ fi
+ if test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ -static)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=built
+ ;;
+ -static-libtool-libs)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ esac
+ build_libtool_libs=no
+ build_old_libs=yes
+ break
+ ;;
+ esac
+ done
+
+ # See if our shared archives depend on static archives.
+ test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+ # Go through the arguments, transforming them on the way.
+ while test "$#" -gt 0; do
+ arg=$1
+ shift
+ func_quote_for_eval "$arg"
+ qarg=$func_quote_for_eval_unquoted_result
+ func_append libtool_args " $func_quote_for_eval_result"
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ output)
+ func_append compile_command " @OUTPUT@"
+ func_append finalize_command " @OUTPUT@"
+ ;;
+ esac
+
+ case $prev in
+ bindir)
+ bindir=$arg
+ prev=
+ continue
+ ;;
+ dlfiles|dlprefiles)
+ $preload || {
+ # Add the symbol object into the linking commands.
+ func_append compile_command " @SYMFILE@"
+ func_append finalize_command " @SYMFILE@"
+ preload=:
+ }
+ case $arg in
+ *.la | *.lo) ;; # We handle these cases below.
+ force)
+ if test no = "$dlself"; then
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ self)
+ if test dlprefiles = "$prev"; then
+ dlself=yes
+ elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then
+ dlself=yes
+ else
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ *)
+ if test dlfiles = "$prev"; then
+ func_append dlfiles " $arg"
+ else
+ func_append dlprefiles " $arg"
+ fi
+ prev=
+ continue
+ ;;
+ esac
+ ;;
+ expsyms)
+ export_symbols=$arg
+ test -f "$arg" \
+ || func_fatal_error "symbol file '$arg' does not exist"
+ prev=
+ continue
+ ;;
+ expsyms_regex)
+ export_symbols_regex=$arg
+ prev=
+ continue
+ ;;
+ framework)
+ case $host in
+ *-*-darwin*)
+ case "$deplibs " in
+ *" $qarg.ltframework "*) ;;
+ *) func_append deplibs " $qarg.ltframework" # this is fixed later
+ ;;
+ esac
+ ;;
+ esac
+ prev=
+ continue
+ ;;
+ inst_prefix)
+ inst_prefix_dir=$arg
+ prev=
+ continue
+ ;;
+ mllvm)
+ # Clang does not use LLVM to link, so we can simply discard any
+ # '-mllvm $arg' options when doing the link step.
+ prev=
+ continue
+ ;;
+ objectlist)
+ if test -f "$arg"; then
+ save_arg=$arg
+ moreargs=
+ for fil in `cat "$save_arg"`
+ do
+# func_append moreargs " $fil"
+ arg=$fil
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if func_lalib_unsafe_p "$arg"; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ func_source "$arg"
+
+ if test -z "$pic_object" ||
+ test -z "$non_pic_object" ||
+ test none = "$pic_object" &&
+ test none = "$non_pic_object"; then
+ func_fatal_error "cannot find name of object for '$arg'"
+ fi
+
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir=$func_dirname_result
+
+ if test none != "$pic_object"; then
+ # Prepend the subdirectory the object is found in.
+ pic_object=$xdir$pic_object
+
+ if test dlfiles = "$prev"; then
+ if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
+ func_append dlfiles " $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test dlprefiles = "$prev"; then
+ # Preload the old-style object.
+ func_append dlprefiles " $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ func_append libobjs " $pic_object"
+ arg=$pic_object
+ fi
+
+ # Non-PIC object.
+ if test none != "$non_pic_object"; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object=$xdir$non_pic_object
+
+ # A standard non-PIC object
+ func_append non_pic_objects " $non_pic_object"
+ if test -z "$pic_object" || test none = "$pic_object"; then
+ arg=$non_pic_object
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object=$pic_object
+ func_append non_pic_objects " $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if $opt_dry_run; then
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir=$func_dirname_result
+
+ func_lo2o "$arg"
+ pic_object=$xdir$objdir/$func_lo2o_result
+ non_pic_object=$xdir$func_lo2o_result
+ func_append libobjs " $pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ else
+ func_fatal_error "'$arg' is not a valid libtool object"
+ fi
+ fi
+ done
+ else
+ func_fatal_error "link input file '$arg' does not exist"
+ fi
+ arg=$save_arg
+ prev=
+ continue
+ ;;
+ os2dllname)
+ os2dllname=$arg
+ prev=
+ continue
+ ;;
+ precious_regex)
+ precious_files_regex=$arg
+ prev=
+ continue
+ ;;
+ release)
+ release=-$arg
+ prev=
+ continue
+ ;;
+ rpath | xrpath)
+ # We need an absolute path.
+ case $arg in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ func_fatal_error "only absolute run-paths are allowed"
+ ;;
+ esac
+ if test rpath = "$prev"; then
+ case "$rpath " in
+ *" $arg "*) ;;
+ *) func_append rpath " $arg" ;;
+ esac
+ else
+ case "$xrpath " in
+ *" $arg "*) ;;
+ *) func_append xrpath " $arg" ;;
+ esac
+ fi
+ prev=
+ continue
+ ;;
+ shrext)
+ shrext_cmds=$arg
+ prev=
+ continue
+ ;;
+ weak)
+ func_append weak_libs " $arg"
+ prev=
+ continue
+ ;;
+ xcclinker)
+ func_append linker_flags " $qarg"
+ func_append compiler_flags " $qarg"
+ prev=
+ func_append compile_command " $qarg"
+ func_append finalize_command " $qarg"
+ continue
+ ;;
+ xcompiler)
+ func_append compiler_flags " $qarg"
+ prev=
+ func_append compile_command " $qarg"
+ func_append finalize_command " $qarg"
+ continue
+ ;;
+ xlinker)
+ func_append linker_flags " $qarg"
+ func_append compiler_flags " $wl$qarg"
+ prev=
+ func_append compile_command " $wl$qarg"
+ func_append finalize_command " $wl$qarg"
+ continue
+ ;;
+ *)
+ eval "$prev=\"\$arg\""
+ prev=
+ continue
+ ;;
+ esac
+ fi # test -n "$prev"
+
+ prevarg=$arg
+
+ case $arg in
+ -all-static)
+ if test -n "$link_static_flag"; then
+ # See comment for -static flag below, for more details.
+ func_append compile_command " $link_static_flag"
+ func_append finalize_command " $link_static_flag"
+ fi
+ continue
+ ;;
+
+ -allow-undefined)
+ # FIXME: remove this flag sometime in the future.
+ func_fatal_error "'-allow-undefined' must not be used because it is the default"
+ ;;
+
+ -avoid-version)
+ avoid_version=yes
+ continue
+ ;;
+
+ -bindir)
+ prev=bindir
+ continue
+ ;;
+
+ -dlopen)
+ prev=dlfiles
+ continue
+ ;;
+
+ -dlpreopen)
+ prev=dlprefiles
+ continue
+ ;;
+
+ -export-dynamic)
+ export_dynamic=yes
+ continue
+ ;;
+
+ -export-symbols | -export-symbols-regex)
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ func_fatal_error "more than one -exported-symbols argument is not allowed"
+ fi
+ if test X-export-symbols = "X$arg"; then
+ prev=expsyms
+ else
+ prev=expsyms_regex
+ fi
+ continue
+ ;;
+
+ -framework)
+ prev=framework
+ continue
+ ;;
+
+ -inst-prefix-dir)
+ prev=inst_prefix
+ continue
+ ;;
+
+ # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+ # so, if we see these flags be careful not to treat them like -L
+ -L[A-Z][A-Z]*:*)
+ case $with_gcc/$host in
+ no/*-*-irix* | /*-*-irix*)
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ ;;
+ esac
+ continue
+ ;;
+
+ -L*)
+ func_stripname "-L" '' "$arg"
+ if test -z "$func_stripname_result"; then
+ if test "$#" -gt 0; then
+ func_fatal_error "require no space between '-L' and '$1'"
+ else
+ func_fatal_error "need path for '-L' option"
+ fi
+ fi
+ func_resolve_sysroot "$func_stripname_result"
+ dir=$func_resolve_sysroot_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ test -z "$absdir" && \
+ func_fatal_error "cannot determine absolute directory name of '$dir'"
+ dir=$absdir
+ ;;
+ esac
+ case "$deplibs " in
+ *" -L$dir "* | *" $arg "*)
+ # Will only happen for absolute or sysroot arguments
+ ;;
+ *)
+ # Preserve sysroot, but never include relative directories
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;;
+ *) func_append deplibs " -L$dir" ;;
+ esac
+ func_append lib_search_path " $dir"
+ ;;
+ esac
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$dir:"*) ;;
+ ::) dllsearchpath=$dir;;
+ *) func_append dllsearchpath ":$dir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ ::) dllsearchpath=$testbindir;;
+ *) func_append dllsearchpath ":$testbindir";;
+ esac
+ ;;
+ esac
+ continue
+ ;;
+
+ -l*)
+ if test X-lc = "X$arg" || test X-lm = "X$arg"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+ # These systems don't actually have a C or math library (as such)
+ continue
+ ;;
+ *-*-os2*)
+ # These systems don't actually have a C library (as such)
+ test X-lc = "X$arg" && continue
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
+ # Do not include libc due to us having libc/libc_r.
+ test X-lc = "X$arg" && continue
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C and math libraries are in the System framework
+ func_append deplibs " System.ltframework"
+ continue
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ test X-lc = "X$arg" && continue
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ test X-lc = "X$arg" && continue
+ ;;
+ esac
+ elif test X-lc_r = "X$arg"; then
+ case $host in
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
+ # Do not include libc_r directly, use -pthread flag.
+ continue
+ ;;
+ esac
+ fi
+ func_append deplibs " $arg"
+ continue
+ ;;
+
+ -mllvm)
+ prev=mllvm
+ continue
+ ;;
+
+ -module)
+ module=yes
+ continue
+ ;;
+
+ # Tru64 UNIX uses -model [arg] to determine the layout of C++
+ # classes, name mangling, and exception handling.
+ # Darwin uses the -arch flag to determine output architecture.
+ -model|-arch|-isysroot|--sysroot)
+ func_append compiler_flags " $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ prev=xcompiler
+ continue
+ ;;
+
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+ func_append compiler_flags " $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ case "$new_inherited_linker_flags " in
+ *" $arg "*) ;;
+ * ) func_append new_inherited_linker_flags " $arg" ;;
+ esac
+ continue
+ ;;
+
+ -multi_module)
+ single_module=$wl-multi_module
+ continue
+ ;;
+
+ -no-fast-install)
+ fast_install=no
+ continue
+ ;;
+
+ -no-install)
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+ # The PATH hackery in wrapper scripts is required on Windows
+ # and Darwin in order for the loader to find any dlls it needs.
+ func_warning "'-no-install' is ignored for $host"
+ func_warning "assuming '-no-fast-install' instead"
+ fast_install=no
+ ;;
+ *) no_install=yes ;;
+ esac
+ continue
+ ;;
+
+ -no-undefined)
+ allow_undefined=no
+ continue
+ ;;
+
+ -objectlist)
+ prev=objectlist
+ continue
+ ;;
+
+ -os2dllname)
+ prev=os2dllname
+ continue
+ ;;
+
+ -o) prev=output ;;
+
+ -precious-files-regex)
+ prev=precious_regex
+ continue
+ ;;
+
+ -release)
+ prev=release
+ continue
+ ;;
+
+ -rpath)
+ prev=rpath
+ continue
+ ;;
+
+ -R)
+ prev=xrpath
+ continue
+ ;;
+
+ -R*)
+ func_stripname '-R' '' "$arg"
+ dir=$func_stripname_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ =*)
+ func_stripname '=' '' "$dir"
+ dir=$lt_sysroot$func_stripname_result
+ ;;
+ *)
+ func_fatal_error "only absolute run-paths are allowed"
+ ;;
+ esac
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) func_append xrpath " $dir" ;;
+ esac
+ continue
+ ;;
+
+ -shared)
+ # The effects of -shared are defined in a previous loop.
+ continue
+ ;;
+
+ -shrext)
+ prev=shrext
+ continue
+ ;;
+
+ -static | -static-libtool-libs)
+ # The effects of -static are defined in a previous loop.
+ # We used to do the same as -all-static on platforms that
+ # didn't have a PIC flag, but the assumption that the effects
+ # would be equivalent was wrong. It would break on at least
+ # Digital Unix and AIX.
+ continue
+ ;;
+
+ -thread-safe)
+ thread_safe=yes
+ continue
+ ;;
+
+ -version-info)
+ prev=vinfo
+ continue
+ ;;
+
+ -version-number)
+ prev=vinfo
+ vinfo_number=yes
+ continue
+ ;;
+
+ -weak)
+ prev=weak
+ continue
+ ;;
+
+ -Wc,*)
+ func_stripname '-Wc,' '' "$arg"
+ args=$func_stripname_result
+ arg=
+ save_ifs=$IFS; IFS=,
+ for flag in $args; do
+ IFS=$save_ifs
+ func_quote_for_eval "$flag"
+ func_append arg " $func_quote_for_eval_result"
+ func_append compiler_flags " $func_quote_for_eval_result"
+ done
+ IFS=$save_ifs
+ func_stripname ' ' '' "$arg"
+ arg=$func_stripname_result
+ ;;
+
+ -Wl,*)
+ func_stripname '-Wl,' '' "$arg"
+ args=$func_stripname_result
+ arg=
+ save_ifs=$IFS; IFS=,
+ for flag in $args; do
+ IFS=$save_ifs
+ func_quote_for_eval "$flag"
+ func_append arg " $wl$func_quote_for_eval_result"
+ func_append compiler_flags " $wl$func_quote_for_eval_result"
+ func_append linker_flags " $func_quote_for_eval_result"
+ done
+ IFS=$save_ifs
+ func_stripname ' ' '' "$arg"
+ arg=$func_stripname_result
+ ;;
+
+ -Xcompiler)
+ prev=xcompiler
+ continue
+ ;;
+
+ -Xlinker)
+ prev=xlinker
+ continue
+ ;;
+
+ -XCClinker)
+ prev=xcclinker
+ continue
+ ;;
+
+ # -msg_* for osf cc
+ -msg_*)
+ func_quote_for_eval "$arg"
+ arg=$func_quote_for_eval_result
+ ;;
+
+ # Flags to be passed through unchanged, with rationale:
+ # -64, -mips[0-9] enable 64-bit mode for the SGI compiler
+ # -r[0-9][0-9]* specify processor for the SGI compiler
+ # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
+ # +DA*, +DD* enable 64-bit mode for the HP compiler
+ # -q* compiler args for the IBM compiler
+ # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
+ # -F/path path to uninstalled frameworks, gcc on darwin
+ # -p, -pg, --coverage, -fprofile-* profiling flags for GCC
+ # -fstack-protector* stack protector flags for GCC
+ # @file GCC response files
+ # -tp=* Portland pgcc target processor selection
+ # --sysroot=* for sysroot support
+ # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+ # -specs=* GCC specs files
+ # -stdlib=* select c++ std lib with clang
+ # -fsanitize=* Clang/GCC memory and address sanitizer
+ # -fuse-ld=* Linker select flags for GCC
+ # -static-* direct GCC to link specific libraries statically
+ # -fcilkplus Cilk Plus language extension features for C/C++
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+ -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \
+ -specs=*|-fsanitize=*|-fuse-ld=*|-static-*|-fcilkplus)
+ func_quote_for_eval "$arg"
+ arg=$func_quote_for_eval_result
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ func_append compiler_flags " $arg"
+ continue
+ ;;
+
+ -Z*)
+ if test os2 = "`expr $host : '.*\(os2\)'`"; then
+ # OS/2 uses -Zxxx to specify OS/2-specific options
+ compiler_flags="$compiler_flags $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ case $arg in
+ -Zlinker | -Zstack)
+ prev=xcompiler
+ ;;
+ esac
+ continue
+ else
+ # Otherwise treat like 'Some other compiler flag' below
+ func_quote_for_eval "$arg"
+ arg=$func_quote_for_eval_result
+ fi
+ ;;
+
+ # Some other compiler flag.
+ -* | +*)
+ func_quote_for_eval "$arg"
+ arg=$func_quote_for_eval_result
+ ;;
+
+ *.$objext)
+ # A standard object.
+ func_append objs " $arg"
+ ;;
+
+ *.lo)
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if func_lalib_unsafe_p "$arg"; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ func_source "$arg"
+
+ if test -z "$pic_object" ||
+ test -z "$non_pic_object" ||
+ test none = "$pic_object" &&
+ test none = "$non_pic_object"; then
+ func_fatal_error "cannot find name of object for '$arg'"
+ fi
+
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir=$func_dirname_result
+
+ test none = "$pic_object" || {
+ # Prepend the subdirectory the object is found in.
+ pic_object=$xdir$pic_object
+
+ if test dlfiles = "$prev"; then
+ if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
+ func_append dlfiles " $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test dlprefiles = "$prev"; then
+ # Preload the old-style object.
+ func_append dlprefiles " $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ func_append libobjs " $pic_object"
+ arg=$pic_object
+ }
+
+ # Non-PIC object.
+ if test none != "$non_pic_object"; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object=$xdir$non_pic_object
+
+ # A standard non-PIC object
+ func_append non_pic_objects " $non_pic_object"
+ if test -z "$pic_object" || test none = "$pic_object"; then
+ arg=$non_pic_object
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object=$pic_object
+ func_append non_pic_objects " $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if $opt_dry_run; then
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir=$func_dirname_result
+
+ func_lo2o "$arg"
+ pic_object=$xdir$objdir/$func_lo2o_result
+ non_pic_object=$xdir$func_lo2o_result
+ func_append libobjs " $pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ else
+ func_fatal_error "'$arg' is not a valid libtool object"
+ fi
+ fi
+ ;;
+
+ *.$libext)
+ # An archive.
+ func_append deplibs " $arg"
+ func_append old_deplibs " $arg"
+ continue
+ ;;
+
+ *.la)
+ # A libtool-controlled library.
+
+ func_resolve_sysroot "$arg"
+ if test dlfiles = "$prev"; then
+ # This library was specified with -dlopen.
+ func_append dlfiles " $func_resolve_sysroot_result"
+ prev=
+ elif test dlprefiles = "$prev"; then
+ # The library was specified with -dlpreopen.
+ func_append dlprefiles " $func_resolve_sysroot_result"
+ prev=
+ else
+ func_append deplibs " $func_resolve_sysroot_result"
+ fi
+ continue
+ ;;
+
+ # Some other compiler argument.
+ *)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ func_quote_for_eval "$arg"
+ arg=$func_quote_for_eval_result
+ ;;
+ esac # arg
+
+ # Now actually substitute the argument into the commands.
+ if test -n "$arg"; then
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ fi
+ done # argument parsing loop
+
+ test -n "$prev" && \
+ func_fatal_help "the '$prevarg' option requires an argument"
+
+ if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then
+ eval arg=\"$export_dynamic_flag_spec\"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ fi
+
+ oldlibs=
+ # calculate the name of the file, without its directory
+ func_basename "$output"
+ outputname=$func_basename_result
+ libobjs_save=$libobjs
+
+ if test -n "$shlibpath_var"; then
+ # get the directories listed in $shlibpath_var
+ eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\`
+ else
+ shlib_search_path=
+ fi
+ eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+ eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+ # Definition is injected by LT_CONFIG during libtool generation.
+ func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH"
+
+ func_dirname "$output" "/" ""
+ output_objdir=$func_dirname_result$objdir
+ func_to_tool_file "$output_objdir/"
+ tool_output_objdir=$func_to_tool_file_result
+ # Create the object directory.
+ func_mkdir_p "$output_objdir"
+
+ # Determine the type of output
+ case $output in
+ "")
+ func_fatal_help "you must specify an output file"
+ ;;
+ *.$libext) linkmode=oldlib ;;
+ *.lo | *.$objext) linkmode=obj ;;
+ *.la) linkmode=lib ;;
+ *) linkmode=prog ;; # Anything else should be a program.
+ esac
+
+ specialdeplibs=
+
+ libs=
+ # Find all interdependent deplibs by searching for libraries
+ # that are linked more than once (e.g. -la -lb -la)
+ for deplib in $deplibs; do
+ if $opt_preserve_dup_deps; then
+ case "$libs " in
+ *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+ esac
+ fi
+ func_append libs " $deplib"
+ done
+
+ if test lib = "$linkmode"; then
+ libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+ # Compute libraries that are listed more than once in $predeps
+ # $postdeps and mark them as special (i.e., whose duplicates are
+ # not to be eliminated).
+ pre_post_deps=
+ if $opt_duplicate_compiler_generated_deps; then
+ for pre_post_dep in $predeps $postdeps; do
+ case "$pre_post_deps " in
+ *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;;
+ esac
+ func_append pre_post_deps " $pre_post_dep"
+ done
+ fi
+ pre_post_deps=
+ fi
+
+ deplibs=
+ newdependency_libs=
+ newlib_search_path=
+ need_relink=no # whether we're linking any uninstalled libtool libraries
+ notinst_deplibs= # not-installed libtool libraries
+ notinst_path= # paths that contain not-installed libtool libraries
+
+ case $linkmode in
+ lib)
+ passes="conv dlpreopen link"
+ for file in $dlfiles $dlprefiles; do
+ case $file in
+ *.la) ;;
+ *)
+ func_fatal_help "libraries can '-dlopen' only libtool libraries: $file"
+ ;;
+ esac
+ done
+ ;;
+ prog)
+ compile_deplibs=
+ finalize_deplibs=
+ alldeplibs=false
+ newdlfiles=
+ newdlprefiles=
+ passes="conv scan dlopen dlpreopen link"
+ ;;
+ *) passes="conv"
+ ;;
+ esac
+
+ for pass in $passes; do
+ # The preopen pass in lib mode reverses $deplibs; put it back here
+ # so that -L comes before libs that need it for instance...
+ if test lib,link = "$linkmode,$pass"; then
+ ## FIXME: Find the place where the list is rebuilt in the wrong
+ ## order, and fix it there properly
+ tmp_deplibs=
+ for deplib in $deplibs; do
+ tmp_deplibs="$deplib $tmp_deplibs"
+ done
+ deplibs=$tmp_deplibs
+ fi
+
+ if test lib,link = "$linkmode,$pass" ||
+ test prog,scan = "$linkmode,$pass"; then
+ libs=$deplibs
+ deplibs=
+ fi
+ if test prog = "$linkmode"; then
+ case $pass in
+ dlopen) libs=$dlfiles ;;
+ dlpreopen) libs=$dlprefiles ;;
+ link)
+ libs="$deplibs %DEPLIBS%"
+ test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
+ ;;
+ esac
+ fi
+ if test lib,dlpreopen = "$linkmode,$pass"; then
+ # Collect and forward deplibs of preopened libtool libs
+ for lib in $dlprefiles; do
+ # Ignore non-libtool-libs
+ dependency_libs=
+ func_resolve_sysroot "$lib"
+ case $lib in
+ *.la) func_source "$func_resolve_sysroot_result" ;;
+ esac
+
+ # Collect preopened libtool deplibs, except any this library
+ # has declared as weak libs
+ for deplib in $dependency_libs; do
+ func_basename "$deplib"
+ deplib_base=$func_basename_result
+ case " $weak_libs " in
+ *" $deplib_base "*) ;;
+ *) func_append deplibs " $deplib" ;;
+ esac
+ done
+ done
+ libs=$dlprefiles
+ fi
+ if test dlopen = "$pass"; then
+ # Collect dlpreopened libraries
+ save_deplibs=$deplibs
+ deplibs=
+ fi
+
+ for deplib in $libs; do
+ lib=
+ found=false
+ case $deplib in
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+ if test prog,link = "$linkmode,$pass"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ func_append compiler_flags " $deplib"
+ if test lib = "$linkmode"; then
+ case "$new_inherited_linker_flags " in
+ *" $deplib "*) ;;
+ * ) func_append new_inherited_linker_flags " $deplib" ;;
+ esac
+ fi
+ fi
+ continue
+ ;;
+ -l*)
+ if test lib != "$linkmode" && test prog != "$linkmode"; then
+ func_warning "'-l' is ignored for archives/objects"
+ continue
+ fi
+ func_stripname '-l' '' "$deplib"
+ name=$func_stripname_result
+ if test lib = "$linkmode"; then
+ searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+ else
+ searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+ fi
+ for searchdir in $searchdirs; do
+ for search_ext in .la $std_shrext .so .a; do
+ # Search the libtool library
+ lib=$searchdir/lib$name$search_ext
+ if test -f "$lib"; then
+ if test .la = "$search_ext"; then
+ found=:
+ else
+ found=false
+ fi
+ break 2
+ fi
+ done
+ done
+ if $found; then
+ # deplib is a libtool library
+ # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+ # We need to do some special things here, and not later.
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ case " $predeps $postdeps " in
+ *" $deplib "*)
+ if func_lalib_p "$lib"; then
+ library_names=
+ old_library=
+ func_source "$lib"
+ for l in $old_library $library_names; do
+ ll=$l
+ done
+ if test "X$ll" = "X$old_library"; then # only static version available
+ found=false
+ func_dirname "$lib" "" "."
+ ladir=$func_dirname_result
+ lib=$ladir/$old_library
+ if test prog,link = "$linkmode,$pass"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ fi
+ ;;
+ *) ;;
+ esac
+ fi
+ else
+ # deplib doesn't seem to be a libtool library
+ if test prog,link = "$linkmode,$pass"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ ;; # -l
+ *.ltframework)
+ if test prog,link = "$linkmode,$pass"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ if test lib = "$linkmode"; then
+ case "$new_inherited_linker_flags " in
+ *" $deplib "*) ;;
+ * ) func_append new_inherited_linker_flags " $deplib" ;;
+ esac
+ fi
+ fi
+ continue
+ ;;
+ -L*)
+ case $linkmode in
+ lib)
+ deplibs="$deplib $deplibs"
+ test conv = "$pass" && continue
+ newdependency_libs="$deplib $newdependency_libs"
+ func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ func_append newlib_search_path " $func_resolve_sysroot_result"
+ ;;
+ prog)
+ if test conv = "$pass"; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ if test scan = "$pass"; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ func_append newlib_search_path " $func_resolve_sysroot_result"
+ ;;
+ *)
+ func_warning "'-L' is ignored for archives/objects"
+ ;;
+ esac # linkmode
+ continue
+ ;; # -L
+ -R*)
+ if test link = "$pass"; then
+ func_stripname '-R' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ dir=$func_resolve_sysroot_result
+ # Make sure the xrpath contains only unique directories.
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) func_append xrpath " $dir" ;;
+ esac
+ fi
+ deplibs="$deplib $deplibs"
+ continue
+ ;;
+ *.la)
+ func_resolve_sysroot "$deplib"
+ lib=$func_resolve_sysroot_result
+ ;;
+ *.$libext)
+ if test conv = "$pass"; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ case $linkmode in
+ lib)
+ # Linking convenience modules into shared libraries is allowed,
+ # but linking other static libraries is non-portable.
+ case " $dlpreconveniencelibs " in
+ *" $deplib "*) ;;
+ *)
+ valid_a_lib=false
+ case $deplibs_check_method in
+ match_pattern*)
+ set dummy $deplibs_check_method; shift
+ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+ | $EGREP "$match_pattern_regex" > /dev/null; then
+ valid_a_lib=:
+ fi
+ ;;
+ pass_all)
+ valid_a_lib=:
+ ;;
+ esac
+ if $valid_a_lib; then
+ echo
+ $ECHO "*** Warning: Linking the shared library $output against the"
+ $ECHO "*** static library $deplib is not portable!"
+ deplibs="$deplib $deplibs"
+ else
+ echo
+ $ECHO "*** Warning: Trying to link with static lib archive $deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because the file extensions .$libext of this argument makes me believe"
+ echo "*** that it is just a static archive that I should not use here."
+ fi
+ ;;
+ esac
+ continue
+ ;;
+ prog)
+ if test link != "$pass"; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ continue
+ ;;
+ esac # linkmode
+ ;; # *.$libext
+ *.lo | *.$objext)
+ if test conv = "$pass"; then
+ deplibs="$deplib $deplibs"
+ elif test prog = "$linkmode"; then
+ if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then
+ # If there is no dlopen support or we're linking statically,
+ # we need to preload.
+ func_append newdlprefiles " $deplib"
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ func_append newdlfiles " $deplib"
+ fi
+ fi
+ continue
+ ;;
+ %DEPLIBS%)
+ alldeplibs=:
+ continue
+ ;;
+ esac # case $deplib
+
+ $found || test -f "$lib" \
+ || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'"
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$lib" \
+ || func_fatal_error "'$lib' is not a valid libtool archive"
+
+ func_dirname "$lib" "" "."
+ ladir=$func_dirname_result
+
+ dlname=
+ dlopen=
+ dlpreopen=
+ libdir=
+ library_names=
+ old_library=
+ inherited_linker_flags=
+ # If the library was installed with an old release of libtool,
+ # it will not redefine variables installed, or shouldnotlink
+ installed=yes
+ shouldnotlink=no
+ avoidtemprpath=
+
+
+ # Read the .la file
+ func_source "$lib"
+
+ # Convert "-framework foo" to "foo.ltframework"
+ if test -n "$inherited_linker_flags"; then
+ tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+ for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+ case " $new_inherited_linker_flags " in
+ *" $tmp_inherited_linker_flag "*) ;;
+ *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";;
+ esac
+ done
+ fi
+ dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ if test lib,link = "$linkmode,$pass" ||
+ test prog,scan = "$linkmode,$pass" ||
+ { test prog != "$linkmode" && test lib != "$linkmode"; }; then
+ test -n "$dlopen" && func_append dlfiles " $dlopen"
+ test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
+ fi
+
+ if test conv = "$pass"; then
+ # Only check for convenience libraries
+ deplibs="$lib $deplibs"
+ if test -z "$libdir"; then
+ if test -z "$old_library"; then
+ func_fatal_error "cannot find name of link library for '$lib'"
+ fi
+ # It is a libtool convenience library, so add in its objects.
+ func_append convenience " $ladir/$objdir/$old_library"
+ func_append old_convenience " $ladir/$objdir/$old_library"
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ deplibs="$deplib $deplibs"
+ if $opt_preserve_dup_deps; then
+ case "$tmp_libs " in
+ *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+ esac
+ fi
+ func_append tmp_libs " $deplib"
+ done
+ elif test prog != "$linkmode" && test lib != "$linkmode"; then
+ func_fatal_error "'$lib' is not a convenience library"
+ fi
+ continue
+ fi # $pass = conv
+
+
+ # Get the name of the library we link against.
+ linklib=
+ if test -n "$old_library" &&
+ { test yes = "$prefer_static_libs" ||
+ test built,no = "$prefer_static_libs,$installed"; }; then
+ linklib=$old_library
+ else
+ for l in $old_library $library_names; do
+ linklib=$l
+ done
+ fi
+ if test -z "$linklib"; then
+ func_fatal_error "cannot find name of link library for '$lib'"
+ fi
+
+ # This library was specified with -dlopen.
+ if test dlopen = "$pass"; then
+ test -z "$libdir" \
+ && func_fatal_error "cannot -dlopen a convenience library: '$lib'"
+ if test -z "$dlname" ||
+ test yes != "$dlopen_support" ||
+ test no = "$build_libtool_libs"
+ then
+ # If there is no dlname, no dlopen support or we're linking
+ # statically, we need to preload. We also need to preload any
+ # dependent libraries so libltdl's deplib preloader doesn't
+ # bomb out in the load deplibs phase.
+ func_append dlprefiles " $lib $dependency_libs"
+ else
+ func_append newdlfiles " $lib"
+ fi
+ continue
+ fi # $pass = dlopen
+
+ # We need an absolute path.
+ case $ladir in
+ [\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;;
+ *)
+ abs_ladir=`cd "$ladir" && pwd`
+ if test -z "$abs_ladir"; then
+ func_warning "cannot determine absolute directory name of '$ladir'"
+ func_warning "passing it literally to the linker, although it might fail"
+ abs_ladir=$ladir
+ fi
+ ;;
+ esac
+ func_basename "$lib"
+ laname=$func_basename_result
+
+ # Find the relevant object directory and library name.
+ if test yes = "$installed"; then
+ if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ func_warning "library '$lib' was moved."
+ dir=$ladir
+ absdir=$abs_ladir
+ libdir=$abs_ladir
+ else
+ dir=$lt_sysroot$libdir
+ absdir=$lt_sysroot$libdir
+ fi
+ test yes = "$hardcode_automatic" && avoidtemprpath=yes
+ else
+ if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ dir=$ladir
+ absdir=$abs_ladir
+ # Remove this search path later
+ func_append notinst_path " $abs_ladir"
+ else
+ dir=$ladir/$objdir
+ absdir=$abs_ladir/$objdir
+ # Remove this search path later
+ func_append notinst_path " $abs_ladir"
+ fi
+ fi # $installed = yes
+ func_stripname 'lib' '.la' "$laname"
+ name=$func_stripname_result
+
+ # This library was specified with -dlpreopen.
+ if test dlpreopen = "$pass"; then
+ if test -z "$libdir" && test prog = "$linkmode"; then
+ func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'"
+ fi
+ case $host in
+ # special handling for platforms with PE-DLLs.
+ *cygwin* | *mingw* | *cegcc* )
+ # Linker will automatically link against shared library if both
+ # static and shared are present. Therefore, ensure we extract
+ # symbols from the import library if a shared library is present
+ # (otherwise, the dlopen module name will be incorrect). We do
+ # this by putting the import library name into $newdlprefiles.
+ # We recover the dlopen module name by 'saving' the la file
+ # name in a special purpose variable, and (later) extracting the
+ # dlname from the la file.
+ if test -n "$dlname"; then
+ func_tr_sh "$dir/$linklib"
+ eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
+ func_append newdlprefiles " $dir/$linklib"
+ else
+ func_append newdlprefiles " $dir/$old_library"
+ # Keep a list of preopened convenience libraries to check
+ # that they are being used correctly in the link pass.
+ test -z "$libdir" && \
+ func_append dlpreconveniencelibs " $dir/$old_library"
+ fi
+ ;;
+ * )
+ # Prefer using a static library (so that no silly _DYNAMIC symbols
+ # are required to link).
+ if test -n "$old_library"; then
+ func_append newdlprefiles " $dir/$old_library"
+ # Keep a list of preopened convenience libraries to check
+ # that they are being used correctly in the link pass.
+ test -z "$libdir" && \
+ func_append dlpreconveniencelibs " $dir/$old_library"
+ # Otherwise, use the dlname, so that lt_dlopen finds it.
+ elif test -n "$dlname"; then
+ func_append newdlprefiles " $dir/$dlname"
+ else
+ func_append newdlprefiles " $dir/$linklib"
+ fi
+ ;;
+ esac
+ fi # $pass = dlpreopen
+
+ if test -z "$libdir"; then
+ # Link the convenience library
+ if test lib = "$linkmode"; then
+ deplibs="$dir/$old_library $deplibs"
+ elif test prog,link = "$linkmode,$pass"; then
+ compile_deplibs="$dir/$old_library $compile_deplibs"
+ finalize_deplibs="$dir/$old_library $finalize_deplibs"
+ else
+ deplibs="$lib $deplibs" # used for prog,scan pass
+ fi
+ continue
+ fi
+
+
+ if test prog = "$linkmode" && test link != "$pass"; then
+ func_append newlib_search_path " $ladir"
+ deplibs="$lib $deplibs"
+
+ linkalldeplibs=false
+ if test no != "$link_all_deplibs" || test -z "$library_names" ||
+ test no = "$build_libtool_libs"; then
+ linkalldeplibs=:
+ fi
+
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ func_append newlib_search_path " $func_resolve_sysroot_result"
+ ;;
+ esac
+ # Need to link against all dependency_libs?
+ if $linkalldeplibs; then
+ deplibs="$deplib $deplibs"
+ else
+ # Need to hardcode shared library paths
+ # or/and link against static libraries
+ newdependency_libs="$deplib $newdependency_libs"
+ fi
+ if $opt_preserve_dup_deps; then
+ case "$tmp_libs " in
+ *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+ esac
+ fi
+ func_append tmp_libs " $deplib"
+ done # for deplib
+ continue
+ fi # $linkmode = prog...
+
+ if test prog,link = "$linkmode,$pass"; then
+ if test -n "$library_names" &&
+ { { test no = "$prefer_static_libs" ||
+ test built,yes = "$prefer_static_libs,$installed"; } ||
+ test -z "$old_library"; }; then
+ # We need to hardcode the library path
+ if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then
+ # Make sure the rpath contains only unique directories.
+ case $temp_rpath: in
+ *"$absdir:"*) ;;
+ *) func_append temp_rpath "$absdir:" ;;
+ esac
+ fi
+
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) func_append compile_rpath " $absdir" ;;
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ ;;
+ esac
+ fi # $linkmode,$pass = prog,link...
+
+ if $alldeplibs &&
+ { test pass_all = "$deplibs_check_method" ||
+ { test yes = "$build_libtool_libs" &&
+ test -n "$library_names"; }; }; then
+ # We only need to search for static libraries
+ continue
+ fi
+ fi
+
+ link_static=no # Whether the deplib will be linked statically
+ use_static_libs=$prefer_static_libs
+ if test built = "$use_static_libs" && test yes = "$installed"; then
+ use_static_libs=no
+ fi
+ if test -n "$library_names" &&
+ { test no = "$use_static_libs" || test -z "$old_library"; }; then
+ case $host in
+ *cygwin* | *mingw* | *cegcc* | *os2*)
+ # No point in relinking DLLs because paths are not encoded
+ func_append notinst_deplibs " $lib"
+ need_relink=no
+ ;;
+ *)
+ if test no = "$installed"; then
+ func_append notinst_deplibs " $lib"
+ need_relink=yes
+ fi
+ ;;
+ esac
+ # This is a shared library
+
+ # Warn about portability, can't link against -module's on some
+ # systems (darwin). Don't bleat about dlopened modules though!
+ dlopenmodule=
+ for dlpremoduletest in $dlprefiles; do
+ if test "X$dlpremoduletest" = "X$lib"; then
+ dlopenmodule=$dlpremoduletest
+ break
+ fi
+ done
+ if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then
+ echo
+ if test prog = "$linkmode"; then
+ $ECHO "*** Warning: Linking the executable $output against the loadable module"
+ else
+ $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+ fi
+ $ECHO "*** $linklib is not portable!"
+ fi
+ if test lib = "$linkmode" &&
+ test yes = "$hardcode_into_libs"; then
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) func_append compile_rpath " $absdir" ;;
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ ;;
+ esac
+ fi
+
+ if test -n "$old_archive_from_expsyms_cmds"; then
+ # figure out the soname
+ set dummy $library_names
+ shift
+ realname=$1
+ shift
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ # use dlname if we got it. it's perfectly good, no?
+ if test -n "$dlname"; then
+ soname=$dlname
+ elif test -n "$soname_spec"; then
+ # bleh windows
+ case $host in
+ *cygwin* | mingw* | *cegcc* | *os2*)
+ func_arith $current - $age
+ major=$func_arith_result
+ versuffix=-$major
+ ;;
+ esac
+ eval soname=\"$soname_spec\"
+ else
+ soname=$realname
+ fi
+
+ # Make a new name for the extract_expsyms_cmds to use
+ soroot=$soname
+ func_basename "$soroot"
+ soname=$func_basename_result
+ func_stripname 'lib' '.dll' "$soname"
+ newlib=libimp-$func_stripname_result.a
+
+ # If the library has no export list, then create one now
+ if test -f "$output_objdir/$soname-def"; then :
+ else
+ func_verbose "extracting exported symbol list from '$soname'"
+ func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+ fi
+
+ # Create $newlib
+ if test -f "$output_objdir/$newlib"; then :; else
+ func_verbose "generating import library for '$soname'"
+ func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+ fi
+ # make sure the library variables are pointing to the new library
+ dir=$output_objdir
+ linklib=$newlib
+ fi # test -n "$old_archive_from_expsyms_cmds"
+
+ if test prog = "$linkmode" || test relink != "$opt_mode"; then
+ add_shlibpath=
+ add_dir=
+ add=
+ lib_linked=yes
+ case $hardcode_action in
+ immediate | unsupported)
+ if test no = "$hardcode_direct"; then
+ add=$dir/$linklib
+ case $host in
+ *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;;
+ *-*-sysv4*uw2*) add_dir=-L$dir ;;
+ *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+ *-*-unixware7*) add_dir=-L$dir ;;
+ *-*-darwin* )
+ # if the lib is a (non-dlopened) module then we cannot
+ # link against it, someone is ignoring the earlier warnings
+ if /usr/bin/file -L $add 2> /dev/null |
+ $GREP ": [^:]* bundle" >/dev/null; then
+ if test "X$dlopenmodule" != "X$lib"; then
+ $ECHO "*** Warning: lib $linklib is a module, not a shared library"
+ if test -z "$old_library"; then
+ echo
+ echo "*** And there doesn't seem to be a static archive available"
+ echo "*** The link will probably fail, sorry"
+ else
+ add=$dir/$old_library
+ fi
+ elif test -n "$old_library"; then
+ add=$dir/$old_library
+ fi
+ fi
+ esac
+ elif test no = "$hardcode_minus_L"; then
+ case $host in
+ *-*-sunos*) add_shlibpath=$dir ;;
+ esac
+ add_dir=-L$dir
+ add=-l$name
+ elif test no = "$hardcode_shlibpath_var"; then
+ add_shlibpath=$dir
+ add=-l$name
+ else
+ lib_linked=no
+ fi
+ ;;
+ relink)
+ if test yes = "$hardcode_direct" &&
+ test no = "$hardcode_direct_absolute"; then
+ add=$dir/$linklib
+ elif test yes = "$hardcode_minus_L"; then
+ add_dir=-L$absdir
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ func_append add_dir " -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add=-l$name
+ elif test yes = "$hardcode_shlibpath_var"; then
+ add_shlibpath=$dir
+ add=-l$name
+ else
+ lib_linked=no
+ fi
+ ;;
+ *) lib_linked=no ;;
+ esac
+
+ if test yes != "$lib_linked"; then
+ func_fatal_configuration "unsupported hardcode properties"
+ fi
+
+ if test -n "$add_shlibpath"; then
+ case :$compile_shlibpath: in
+ *":$add_shlibpath:"*) ;;
+ *) func_append compile_shlibpath "$add_shlibpath:" ;;
+ esac
+ fi
+ if test prog = "$linkmode"; then
+ test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+ test -n "$add" && compile_deplibs="$add $compile_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ if test yes != "$hardcode_direct" &&
+ test yes != "$hardcode_minus_L" &&
+ test yes = "$hardcode_shlibpath_var"; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) func_append finalize_shlibpath "$libdir:" ;;
+ esac
+ fi
+ fi
+ fi
+
+ if test prog = "$linkmode" || test relink = "$opt_mode"; then
+ add_shlibpath=
+ add_dir=
+ add=
+ # Finalize command for both is simple: just hardcode it.
+ if test yes = "$hardcode_direct" &&
+ test no = "$hardcode_direct_absolute"; then
+ add=$libdir/$linklib
+ elif test yes = "$hardcode_minus_L"; then
+ add_dir=-L$libdir
+ add=-l$name
+ elif test yes = "$hardcode_shlibpath_var"; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) func_append finalize_shlibpath "$libdir:" ;;
+ esac
+ add=-l$name
+ elif test yes = "$hardcode_automatic"; then
+ if test -n "$inst_prefix_dir" &&
+ test -f "$inst_prefix_dir$libdir/$linklib"; then
+ add=$inst_prefix_dir$libdir/$linklib
+ else
+ add=$libdir/$linklib
+ fi
+ else
+ # We cannot seem to hardcode it, guess we'll fake it.
+ add_dir=-L$libdir
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ func_append add_dir " -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add=-l$name
+ fi
+
+ if test prog = "$linkmode"; then
+ test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+ test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ fi
+ fi
+ elif test prog = "$linkmode"; then
+ # Here we assume that one of hardcode_direct or hardcode_minus_L
+ # is not unsupported. This is valid on all known static and
+ # shared platforms.
+ if test unsupported != "$hardcode_direct"; then
+ test -n "$old_library" && linklib=$old_library
+ compile_deplibs="$dir/$linklib $compile_deplibs"
+ finalize_deplibs="$dir/$linklib $finalize_deplibs"
+ else
+ compile_deplibs="-l$name -L$dir $compile_deplibs"
+ finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+ fi
+ elif test yes = "$build_libtool_libs"; then
+ # Not a shared library
+ if test pass_all != "$deplibs_check_method"; then
+ # We're trying link a shared library against a static one
+ # but the system doesn't support it.
+
+ # Just print a warning and add the library to dependency_libs so
+ # that the program can be linked against the static library.
+ echo
+ $ECHO "*** Warning: This system cannot link to static lib archive $lib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have."
+ if test yes = "$module"; then
+ echo "*** But as you try to build a module library, libtool will still create "
+ echo "*** a static module, that should work as long as the dlopening application"
+ echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** 'nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test no = "$build_old_libs"; then
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ else
+ deplibs="$dir/$old_library $deplibs"
+ link_static=yes
+ fi
+ fi # link shared/static library?
+
+ if test lib = "$linkmode"; then
+ if test -n "$dependency_libs" &&
+ { test yes != "$hardcode_into_libs" ||
+ test yes = "$build_old_libs" ||
+ test yes = "$link_static"; }; then
+ # Extract -R from dependency_libs
+ temp_deplibs=
+ for libdir in $dependency_libs; do
+ case $libdir in
+ -R*) func_stripname '-R' '' "$libdir"
+ temp_xrpath=$func_stripname_result
+ case " $xrpath " in
+ *" $temp_xrpath "*) ;;
+ *) func_append xrpath " $temp_xrpath";;
+ esac;;
+ *) func_append temp_deplibs " $libdir";;
+ esac
+ done
+ dependency_libs=$temp_deplibs
+ fi
+
+ func_append newlib_search_path " $absdir"
+ # Link against this library
+ test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+ # ... and its dependency_libs
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ newdependency_libs="$deplib $newdependency_libs"
+ case $deplib in
+ -L*) func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result";;
+ *) func_resolve_sysroot "$deplib" ;;
+ esac
+ if $opt_preserve_dup_deps; then
+ case "$tmp_libs " in
+ *" $func_resolve_sysroot_result "*)
+ func_append specialdeplibs " $func_resolve_sysroot_result" ;;
+ esac
+ fi
+ func_append tmp_libs " $func_resolve_sysroot_result"
+ done
+
+ if test no != "$link_all_deplibs"; then
+ # Add the search paths of all dependency libraries
+ for deplib in $dependency_libs; do
+ path=
+ case $deplib in
+ -L*) path=$deplib ;;
+ *.la)
+ func_resolve_sysroot "$deplib"
+ deplib=$func_resolve_sysroot_result
+ func_dirname "$deplib" "" "."
+ dir=$func_dirname_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ func_warning "cannot determine absolute directory name of '$dir'"
+ absdir=$dir
+ fi
+ ;;
+ esac
+ if $GREP "^installed=no" $deplib > /dev/null; then
+ case $host in
+ *-*-darwin*)
+ depdepl=
+ eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+ if test -n "$deplibrary_names"; then
+ for tmp in $deplibrary_names; do
+ depdepl=$tmp
+ done
+ if test -f "$absdir/$objdir/$depdepl"; then
+ depdepl=$absdir/$objdir/$depdepl
+ darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ if test -z "$darwin_install_name"; then
+ darwin_install_name=`$OTOOL64 -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ fi
+ func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl"
+ func_append linker_flags " -dylib_file $darwin_install_name:$depdepl"
+ path=
+ fi
+ fi
+ ;;
+ *)
+ path=-L$absdir/$objdir
+ ;;
+ esac
+ else
+ eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ test -z "$libdir" && \
+ func_fatal_error "'$deplib' is not a valid libtool archive"
+ test "$absdir" != "$libdir" && \
+ func_warning "'$deplib' seems to be moved"
+
+ path=-L$absdir
+ fi
+ ;;
+ esac
+ case " $deplibs " in
+ *" $path "*) ;;
+ *) deplibs="$path $deplibs" ;;
+ esac
+ done
+ fi # link_all_deplibs != no
+ fi # linkmode = lib
+ done # for deplib in $libs
+ if test link = "$pass"; then
+ if test prog = "$linkmode"; then
+ compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+ finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+ else
+ compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ fi
+ fi
+ dependency_libs=$newdependency_libs
+ if test dlpreopen = "$pass"; then
+ # Link the dlpreopened libraries before other libraries
+ for deplib in $save_deplibs; do
+ deplibs="$deplib $deplibs"
+ done
+ fi
+ if test dlopen != "$pass"; then
+ test conv = "$pass" || {
+ # Make sure lib_search_path contains only unique directories.
+ lib_search_path=
+ for dir in $newlib_search_path; do
+ case "$lib_search_path " in
+ *" $dir "*) ;;
+ *) func_append lib_search_path " $dir" ;;
+ esac
+ done
+ newlib_search_path=
+ }
+
+ if test prog,link = "$linkmode,$pass"; then
+ vars="compile_deplibs finalize_deplibs"
+ else
+ vars=deplibs
+ fi
+ for var in $vars dependency_libs; do
+ # Add libraries to $var in reverse order
+ eval tmp_libs=\"\$$var\"
+ new_libs=
+ for deplib in $tmp_libs; do
+ # FIXME: Pedantically, this is the right thing to do, so
+ # that some nasty dependency loop isn't accidentally
+ # broken:
+ #new_libs="$deplib $new_libs"
+ # Pragmatically, this seems to cause very few problems in
+ # practice:
+ case $deplib in
+ -L*) new_libs="$deplib $new_libs" ;;
+ -R*) ;;
+ *)
+ # And here is the reason: when a library appears more
+ # than once as an explicit dependence of a library, or
+ # is implicitly linked in more than once by the
+ # compiler, it is considered special, and multiple
+ # occurrences thereof are not removed. Compare this
+ # with having the same library being listed as a
+ # dependency of multiple other libraries: in this case,
+ # we know (pedantically, we assume) the library does not
+ # need to be listed more than once, so we keep only the
+ # last copy. This is not always right, but it is rare
+ # enough that we require users that really mean to play
+ # such unportable linking tricks to link the library
+ # using -Wl,-lname, so that libtool does not consider it
+ # for duplicate removal.
+ case " $specialdeplibs " in
+ *" $deplib "*) new_libs="$deplib $new_libs" ;;
+ *)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$deplib $new_libs" ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ done
+ tmp_libs=
+ for deplib in $new_libs; do
+ case $deplib in
+ -L*)
+ case " $tmp_libs " in
+ *" $deplib "*) ;;
+ *) func_append tmp_libs " $deplib" ;;
+ esac
+ ;;
+ *) func_append tmp_libs " $deplib" ;;
+ esac
+ done
+ eval $var=\"$tmp_libs\"
+ done # for var
+ fi
+
+ # Add Sun CC postdeps if required:
+ test CXX = "$tagname" && {
+ case $host_os in
+ linux*)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C++ 5.9
+ func_suncc_cstd_abi
+
+ if test no != "$suncc_use_cstd_abi"; then
+ func_append postdeps ' -library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ func_cc_basename "$CC"
+ case $func_cc_basename_result in
+ CC* | sunCC*)
+ func_suncc_cstd_abi
+
+ if test no != "$suncc_use_cstd_abi"; then
+ func_append postdeps ' -library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ }
+
+ # Last step: remove runtime libs from dependency_libs
+ # (they stay in deplibs)
+ tmp_libs=
+ for i in $dependency_libs; do
+ case " $predeps $postdeps $compiler_lib_search_path " in
+ *" $i "*)
+ i=
+ ;;
+ esac
+ if test -n "$i"; then
+ func_append tmp_libs " $i"
+ fi
+ done
+ dependency_libs=$tmp_libs
+ done # for pass
+ if test prog = "$linkmode"; then
+ dlfiles=$newdlfiles
+ fi
+ if test prog = "$linkmode" || test lib = "$linkmode"; then
+ dlprefiles=$newdlprefiles
+ fi
+
+ case $linkmode in
+ oldlib)
+ if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+ func_warning "'-dlopen' is ignored for archives"
+ fi
+
+ case " $deplibs" in
+ *\ -l* | *\ -L*)
+ func_warning "'-l' and '-L' are ignored for archives" ;;
+ esac
+
+ test -n "$rpath" && \
+ func_warning "'-rpath' is ignored for archives"
+
+ test -n "$xrpath" && \
+ func_warning "'-R' is ignored for archives"
+
+ test -n "$vinfo" && \
+ func_warning "'-version-info/-version-number' is ignored for archives"
+
+ test -n "$release" && \
+ func_warning "'-release' is ignored for archives"
+
+ test -n "$export_symbols$export_symbols_regex" && \
+ func_warning "'-export-symbols' is ignored for archives"
+
+ # Now set the variables for building old libraries.
+ build_libtool_libs=no
+ oldlibs=$output
+ func_append objs "$old_deplibs"
+ ;;
+
+ lib)
+ # Make sure we only generate libraries of the form 'libNAME.la'.
+ case $outputname in
+ lib*)
+ func_stripname 'lib' '.la' "$outputname"
+ name=$func_stripname_result
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ ;;
+ *)
+ test no = "$module" \
+ && func_fatal_help "libtool library '$output' must begin with 'lib'"
+
+ if test no != "$need_lib_prefix"; then
+ # Add the "lib" prefix for modules if required
+ func_stripname '' '.la' "$outputname"
+ name=$func_stripname_result
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ else
+ func_stripname '' '.la' "$outputname"
+ libname=$func_stripname_result
+ fi
+ ;;
+ esac
+
+ if test -n "$objs"; then
+ if test pass_all != "$deplibs_check_method"; then
+ func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs"
+ else
+ echo
+ $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+ $ECHO "*** objects $objs is not portable!"
+ func_append libobjs " $objs"
+ fi
+ fi
+
+ test no = "$dlself" \
+ || func_warning "'-dlopen self' is ignored for libtool libraries"
+
+ set dummy $rpath
+ shift
+ test 1 -lt "$#" \
+ && func_warning "ignoring multiple '-rpath's for a libtool library"
+
+ install_libdir=$1
+
+ oldlibs=
+ if test -z "$rpath"; then
+ if test yes = "$build_libtool_libs"; then
+ # Building a libtool convenience library.
+ # Some compilers have problems with a '.al' extension so
+ # convenience libraries should have the same extension an
+ # archive normally would.
+ oldlibs="$output_objdir/$libname.$libext $oldlibs"
+ build_libtool_libs=convenience
+ build_old_libs=yes
+ fi
+
+ test -n "$vinfo" && \
+ func_warning "'-version-info/-version-number' is ignored for convenience libraries"
+
+ test -n "$release" && \
+ func_warning "'-release' is ignored for convenience libraries"
+ else
+
+ # Parse the version information argument.
+ save_ifs=$IFS; IFS=:
+ set dummy $vinfo 0 0 0
+ shift
+ IFS=$save_ifs
+
+ test -n "$7" && \
+ func_fatal_help "too many parameters to '-version-info'"
+
+ # convert absolute version numbers to libtool ages
+ # this retains compatibility with .la files and attempts
+ # to make the code below a bit more comprehensible
+
+ case $vinfo_number in
+ yes)
+ number_major=$1
+ number_minor=$2
+ number_revision=$3
+ #
+ # There are really only two kinds -- those that
+ # use the current revision as the major version
+ # and those that subtract age and use age as
+ # a minor version. But, then there is irix
+ # that has an extra 1 added just for fun
+ #
+ case $version_type in
+ # correct linux to gnu/linux during the next big refactor
+ darwin|freebsd-elf|linux|osf|windows|none)
+ func_arith $number_major + $number_minor
+ current=$func_arith_result
+ age=$number_minor
+ revision=$number_revision
+ ;;
+ freebsd-aout|qnx|sunos)
+ current=$number_major
+ revision=$number_minor
+ age=0
+ ;;
+ irix|nonstopux)
+ func_arith $number_major + $number_minor
+ current=$func_arith_result
+ age=$number_minor
+ revision=$number_minor
+ lt_irix_increment=no
+ ;;
+ *)
+ func_fatal_configuration "$modename: unknown library version type '$version_type'"
+ ;;
+ esac
+ ;;
+ no)
+ current=$1
+ revision=$2
+ age=$3
+ ;;
+ esac
+
+ # Check that each of the things are valid numbers.
+ case $current in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "CURRENT '$current' must be a nonnegative integer"
+ func_fatal_error "'$vinfo' is not valid version information"
+ ;;
+ esac
+
+ case $revision in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "REVISION '$revision' must be a nonnegative integer"
+ func_fatal_error "'$vinfo' is not valid version information"
+ ;;
+ esac
+
+ case $age in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "AGE '$age' must be a nonnegative integer"
+ func_fatal_error "'$vinfo' is not valid version information"
+ ;;
+ esac
+
+ if test "$age" -gt "$current"; then
+ func_error "AGE '$age' is greater than the current interface number '$current'"
+ func_fatal_error "'$vinfo' is not valid version information"
+ fi
+
+ # Calculate the version variables.
+ major=
+ versuffix=
+ verstring=
+ case $version_type in
+ none) ;;
+
+ darwin)
+ # Like Linux, but with the current version available in
+ # verstring for coding it into the library header
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=$major.$age.$revision
+ # Darwin ld doesn't like 0 for these options...
+ func_arith $current + 1
+ minor_current=$func_arith_result
+ xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ # On Darwin other compilers
+ case $CC in
+ nagfor*)
+ verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
+ ;;
+ *)
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ ;;
+ esac
+ ;;
+
+ freebsd-aout)
+ major=.$current
+ versuffix=.$current.$revision
+ ;;
+
+ freebsd-elf)
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=$major.$age.$revision
+ ;;
+
+ irix | nonstopux)
+ if test no = "$lt_irix_increment"; then
+ func_arith $current - $age
+ else
+ func_arith $current - $age + 1
+ fi
+ major=$func_arith_result
+
+ case $version_type in
+ nonstopux) verstring_prefix=nonstopux ;;
+ *) verstring_prefix=sgi ;;
+ esac
+ verstring=$verstring_prefix$major.$revision
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$revision
+ while test 0 -ne "$loop"; do
+ func_arith $revision - $loop
+ iface=$func_arith_result
+ func_arith $loop - 1
+ loop=$func_arith_result
+ verstring=$verstring_prefix$major.$iface:$verstring
+ done
+
+ # Before this point, $major must not contain '.'.
+ major=.$major
+ versuffix=$major.$revision
+ ;;
+
+ linux) # correct to gnu/linux during the next big refactor
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=$major.$age.$revision
+ ;;
+
+ osf)
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=.$current.$age.$revision
+ verstring=$current.$age.$revision
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$age
+ while test 0 -ne "$loop"; do
+ func_arith $current - $loop
+ iface=$func_arith_result
+ func_arith $loop - 1
+ loop=$func_arith_result
+ verstring=$verstring:$iface.0
+ done
+
+ # Make executables depend on our current version.
+ func_append verstring ":$current.0"
+ ;;
+
+ qnx)
+ major=.$current
+ versuffix=.$current
+ ;;
+
+ sco)
+ major=.$current
+ versuffix=.$current
+ ;;
+
+ sunos)
+ major=.$current
+ versuffix=.$current.$revision
+ ;;
+
+ windows)
+ # Use '-' rather than '.', since we only want one
+ # extension on DOS 8.3 file systems.
+ func_arith $current - $age
+ major=$func_arith_result
+ versuffix=-$major
+ ;;
+
+ *)
+ func_fatal_configuration "unknown library version type '$version_type'"
+ ;;
+ esac
+
+ # Clear the version info if we defaulted, and they specified a release.
+ if test -z "$vinfo" && test -n "$release"; then
+ major=
+ case $version_type in
+ darwin)
+ # we can't check for "0.0" in archive_cmds due to quoting
+ # problems, so we reset it completely
+ verstring=
+ ;;
+ *)
+ verstring=0.0
+ ;;
+ esac
+ if test no = "$need_version"; then
+ versuffix=
+ else
+ versuffix=.0.0
+ fi
+ fi
+
+ # Remove version info from name if versioning should be avoided
+ if test yes,no = "$avoid_version,$need_version"; then
+ major=
+ versuffix=
+ verstring=
+ fi
+
+ # Check to see if the archive will have undefined symbols.
+ if test yes = "$allow_undefined"; then
+ if test unsupported = "$allow_undefined_flag"; then
+ if test yes = "$build_old_libs"; then
+ func_warning "undefined symbols not allowed in $host shared libraries; building static only"
+ build_libtool_libs=no
+ else
+ func_fatal_error "can't build $host shared library unless -no-undefined is specified"
+ fi
+ fi
+ else
+ # Don't allow undefined symbols.
+ allow_undefined_flag=$no_undefined_flag
+ fi
+
+ fi
+
+ func_generate_dlsyms "$libname" "$libname" :
+ func_append libobjs " $symfileobj"
+ test " " = "$libobjs" && libobjs=
+
+ if test relink != "$opt_mode"; then
+ # Remove our outputs, but don't remove object files since they
+ # may have been created when compiling PIC objects.
+ removelist=
+ tempremovelist=`$ECHO "$output_objdir/*"`
+ for p in $tempremovelist; do
+ case $p in
+ *.$objext | *.gcno)
+ ;;
+ $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*)
+ if test -n "$precious_files_regex"; then
+ if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+ then
+ continue
+ fi
+ fi
+ func_append removelist " $p"
+ ;;
+ *) ;;
+ esac
+ done
+ test -n "$removelist" && \
+ func_show_eval "${RM}r \$removelist"
+ fi
+
+ # Now set the variables for building old libraries.
+ if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then
+ func_append oldlibs " $output_objdir/$libname.$libext"
+
+ # Transform .lo files to .o files.
+ oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP`
+ fi
+
+ # Eliminate all temporary directories.
+ #for path in $notinst_path; do
+ # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+ # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+ # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+ #done
+
+ if test -n "$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ temp_xrpath=
+ for libdir in $xrpath; do
+ func_replace_sysroot "$libdir"
+ func_append temp_xrpath " -R$func_replace_sysroot_result"
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ done
+ if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then
+ dependency_libs="$temp_xrpath $dependency_libs"
+ fi
+ fi
+
+ # Make sure dlfiles contains only unique files that won't be dlpreopened
+ old_dlfiles=$dlfiles
+ dlfiles=
+ for lib in $old_dlfiles; do
+ case " $dlprefiles $dlfiles " in
+ *" $lib "*) ;;
+ *) func_append dlfiles " $lib" ;;
+ esac
+ done
+
+ # Make sure dlprefiles contains only unique files
+ old_dlprefiles=$dlprefiles
+ dlprefiles=
+ for lib in $old_dlprefiles; do
+ case "$dlprefiles " in
+ *" $lib "*) ;;
+ *) func_append dlprefiles " $lib" ;;
+ esac
+ done
+
+ if test yes = "$build_libtool_libs"; then
+ if test -n "$rpath"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+ # these systems don't actually have a c library (as such)!
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C library is in the System framework
+ func_append deplibs " System.ltframework"
+ ;;
+ *-*-netbsd*)
+ # Don't link with libc until the a.out ld.so is fixed.
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ ;;
+ *)
+ # Add libc to deplibs on all other systems if necessary.
+ if test yes = "$build_libtool_need_lc"; then
+ func_append deplibs " -lc"
+ fi
+ ;;
+ esac
+ fi
+
+ # Transform deplibs into only deplibs that can be linked in shared.
+ name_save=$name
+ libname_save=$libname
+ release_save=$release
+ versuffix_save=$versuffix
+ major_save=$major
+ # I'm not sure if I'm treating the release correctly. I think
+ # release should show up in the -l (ie -lgmp5) so we don't want to
+ # add it in twice. Is that correct?
+ release=
+ versuffix=
+ major=
+ newdeplibs=
+ droppeddeps=no
+ case $deplibs_check_method in
+ pass_all)
+ # Don't check for shared/static. Everything works.
+ # This might be a little naive. We might want to check
+ # whether the library exists or not. But this is on
+ # osf3 & osf4 and I'm not really sure... Just
+ # implementing what was already the behavior.
+ newdeplibs=$deplibs
+ ;;
+ test_compile)
+ # This code stresses the "libraries are programs" paradigm to its
+ # limits. Maybe even breaks it. We compile a program, linking it
+ # against the deplibs as a proxy for the library. Then we can check
+ # whether they linked in statically or dynamically with ldd.
+ $opt_dry_run || $RM conftest.c
+ cat > conftest.c <<EOF
+ int main() { return 0; }
+EOF
+ $opt_dry_run || $RM conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+ ldd_output=`ldd conftest`
+ for i in $deplibs; do
+ case $i in
+ -l*)
+ func_stripname -l '' "$i"
+ name=$func_stripname_result
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ func_append newdeplibs " $i"
+ i=
+ ;;
+ esac
+ fi
+ if test -n "$i"; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+ set dummy $deplib_matches; shift
+ deplib_match=$1
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
+ func_append newdeplibs " $i"
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which I believe you do not have"
+ echo "*** because a test_compile did reveal that the linker did not use it for"
+ echo "*** its dynamic dependency list that programs get resolved with at runtime."
+ fi
+ fi
+ ;;
+ *)
+ func_append newdeplibs " $i"
+ ;;
+ esac
+ done
+ else
+ # Error occurred in the first compile. Let's try to salvage
+ # the situation: Compile a separate program for each library.
+ for i in $deplibs; do
+ case $i in
+ -l*)
+ func_stripname -l '' "$i"
+ name=$func_stripname_result
+ $opt_dry_run || $RM conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+ ldd_output=`ldd conftest`
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ func_append newdeplibs " $i"
+ i=
+ ;;
+ esac
+ fi
+ if test -n "$i"; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+ set dummy $deplib_matches; shift
+ deplib_match=$1
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
+ func_append newdeplibs " $i"
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because a test_compile did reveal that the linker did not use this one"
+ echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+ fi
+ fi
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning! Library $i is needed by this library but I was not able to"
+ echo "*** make it link in! You will probably need to install it or some"
+ echo "*** library that it depends on before this library will be fully"
+ echo "*** functional. Installing it before continuing would be even better."
+ fi
+ ;;
+ *)
+ func_append newdeplibs " $i"
+ ;;
+ esac
+ done
+ fi
+ ;;
+ file_magic*)
+ set dummy $deplibs_check_method; shift
+ file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ for a_deplib in $deplibs; do
+ case $a_deplib in
+ -l*)
+ func_stripname -l '' "$a_deplib"
+ name=$func_stripname_result
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ func_append newdeplibs " $a_deplib"
+ a_deplib=
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib"; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ if test -n "$file_magic_glob"; then
+ libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob`
+ else
+ libnameglob=$libname
+ fi
+ test yes = "$want_nocaseglob" && nocaseglob=`shopt -p nocaseglob`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ if test yes = "$want_nocaseglob"; then
+ shopt -s nocaseglob
+ potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+ $nocaseglob
+ else
+ potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+ fi
+ for potent_lib in $potential_libs; do
+ # Follow soft links.
+ if ls -lLd "$potent_lib" 2>/dev/null |
+ $GREP " -> " >/dev/null; then
+ continue
+ fi
+ # The statement above tries to avoid entering an
+ # endless loop below, in case of cyclic links.
+ # We might still enter an endless loop, since a link
+ # loop can be closed while we follow links,
+ # but so what?
+ potlib=$potent_lib
+ while test -h "$potlib" 2>/dev/null; do
+ potliblink=`ls -ld $potlib | $SED 's/.* -> //'`
+ case $potliblink in
+ [\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;;
+ *) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";;
+ esac
+ done
+ if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+ $SED -e 10q |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ func_append newdeplibs " $a_deplib"
+ a_deplib=
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib"; then
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib"; then
+ $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+ else
+ $ECHO "*** with $libname and none of the candidates passed a file format test"
+ $ECHO "*** using a file magic. Last file checked: $potlib"
+ fi
+ fi
+ ;;
+ *)
+ # Add a -L argument.
+ func_append newdeplibs " $a_deplib"
+ ;;
+ esac
+ done # Gone through all deplibs.
+ ;;
+ match_pattern*)
+ set dummy $deplibs_check_method; shift
+ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ for a_deplib in $deplibs; do
+ case $a_deplib in
+ -l*)
+ func_stripname -l '' "$a_deplib"
+ name=$func_stripname_result
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ func_append newdeplibs " $a_deplib"
+ a_deplib=
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib"; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ potlib=$potent_lib # see symlink-check above in file_magic test
+ if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+ $EGREP "$match_pattern_regex" > /dev/null; then
+ func_append newdeplibs " $a_deplib"
+ a_deplib=
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib"; then
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib"; then
+ $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+ else
+ $ECHO "*** with $libname and none of the candidates passed a file format test"
+ $ECHO "*** using a regex pattern. Last file checked: $potlib"
+ fi
+ fi
+ ;;
+ *)
+ # Add a -L argument.
+ func_append newdeplibs " $a_deplib"
+ ;;
+ esac
+ done # Gone through all deplibs.
+ ;;
+ none | unknown | *)
+ newdeplibs=
+ tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ for i in $predeps $postdeps; do
+ # can't use Xsed below, because $i might contain '/'
+ tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"`
+ done
+ fi
+ case $tmp_deplibs in
+ *[!\ \ ]*)
+ echo
+ if test none = "$deplibs_check_method"; then
+ echo "*** Warning: inter-library dependencies are not supported in this platform."
+ else
+ echo "*** Warning: inter-library dependencies are not known to be supported."
+ fi
+ echo "*** All declared inter-library dependencies are being dropped."
+ droppeddeps=yes
+ ;;
+ esac
+ ;;
+ esac
+ versuffix=$versuffix_save
+ major=$major_save
+ release=$release_save
+ libname=$libname_save
+ name=$name_save
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library with the System framework
+ newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+ ;;
+ esac
+
+ if test yes = "$droppeddeps"; then
+ if test yes = "$module"; then
+ echo
+ echo "*** Warning: libtool could not satisfy all declared inter-library"
+ $ECHO "*** dependencies of module $libname. Therefore, libtool will create"
+ echo "*** a static module, that should work as long as the dlopening"
+ echo "*** application is linked with the -dlopen flag."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** 'nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test no = "$build_old_libs"; then
+ oldlibs=$output_objdir/$libname.$libext
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ else
+ echo "*** The inter-library dependencies that have been dropped here will be"
+ echo "*** automatically added whenever a program is linked with this library"
+ echo "*** or is declared to -dlopen it."
+
+ if test no = "$allow_undefined"; then
+ echo
+ echo "*** Since this library must not contain undefined symbols,"
+ echo "*** because either the platform does not support them or"
+ echo "*** it was explicitly requested with -no-undefined,"
+ echo "*** libtool will only create a static version of it."
+ if test no = "$build_old_libs"; then
+ oldlibs=$output_objdir/$libname.$libext
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ fi
+ fi
+ # Done checking deplibs!
+ deplibs=$newdeplibs
+ fi
+ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+ case $host in
+ *-*-darwin*)
+ newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ ;;
+ esac
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $deplibs " in
+ *" -L$path/$objdir "*)
+ func_append new_libs " -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ done
+ deplibs=$new_libs
+
+ # All the library-specific variables (install_libdir is set above).
+ library_names=
+ old_library=
+ dlname=
+
+ # Test again, we may have decided not to build it any more
+ if test yes = "$build_libtool_libs"; then
+ # Remove $wl instances when linking with ld.
+ # FIXME: should test the right _cmds variable.
+ case $archive_cmds in
+ *\$LD\ *) wl= ;;
+ esac
+ if test yes = "$hardcode_into_libs"; then
+ # Hardcode the library paths
+ hardcode_libdirs=
+ dep_rpath=
+ rpath=$finalize_rpath
+ test relink = "$opt_mode" || rpath=$compile_rpath$rpath
+ for libdir in $rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ func_replace_sysroot "$libdir"
+ libdir=$func_replace_sysroot_result
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs=$libdir
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ func_append dep_rpath " $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) func_append perm_rpath " $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir=$hardcode_libdirs
+ eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
+ fi
+ if test -n "$runpath_var" && test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ func_append rpath "$dir:"
+ done
+ eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+ fi
+ test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+ fi
+
+ shlibpath=$finalize_shlibpath
+ test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath
+ if test -n "$shlibpath"; then
+ eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+ fi
+
+ # Get the real and link names of the library.
+ eval shared_ext=\"$shrext_cmds\"
+ eval library_names=\"$library_names_spec\"
+ set dummy $library_names
+ shift
+ realname=$1
+ shift
+
+ if test -n "$soname_spec"; then
+ eval soname=\"$soname_spec\"
+ else
+ soname=$realname
+ fi
+ if test -z "$dlname"; then
+ dlname=$soname
+ fi
+
+ lib=$output_objdir/$realname
+ linknames=
+ for link
+ do
+ func_append linknames " $link"
+ done
+
+ # Use standard objects if they are pic
+ test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ test "X$libobjs" = "X " && libobjs=
+
+ delfiles=
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+ export_symbols=$output_objdir/$libname.uexp
+ func_append delfiles " $export_symbols"
+ fi
+
+ orig_export_symbols=
+ case $host_os in
+ cygwin* | mingw* | cegcc*)
+ if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+ # exporting using user supplied symfile
+ func_dll_def_p "$export_symbols" || {
+ # and it's NOT already a .def file. Must figure out
+ # which of the given symbols are data symbols and tag
+ # them as such. So, trigger use of export_symbols_cmds.
+ # export_symbols gets reassigned inside the "prepare
+ # the list of exported symbols" if statement, so the
+ # include_expsyms logic still works.
+ orig_export_symbols=$export_symbols
+ export_symbols=
+ always_export_symbols=yes
+ }
+ fi
+ ;;
+ esac
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then
+ func_verbose "generating symbol list for '$libname.la'"
+ export_symbols=$output_objdir/$libname.exp
+ $opt_dry_run || $RM $export_symbols
+ cmds=$export_symbols_cmds
+ save_ifs=$IFS; IFS='~'
+ for cmd1 in $cmds; do
+ IFS=$save_ifs
+ # Take the normal branch if the nm_file_list_spec branch
+ # doesn't work or if tool conversion is not needed.
+ case $nm_file_list_spec~$to_tool_file_cmd in
+ *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*)
+ try_normal_branch=yes
+ eval cmd=\"$cmd1\"
+ func_len " $cmd"
+ len=$func_len_result
+ ;;
+ *)
+ try_normal_branch=no
+ ;;
+ esac
+ if test yes = "$try_normal_branch" \
+ && { test "$len" -lt "$max_cmd_len" \
+ || test "$max_cmd_len" -le -1; }
+ then
+ func_show_eval "$cmd" 'exit $?'
+ skipped_export=false
+ elif test -n "$nm_file_list_spec"; then
+ func_basename "$output"
+ output_la=$func_basename_result
+ save_libobjs=$libobjs
+ save_output=$output
+ output=$output_objdir/$output_la.nm
+ func_to_tool_file "$output"
+ libobjs=$nm_file_list_spec$func_to_tool_file_result
+ func_append delfiles " $output"
+ func_verbose "creating $NM input file list: $output"
+ for obj in $save_libobjs; do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result"
+ done > "$output"
+ eval cmd=\"$cmd1\"
+ func_show_eval "$cmd" 'exit $?'
+ output=$save_output
+ libobjs=$save_libobjs
+ skipped_export=false
+ else
+ # The command line is too long to execute in one step.
+ func_verbose "using reloadable object file for export list..."
+ skipped_export=:
+ # Break out early, otherwise skipped_export may be
+ # set to false by a later but shorter cmd.
+ break
+ fi
+ done
+ IFS=$save_ifs
+ if test -n "$export_symbols_regex" && test : != "$skipped_export"; then
+ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+ fi
+
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ tmp_export_symbols=$export_symbols
+ test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
+ $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+ fi
+
+ if test : != "$skipped_export" && test -n "$orig_export_symbols"; then
+ # The given exports_symbols file has to be filtered, so filter it.
+ func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
+ # FIXME: $output_objdir/$libname.filter potentially contains lots of
+ # 's' commands, which not all seds can handle. GNU sed should be fine
+ # though. Also, the filter scales superlinearly with the number of
+ # global variables. join(1) would be nice here, but unfortunately
+ # isn't a blessed tool.
+ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+ func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+ export_symbols=$output_objdir/$libname.def
+ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+ fi
+
+ tmp_deplibs=
+ for test_deplib in $deplibs; do
+ case " $convenience " in
+ *" $test_deplib "*) ;;
+ *)
+ func_append tmp_deplibs " $test_deplib"
+ ;;
+ esac
+ done
+ deplibs=$tmp_deplibs
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec" &&
+ test yes = "$compiler_needs_object" &&
+ test -z "$libobjs"; then
+ # extract the archives, so we have objects to list.
+ # TODO: could optimize this to just extract one archive.
+ whole_archive_flag_spec=
+ fi
+ if test -n "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ test "X$libobjs" = "X " && libobjs=
+ else
+ gentop=$output_objdir/${outputname}x
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $convenience
+ func_append libobjs " $func_extract_archives_result"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+ fi
+
+ if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then
+ eval flag=\"$thread_safe_flag_spec\"
+ func_append linker_flags " $flag"
+ fi
+
+ # Make a backup of the uninstalled library when relinking
+ if test relink = "$opt_mode"; then
+ $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+ fi
+
+ # Do each of the archive commands.
+ if test yes = "$module" && test -n "$module_cmds"; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ eval test_cmds=\"$module_expsym_cmds\"
+ cmds=$module_expsym_cmds
+ else
+ eval test_cmds=\"$module_cmds\"
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval test_cmds=\"$archive_expsym_cmds\"
+ cmds=$archive_expsym_cmds
+ else
+ eval test_cmds=\"$archive_cmds\"
+ cmds=$archive_cmds
+ fi
+ fi
+
+ if test : != "$skipped_export" &&
+ func_len " $test_cmds" &&
+ len=$func_len_result &&
+ test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ :
+ else
+ # The command line is too long to link in one step, link piecewise
+ # or, if using GNU ld and skipped_export is not :, use a linker
+ # script.
+
+ # Save the value of $output and $libobjs because we want to
+ # use them later. If we have whole_archive_flag_spec, we
+ # want to use save_libobjs as it was before
+ # whole_archive_flag_spec was expanded, because we can't
+ # assume the linker understands whole_archive_flag_spec.
+ # This may have to be revisited, in case too many
+ # convenience libraries get linked in and end up exceeding
+ # the spec.
+ if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ fi
+ save_output=$output
+ func_basename "$output"
+ output_la=$func_basename_result
+
+ # Clear the reloadable object creation command queue and
+ # initialize k to one.
+ test_cmds=
+ concat_cmds=
+ objlist=
+ last_robj=
+ k=1
+
+ if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then
+ output=$output_objdir/$output_la.lnkscript
+ func_verbose "creating GNU ld script: $output"
+ echo 'INPUT (' > $output
+ for obj in $save_libobjs
+ do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result" >> $output
+ done
+ echo ')' >> $output
+ func_append delfiles " $output"
+ func_to_tool_file "$output"
+ output=$func_to_tool_file_result
+ elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then
+ output=$output_objdir/$output_la.lnk
+ func_verbose "creating linker input file list: $output"
+ : > $output
+ set x $save_libobjs
+ shift
+ firstobj=
+ if test yes = "$compiler_needs_object"; then
+ firstobj="$1 "
+ shift
+ fi
+ for obj
+ do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result" >> $output
+ done
+ func_append delfiles " $output"
+ func_to_tool_file "$output"
+ output=$firstobj\"$file_list_spec$func_to_tool_file_result\"
+ else
+ if test -n "$save_libobjs"; then
+ func_verbose "creating reloadable object files..."
+ output=$output_objdir/$output_la-$k.$objext
+ eval test_cmds=\"$reload_cmds\"
+ func_len " $test_cmds"
+ len0=$func_len_result
+ len=$len0
+
+ # Loop over the list of objects to be linked.
+ for obj in $save_libobjs
+ do
+ func_len " $obj"
+ func_arith $len + $func_len_result
+ len=$func_arith_result
+ if test -z "$objlist" ||
+ test "$len" -lt "$max_cmd_len"; then
+ func_append objlist " $obj"
+ else
+ # The command $test_cmds is almost too long, add a
+ # command to the queue.
+ if test 1 -eq "$k"; then
+ # The first file doesn't have a previous command to add.
+ reload_objs=$objlist
+ eval concat_cmds=\"$reload_cmds\"
+ else
+ # All subsequent reloadable object files will link in
+ # the last one created.
+ reload_objs="$objlist $last_robj"
+ eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
+ fi
+ last_robj=$output_objdir/$output_la-$k.$objext
+ func_arith $k + 1
+ k=$func_arith_result
+ output=$output_objdir/$output_la-$k.$objext
+ objlist=" $obj"
+ func_len " $last_robj"
+ func_arith $len0 + $func_len_result
+ len=$func_arith_result
+ fi
+ done
+ # Handle the remaining objects by creating one last
+ # reloadable object file. All subsequent reloadable object
+ # files will link in the last one created.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ reload_objs="$objlist $last_robj"
+ eval concat_cmds=\"\$concat_cmds$reload_cmds\"
+ if test -n "$last_robj"; then
+ eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+ fi
+ func_append delfiles " $output"
+
+ else
+ output=
+ fi
+
+ ${skipped_export-false} && {
+ func_verbose "generating symbol list for '$libname.la'"
+ export_symbols=$output_objdir/$libname.exp
+ $opt_dry_run || $RM $export_symbols
+ libobjs=$output
+ # Append the command to create the export file.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+ if test -n "$last_robj"; then
+ eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+ fi
+ }
+
+ test -n "$save_libobjs" &&
+ func_verbose "creating a temporary reloadable object file: $output"
+
+ # Loop through the commands generated above and execute them.
+ save_ifs=$IFS; IFS='~'
+ for cmd in $concat_cmds; do
+ IFS=$save_ifs
+ $opt_quiet || {
+ func_quote_for_expand "$cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ $opt_dry_run || eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test relink = "$opt_mode"; then
+ ( cd "$output_objdir" && \
+ $RM "${realname}T" && \
+ $MV "${realname}U" "$realname" )
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS=$save_ifs
+
+ if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+
+ ${skipped_export-false} && {
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ tmp_export_symbols=$export_symbols
+ test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
+ $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+ fi
+
+ if test -n "$orig_export_symbols"; then
+ # The given exports_symbols file has to be filtered, so filter it.
+ func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
+ # FIXME: $output_objdir/$libname.filter potentially contains lots of
+ # 's' commands, which not all seds can handle. GNU sed should be fine
+ # though. Also, the filter scales superlinearly with the number of
+ # global variables. join(1) would be nice here, but unfortunately
+ # isn't a blessed tool.
+ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+ func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+ export_symbols=$output_objdir/$libname.def
+ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+ fi
+ }
+
+ libobjs=$output
+ # Restore the value of output.
+ output=$save_output
+
+ if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+ # Expand the library linking commands again to reset the
+ # value of $libobjs for piecewise linking.
+
+ # Do each of the archive commands.
+ if test yes = "$module" && test -n "$module_cmds"; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ cmds=$module_expsym_cmds
+ else
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ cmds=$archive_expsym_cmds
+ else
+ cmds=$archive_cmds
+ fi
+ fi
+ fi
+
+ if test -n "$delfiles"; then
+ # Append the command to remove temporary files to $cmds.
+ eval cmds=\"\$cmds~\$RM $delfiles\"
+ fi
+
+ # Add any objects from preloaded convenience libraries
+ if test -n "$dlprefiles"; then
+ gentop=$output_objdir/${outputname}x
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $dlprefiles
+ func_append libobjs " $func_extract_archives_result"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+
+ save_ifs=$IFS; IFS='~'
+ for cmd in $cmds; do
+ IFS=$sp$nl
+ eval cmd=\"$cmd\"
+ IFS=$save_ifs
+ $opt_quiet || {
+ func_quote_for_expand "$cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ $opt_dry_run || eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test relink = "$opt_mode"; then
+ ( cd "$output_objdir" && \
+ $RM "${realname}T" && \
+ $MV "${realname}U" "$realname" )
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS=$save_ifs
+
+ # Restore the uninstalled library and exit
+ if test relink = "$opt_mode"; then
+ $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+ if test -n "$convenience"; then
+ if test -z "$whole_archive_flag_spec"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ # Create links to the real library.
+ for linkname in $linknames; do
+ if test "$realname" != "$linkname"; then
+ func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+ fi
+ done
+
+ # If -module or -export-dynamic was specified, set the dlname.
+ if test yes = "$module" || test yes = "$export_dynamic"; then
+ # On all known operating systems, these are identical.
+ dlname=$soname
+ fi
+ fi
+ ;;
+
+ obj)
+ if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+ func_warning "'-dlopen' is ignored for objects"
+ fi
+
+ case " $deplibs" in
+ *\ -l* | *\ -L*)
+ func_warning "'-l' and '-L' are ignored for objects" ;;
+ esac
+
+ test -n "$rpath" && \
+ func_warning "'-rpath' is ignored for objects"
+
+ test -n "$xrpath" && \
+ func_warning "'-R' is ignored for objects"
+
+ test -n "$vinfo" && \
+ func_warning "'-version-info' is ignored for objects"
+
+ test -n "$release" && \
+ func_warning "'-release' is ignored for objects"
+
+ case $output in
+ *.lo)
+ test -n "$objs$old_deplibs" && \
+ func_fatal_error "cannot build library object '$output' from non-libtool objects"
+
+ libobj=$output
+ func_lo2o "$libobj"
+ obj=$func_lo2o_result
+ ;;
+ *)
+ libobj=
+ obj=$output
+ ;;
+ esac
+
+ # Delete the old objects.
+ $opt_dry_run || $RM $obj $libobj
+
+ # Objects from convenience libraries. This assumes
+ # single-version convenience libraries. Whenever we create
+ # different ones for PIC/non-PIC, this we'll have to duplicate
+ # the extraction.
+ reload_conv_objs=
+ gentop=
+ # if reload_cmds runs $LD directly, get rid of -Wl from
+ # whole_archive_flag_spec and hope we can get by with turning comma
+ # into space.
+ case $reload_cmds in
+ *\$LD[\ \$]*) wl= ;;
+ esac
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+ test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+ reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags
+ else
+ gentop=$output_objdir/${obj}x
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $convenience
+ reload_conv_objs="$reload_objs $func_extract_archives_result"
+ fi
+ fi
+
+ # If we're not building shared, we need to use non_pic_objs
+ test yes = "$build_libtool_libs" || libobjs=$non_pic_objects
+
+ # Create the old-style object.
+ reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs
+
+ output=$obj
+ func_execute_cmds "$reload_cmds" 'exit $?'
+
+ # Exit if we aren't doing a library object file.
+ if test -z "$libobj"; then
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ test yes = "$build_libtool_libs" || {
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ # Create an invalid libtool object if no PIC, so that we don't
+ # accidentally link it into a program.
+ # $show "echo timestamp > $libobj"
+ # $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+ exit $EXIT_SUCCESS
+ }
+
+ if test -n "$pic_flag" || test default != "$pic_mode"; then
+ # Only do commands if we really have different PIC objects.
+ reload_objs="$libobjs $reload_conv_objs"
+ output=$libobj
+ func_execute_cmds "$reload_cmds" 'exit $?'
+ fi
+
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ exit $EXIT_SUCCESS
+ ;;
+
+ prog)
+ case $host in
+ *cygwin*) func_stripname '' '.exe' "$output"
+ output=$func_stripname_result.exe;;
+ esac
+ test -n "$vinfo" && \
+ func_warning "'-version-info' is ignored for programs"
+
+ test -n "$release" && \
+ func_warning "'-release' is ignored for programs"
+
+ $preload \
+ && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \
+ && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+ finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+ ;;
+ esac
+
+ case $host in
+ *-*-darwin*)
+ # Don't allow lazy linking, it breaks C++ global constructors
+ # But is supposedly fixed on 10.4 or later (yay!).
+ if test CXX = "$tagname"; then
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+ 10.[0123])
+ func_append compile_command " $wl-bind_at_load"
+ func_append finalize_command " $wl-bind_at_load"
+ ;;
+ esac
+ fi
+ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+ compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ ;;
+ esac
+
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $compile_deplibs " in
+ *" -L$path/$objdir "*)
+ func_append new_libs " -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $compile_deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ done
+ compile_deplibs=$new_libs
+
+
+ func_append compile_command " $compile_deplibs"
+ func_append finalize_command " $finalize_deplibs"
+
+ if test -n "$rpath$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ for libdir in $rpath $xrpath; do
+ # This is the magic to use -rpath.
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ done
+ fi
+
+ # Now hardcode the library paths
+ rpath=
+ hardcode_libdirs=
+ for libdir in $compile_rpath $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs=$libdir
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ func_append rpath " $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) func_append perm_rpath " $libdir" ;;
+ esac
+ fi
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$libdir:"*) ;;
+ ::) dllsearchpath=$libdir;;
+ *) func_append dllsearchpath ":$libdir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ ::) dllsearchpath=$testbindir;;
+ *) func_append dllsearchpath ":$testbindir";;
+ esac
+ ;;
+ esac
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir=$hardcode_libdirs
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ compile_rpath=$rpath
+
+ rpath=
+ hardcode_libdirs=
+ for libdir in $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs=$libdir
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ func_append rpath " $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$finalize_perm_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_perm_rpath " $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir=$hardcode_libdirs
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ finalize_rpath=$rpath
+
+ if test -n "$libobjs" && test yes = "$build_old_libs"; then
+ # Transform all the library objects into standard objects.
+ compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ fi
+
+ func_generate_dlsyms "$outputname" "@PROGRAM@" false
+
+ # template prelinking step
+ if test -n "$prelink_cmds"; then
+ func_execute_cmds "$prelink_cmds" 'exit $?'
+ fi
+
+ wrappers_required=:
+ case $host in
+ *cegcc* | *mingw32ce*)
+ # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+ wrappers_required=false
+ ;;
+ *cygwin* | *mingw* )
+ test yes = "$build_libtool_libs" || wrappers_required=false
+ ;;
+ *)
+ if test no = "$need_relink" || test yes != "$build_libtool_libs"; then
+ wrappers_required=false
+ fi
+ ;;
+ esac
+ $wrappers_required || {
+ # Replace the output file specification.
+ compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+ link_command=$compile_command$compile_rpath
+
+ # We have no uninstalled library dependencies, so finalize right now.
+ exit_status=0
+ func_show_eval "$link_command" 'exit_status=$?'
+
+ if test -n "$postlink_cmds"; then
+ func_to_tool_file "$output"
+ postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+ func_execute_cmds "$postlink_cmds" 'exit $?'
+ fi
+
+ # Delete the generated files.
+ if test -f "$output_objdir/${outputname}S.$objext"; then
+ func_show_eval '$RM "$output_objdir/${outputname}S.$objext"'
+ fi
+
+ exit $exit_status
+ }
+
+ if test -n "$compile_shlibpath$finalize_shlibpath"; then
+ compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+ fi
+ if test -n "$finalize_shlibpath"; then
+ finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+ fi
+
+ compile_var=
+ finalize_var=
+ if test -n "$runpath_var"; then
+ if test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ func_append rpath "$dir:"
+ done
+ compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ if test -n "$finalize_perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $finalize_perm_rpath; do
+ func_append rpath "$dir:"
+ done
+ finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ fi
+
+ if test yes = "$no_install"; then
+ # We don't need to create a wrapper script.
+ link_command=$compile_var$compile_command$compile_rpath
+ # Replace the output file specification.
+ link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+ # Delete the old output file.
+ $opt_dry_run || $RM $output
+ # Link the executable and exit
+ func_show_eval "$link_command" 'exit $?'
+
+ if test -n "$postlink_cmds"; then
+ func_to_tool_file "$output"
+ postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+ func_execute_cmds "$postlink_cmds" 'exit $?'
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ case $hardcode_action,$fast_install in
+ relink,*)
+ # Fast installation is not supported
+ link_command=$compile_var$compile_command$compile_rpath
+ relink_command=$finalize_var$finalize_command$finalize_rpath
+
+ func_warning "this platform does not like uninstalled shared libraries"
+ func_warning "'$output' will be relinked during installation"
+ ;;
+ *,yes)
+ link_command=$finalize_var$compile_command$finalize_rpath
+ relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+ ;;
+ *,no)
+ link_command=$compile_var$compile_command$compile_rpath
+ relink_command=$finalize_var$finalize_command$finalize_rpath
+ ;;
+ *,needless)
+ link_command=$finalize_var$compile_command$finalize_rpath
+ relink_command=
+ ;;
+ esac
+
+ # Replace the output file specification.
+ link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+ # Delete the old output files.
+ $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+ func_show_eval "$link_command" 'exit $?'
+
+ if test -n "$postlink_cmds"; then
+ func_to_tool_file "$output_objdir/$outputname"
+ postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+ func_execute_cmds "$postlink_cmds" 'exit $?'
+ fi
+
+ # Now create the wrapper script.
+ func_verbose "creating $output"
+
+ # Quote the relink command for shipping.
+ if test -n "$relink_command"; then
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ func_quote_for_eval "$var_value"
+ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ fi
+ done
+ relink_command="(cd `pwd`; $relink_command)"
+ relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ fi
+
+ # Only actually do things if not in dry run mode.
+ $opt_dry_run || {
+ # win32 will think the script is a binary if it has
+ # a .exe suffix, so we strip it off here.
+ case $output in
+ *.exe) func_stripname '' '.exe' "$output"
+ output=$func_stripname_result ;;
+ esac
+ # test for cygwin because mv fails w/o .exe extensions
+ case $host in
+ *cygwin*)
+ exeext=.exe
+ func_stripname '' '.exe' "$outputname"
+ outputname=$func_stripname_result ;;
+ *) exeext= ;;
+ esac
+ case $host in
+ *cygwin* | *mingw* )
+ func_dirname_and_basename "$output" "" "."
+ output_name=$func_basename_result
+ output_path=$func_dirname_result
+ cwrappersource=$output_path/$objdir/lt-$output_name.c
+ cwrapper=$output_path/$output_name.exe
+ $RM $cwrappersource $cwrapper
+ trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+ func_emit_cwrapperexe_src > $cwrappersource
+
+ # The wrapper executable is built using the $host compiler,
+ # because it contains $host paths and files. If cross-
+ # compiling, it, like the target executable, must be
+ # executed on the $host or under an emulation environment.
+ $opt_dry_run || {
+ $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+ $STRIP $cwrapper
+ }
+
+ # Now, create the wrapper script for func_source use:
+ func_ltwrapper_scriptname $cwrapper
+ $RM $func_ltwrapper_scriptname_result
+ trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+ $opt_dry_run || {
+ # note: this script will not be executed, so do not chmod.
+ if test "x$build" = "x$host"; then
+ $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+ else
+ func_emit_wrapper no > $func_ltwrapper_scriptname_result
+ fi
+ }
+ ;;
+ * )
+ $RM $output
+ trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+ func_emit_wrapper no > $output
+ chmod +x $output
+ ;;
+ esac
+ }
+ exit $EXIT_SUCCESS
+ ;;
+ esac
+
+ # See if we need to build an old-fashioned archive.
+ for oldlib in $oldlibs; do
+
+ case $build_libtool_libs in
+ convenience)
+ oldobjs="$libobjs_save $symfileobj"
+ addlibs=$convenience
+ build_libtool_libs=no
+ ;;
+ module)
+ oldobjs=$libobjs_save
+ addlibs=$old_convenience
+ build_libtool_libs=no
+ ;;
+ *)
+ oldobjs="$old_deplibs $non_pic_objects"
+ $preload && test -f "$symfileobj" \
+ && func_append oldobjs " $symfileobj"
+ addlibs=$old_convenience
+ ;;
+ esac
+
+ if test -n "$addlibs"; then
+ gentop=$output_objdir/${outputname}x
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $addlibs
+ func_append oldobjs " $func_extract_archives_result"
+ fi
+
+ # Do each command in the archive commands.
+ if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then
+ cmds=$old_archive_from_new_cmds
+ else
+
+ # Add any objects from preloaded convenience libraries
+ if test -n "$dlprefiles"; then
+ gentop=$output_objdir/${outputname}x
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $dlprefiles
+ func_append oldobjs " $func_extract_archives_result"
+ fi
+
+ # POSIX demands no paths to be encoded in archives. We have
+ # to avoid creating archives with duplicate basenames if we
+ # might have to extract them afterwards, e.g., when creating a
+ # static archive out of a convenience library, or when linking
+ # the entirety of a libtool archive into another (currently
+ # not supported by libtool).
+ if (for obj in $oldobjs
+ do
+ func_basename "$obj"
+ $ECHO "$func_basename_result"
+ done | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ echo "copying selected object files to avoid basename conflicts..."
+ gentop=$output_objdir/${outputname}x
+ func_append generated " $gentop"
+ func_mkdir_p "$gentop"
+ save_oldobjs=$oldobjs
+ oldobjs=
+ counter=1
+ for obj in $save_oldobjs
+ do
+ func_basename "$obj"
+ objbase=$func_basename_result
+ case " $oldobjs " in
+ " ") oldobjs=$obj ;;
+ *[\ /]"$objbase "*)
+ while :; do
+ # Make sure we don't pick an alternate name that also
+ # overlaps.
+ newobj=lt$counter-$objbase
+ func_arith $counter + 1
+ counter=$func_arith_result
+ case " $oldobjs " in
+ *[\ /]"$newobj "*) ;;
+ *) if test ! -f "$gentop/$newobj"; then break; fi ;;
+ esac
+ done
+ func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+ func_append oldobjs " $gentop/$newobj"
+ ;;
+ *) func_append oldobjs " $obj" ;;
+ esac
+ done
+ fi
+ func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+ tool_oldlib=$func_to_tool_file_result
+ eval cmds=\"$old_archive_cmds\"
+
+ func_len " $cmds"
+ len=$func_len_result
+ if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ cmds=$old_archive_cmds
+ elif test -n "$archiver_list_spec"; then
+ func_verbose "using command file archive linking..."
+ for obj in $oldobjs
+ do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result"
+ done > $output_objdir/$libname.libcmd
+ func_to_tool_file "$output_objdir/$libname.libcmd"
+ oldobjs=" $archiver_list_spec$func_to_tool_file_result"
+ cmds=$old_archive_cmds
+ else
+ # the command line is too long to link in one step, link in parts
+ func_verbose "using piecewise archive linking..."
+ save_RANLIB=$RANLIB
+ RANLIB=:
+ objlist=
+ concat_cmds=
+ save_oldobjs=$oldobjs
+ oldobjs=
+ # Is there a better way of finding the last object in the list?
+ for obj in $save_oldobjs
+ do
+ last_oldobj=$obj
+ done
+ eval test_cmds=\"$old_archive_cmds\"
+ func_len " $test_cmds"
+ len0=$func_len_result
+ len=$len0
+ for obj in $save_oldobjs
+ do
+ func_len " $obj"
+ func_arith $len + $func_len_result
+ len=$func_arith_result
+ func_append objlist " $obj"
+ if test "$len" -lt "$max_cmd_len"; then
+ :
+ else
+ # the above command should be used before it gets too long
+ oldobjs=$objlist
+ if test "$obj" = "$last_oldobj"; then
+ RANLIB=$save_RANLIB
+ fi
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\$concat_cmds$old_archive_cmds\"
+ objlist=
+ len=$len0
+ fi
+ done
+ RANLIB=$save_RANLIB
+ oldobjs=$objlist
+ if test -z "$oldobjs"; then
+ eval cmds=\"\$concat_cmds\"
+ else
+ eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+ fi
+ fi
+ fi
+ func_execute_cmds "$cmds" 'exit $?'
+ done
+
+ test -n "$generated" && \
+ func_show_eval "${RM}r$generated"
+
+ # Now create the libtool archive.
+ case $output in
+ *.la)
+ old_library=
+ test yes = "$build_old_libs" && old_library=$libname.$libext
+ func_verbose "creating $output"
+
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ func_quote_for_eval "$var_value"
+ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ fi
+ done
+ # Quote the link command for shipping.
+ relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+ relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ if test yes = "$hardcode_automatic"; then
+ relink_command=
+ fi
+
+ # Only create the output if not a dry run.
+ $opt_dry_run || {
+ for installed in no yes; do
+ if test yes = "$installed"; then
+ if test -z "$install_libdir"; then
+ break
+ fi
+ output=$output_objdir/${outputname}i
+ # Replace all uninstalled libtool libraries with the installed ones
+ newdependency_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ *.la)
+ func_basename "$deplib"
+ name=$func_basename_result
+ func_resolve_sysroot "$deplib"
+ eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
+ test -z "$libdir" && \
+ func_fatal_error "'$deplib' is not a valid libtool archive"
+ func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
+ ;;
+ -L*)
+ func_stripname -L '' "$deplib"
+ func_replace_sysroot "$func_stripname_result"
+ func_append newdependency_libs " -L$func_replace_sysroot_result"
+ ;;
+ -R*)
+ func_stripname -R '' "$deplib"
+ func_replace_sysroot "$func_stripname_result"
+ func_append newdependency_libs " -R$func_replace_sysroot_result"
+ ;;
+ *) func_append newdependency_libs " $deplib" ;;
+ esac
+ done
+ dependency_libs=$newdependency_libs
+ newdlfiles=
+
+ for lib in $dlfiles; do
+ case $lib in
+ *.la)
+ func_basename "$lib"
+ name=$func_basename_result
+ eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ test -z "$libdir" && \
+ func_fatal_error "'$lib' is not a valid libtool archive"
+ func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
+ ;;
+ *) func_append newdlfiles " $lib" ;;
+ esac
+ done
+ dlfiles=$newdlfiles
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ *.la)
+ # Only pass preopened files to the pseudo-archive (for
+ # eventual linking with the app. that links it) if we
+ # didn't already link the preopened objects directly into
+ # the library:
+ func_basename "$lib"
+ name=$func_basename_result
+ eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ test -z "$libdir" && \
+ func_fatal_error "'$lib' is not a valid libtool archive"
+ func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
+ ;;
+ esac
+ done
+ dlprefiles=$newdlprefiles
+ else
+ newdlfiles=
+ for lib in $dlfiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ func_append newdlfiles " $abs"
+ done
+ dlfiles=$newdlfiles
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ func_append newdlprefiles " $abs"
+ done
+ dlprefiles=$newdlprefiles
+ fi
+ $RM $output
+ # place dlname in correct position for cygwin
+ # In fact, it would be nice if we could use this code for all target
+ # systems that can't hard-code library paths into their executables
+ # and that have no shared library path variable independent of PATH,
+ # but it turns out we can't easily determine that from inspecting
+ # libtool variables, so we have to hard-code the OSs to which it
+ # applies here; at the moment, that means platforms that use the PE
+ # object format with DLL files. See the long comment at the top of
+ # tests/bindir.at for full details.
+ tdlname=$dlname
+ case $host,$output,$installed,$module,$dlname in
+ *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+ # If a -bindir argument was supplied, place the dll there.
+ if test -n "$bindir"; then
+ func_relative_path "$install_libdir" "$bindir"
+ tdlname=$func_relative_path_result/$dlname
+ else
+ # Otherwise fall back on heuristic.
+ tdlname=../bin/$dlname
+ fi
+ ;;
+ esac
+ $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that cannot go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+ if test no,yes = "$installed,$need_relink"; then
+ $ECHO >> $output "\
+relink_command=\"$relink_command\""
+ fi
+ done
+ }
+
+ # Do a symbolic link so that the libtool archive can be found in
+ # LD_LIBRARY_PATH before the program is installed.
+ func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+ ;;
+ esac
+ exit $EXIT_SUCCESS
+}
+
+if test link = "$opt_mode" || test relink = "$opt_mode"; then
+ func_mode_link ${1+"$@"}
+fi
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+ $debug_cmd
+
+ RM=$nonopt
+ files=
+ rmforce=false
+ exit_status=0
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic=$magic
+
+ for arg
+ do
+ case $arg in
+ -f) func_append RM " $arg"; rmforce=: ;;
+ -*) func_append RM " $arg" ;;
+ *) func_append files " $arg" ;;
+ esac
+ done
+
+ test -z "$RM" && \
+ func_fatal_help "you must specify an RM program"
+
+ rmdirs=
+
+ for file in $files; do
+ func_dirname "$file" "" "."
+ dir=$func_dirname_result
+ if test . = "$dir"; then
+ odir=$objdir
+ else
+ odir=$dir/$objdir
+ fi
+ func_basename "$file"
+ name=$func_basename_result
+ test uninstall = "$opt_mode" && odir=$dir
+
+ # Remember odir for removal later, being careful to avoid duplicates
+ if test clean = "$opt_mode"; then
+ case " $rmdirs " in
+ *" $odir "*) ;;
+ *) func_append rmdirs " $odir" ;;
+ esac
+ fi
+
+ # Don't error if the file doesn't exist and rm -f was used.
+ if { test -L "$file"; } >/dev/null 2>&1 ||
+ { test -h "$file"; } >/dev/null 2>&1 ||
+ test -f "$file"; then
+ :
+ elif test -d "$file"; then
+ exit_status=1
+ continue
+ elif $rmforce; then
+ continue
+ fi
+
+ rmfiles=$file
+
+ case $name in
+ *.la)
+ # Possibly a libtool archive, so verify it.
+ if func_lalib_p "$file"; then
+ func_source $dir/$name
+
+ # Delete the libtool libraries and symlinks.
+ for n in $library_names; do
+ func_append rmfiles " $odir/$n"
+ done
+ test -n "$old_library" && func_append rmfiles " $odir/$old_library"
+
+ case $opt_mode in
+ clean)
+ case " $library_names " in
+ *" $dlname "*) ;;
+ *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;;
+ esac
+ test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i"
+ ;;
+ uninstall)
+ if test -n "$library_names"; then
+ # Do each command in the postuninstall commands.
+ func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1'
+ fi
+
+ if test -n "$old_library"; then
+ # Do each command in the old_postuninstall commands.
+ func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1'
+ fi
+ # FIXME: should reinstall the best remaining shared library.
+ ;;
+ esac
+ fi
+ ;;
+
+ *.lo)
+ # Possibly a libtool object, so verify it.
+ if func_lalib_p "$file"; then
+
+ # Read the .lo file
+ func_source $dir/$name
+
+ # Add PIC object to the list of files to remove.
+ if test -n "$pic_object" && test none != "$pic_object"; then
+ func_append rmfiles " $dir/$pic_object"
+ fi
+
+ # Add non-PIC object to the list of files to remove.
+ if test -n "$non_pic_object" && test none != "$non_pic_object"; then
+ func_append rmfiles " $dir/$non_pic_object"
+ fi
+ fi
+ ;;
+
+ *)
+ if test clean = "$opt_mode"; then
+ noexename=$name
+ case $file in
+ *.exe)
+ func_stripname '' '.exe' "$file"
+ file=$func_stripname_result
+ func_stripname '' '.exe' "$name"
+ noexename=$func_stripname_result
+ # $file with .exe has already been added to rmfiles,
+ # add $file without .exe
+ func_append rmfiles " $file"
+ ;;
+ esac
+ # Do a test to see if this is a libtool program.
+ if func_ltwrapper_p "$file"; then
+ if func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ relink_command=
+ func_source $func_ltwrapper_scriptname_result
+ func_append rmfiles " $func_ltwrapper_scriptname_result"
+ else
+ relink_command=
+ func_source $dir/$noexename
+ fi
+
+ # note $name still contains .exe if it was in $file originally
+ # as does the version of $file that was added into $rmfiles
+ func_append rmfiles " $odir/$name $odir/${name}S.$objext"
+ if test yes = "$fast_install" && test -n "$relink_command"; then
+ func_append rmfiles " $odir/lt-$name"
+ fi
+ if test "X$noexename" != "X$name"; then
+ func_append rmfiles " $odir/lt-$noexename.c"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ func_show_eval "$RM $rmfiles" 'exit_status=1'
+ done
+
+ # Try to remove the $objdir's in the directories where we deleted files
+ for dir in $rmdirs; do
+ if test -d "$dir"; then
+ func_show_eval "rmdir $dir >/dev/null 2>&1"
+ fi
+ done
+
+ exit $exit_status
+}
+
+if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then
+ func_mode_uninstall ${1+"$@"}
+fi
+
+test -z "$opt_mode" && {
+ help=$generic_help
+ func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+ func_fatal_help "invalid operation mode '$opt_mode'"
+
+if test -n "$exec_cmd"; then
+ eval exec "$exec_cmd"
+ exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# where we disable both kinds of libraries. Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them. This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration. But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/pigeonhole/m4/dovecot.m4 b/pigeonhole/m4/dovecot.m4
new file mode 100644
index 0000000..037d5e4
--- /dev/null
+++ b/pigeonhole/m4/dovecot.m4
@@ -0,0 +1,609 @@
+dnl dovecot.m4 - Check presence of dovecot -*-Autoconf-*-
+dnl
+dnl Copyright (C) 2010 Dennis Schridde
+dnl
+dnl This file is free software; the authors give
+dnl unlimited permission to copy and/or distribute it, with or without
+dnl modifications, as long as this notice is preserved.
+
+# serial 34
+
+dnl
+dnl Check for support for D_FORTIFY_SOURCE=2
+dnl
+
+AC_DEFUN([AC_CC_D_FORTIFY_SOURCE],[
+ AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS])
+ AS_IF([test "$enable_hardening" = yes], [
+ case "$host" in
+ *)
+ gl_COMPILER_OPTION_IF([-O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2], [
+ CFLAGS="$CFLAGS -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2"
+ ],
+ [],
+ [AC_LANG_PROGRAM()]
+ )
+ esac
+ ])
+])
+
+dnl * gcc specific options
+AC_DEFUN([DC_DOVECOT_CFLAGS],[
+ AS_IF([test "x$ac_cv_c_compiler_gnu" = "xyes"], [
+ dnl -Wcast-qual -Wcast-align -Wconversion -Wunreachable-code # too many warnings
+ dnl -Wstrict-prototypes -Wredundant-decls # may give warnings in some systems
+ dnl -Wmissing-format-attribute -Wmissing-noreturn -Wwrite-strings # a couple of warnings
+ CFLAGS="$CFLAGS -Wall -W -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wchar-subscripts -Wformat=2 -Wbad-function-cast"
+
+ AS_IF([test "$have_clang" = "yes"], [
+ AC_TRY_COMPILE([
+ #if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 3)
+ # error new clang
+ #endif
+ ],,,[
+ dnl clang 3.3+ unfortunately this gives warnings with hash.h
+ CFLAGS="$CFLAGS -Wno-duplicate-decl-specifier"
+ ])
+ ], [
+ dnl This is simply to avoid warning when building strftime() wrappers..
+ CFLAGS="$CFLAGS -fno-builtin-strftime"
+ ])
+
+ AC_TRY_COMPILE([
+ #if __GNUC__ < 4
+ # error old gcc
+ #endif
+ ],,[
+ dnl gcc4
+ CFLAGS="$CFLAGS -Wstrict-aliasing=2"
+ ])
+
+ dnl Use std=gnu99 if we have new enough gcc
+ old_cflags=$CFLAGS
+ CFLAGS="-std=gnu99"
+ AC_TRY_COMPILE([
+ ],, [
+ CFLAGS="$CFLAGS $old_cflags"
+ ], [
+ CFLAGS="$old_cflags"
+ ])
+
+ ])
+])
+
+AC_DEFUN([AC_LD_WHOLE_ARCHIVE], [
+ LD_WHOLE_ARCHIVE=
+ LD_NO_WHOLE_ARCHIVE=
+ AC_MSG_CHECKING([for linker option to include whole archive])
+ ld_help="`$CC -Wl,-help 2>&1`"
+ case "$ld_help" in
+ *"--whole-archive"*)
+ LD_WHOLE_ARCHIVE="--whole-archive"
+ LD_NO_WHOLE_ARCHIVE="--no-whole-archive"
+ ;;
+ esac
+ AS_IF([test "x$LD_WHOLE_ARCHIVE" != "x"],
+ [AC_MSG_RESULT([-Wl,$LD_WHOLE_ARCHIVE])],
+ [AC_MSG_RESULT([not supported])]
+ )
+ AC_SUBST([LD_WHOLE_ARCHIVE])
+ AC_SUBST([LD_NO_WHOLE_ARCHIVE])
+ AM_CONDITIONAL([HAVE_WHOLE_ARCHIVE], [test "x$LD_WHOLE_ARCHIVE" != "x"])
+])
+
+dnl
+dnl Check for -z now and -z relro linker flags
+dnl
+dnl Copyright (C) 2013 Red Hat, Inc.
+dnl
+dnl This library is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU Lesser General Public
+dnl License as published by the Free Software Foundation; either
+dnl version 2.1 of the License, or (at your option) any later version.
+dnl
+dnl This library is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl Lesser General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU Lesser General Public
+dnl License along with this library. If not, see
+dnl <http://www.gnu.org/licenses/>.
+dnl
+
+AC_DEFUN([AC_LD_RELRO],[
+ RELRO_LDFLAGS=
+ AS_IF([test "$enable_hardening" = yes], [
+ AC_MSG_CHECKING([for how to force completely read-only GOT table])
+ ld_help=`$CC -Wl,-help 2>&1`
+ case $ld_help in
+ *"-z relro"*) RELRO_LDFLAGS="-Wl,-z -Wl,relro" ;;
+ esac
+ case $ld_help in
+ *"-z now"*) RELRO_LDFLAGS="$RELRO_LDFLAGS -Wl,-z -Wl,now" ;;
+ esac
+ AS_IF([test "x$RELRO_LDFLAGS" != "x"],
+ [AC_MSG_RESULT([$RELRO_LDFLAGS])],
+ [AC_MSG_RESULT([unknown])]
+ )
+ ])
+ AC_SUBST([RELRO_LDFLAGS])
+])
+
+dnl
+dnl Check for support for position independent executables
+dnl
+dnl Copyright (C) 2013 Red Hat, Inc.
+dnl
+dnl This library is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU Lesser General Public
+dnl License as published by the Free Software Foundation; either
+dnl version 2.1 of the License, or (at your option) any later version.
+dnl
+dnl This library is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl Lesser General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU Lesser General Public
+dnl License along with this library. If not, see
+dnl <http://www.gnu.org/licenses/>.
+dnl
+
+AC_DEFUN([AC_CC_PIE],[
+ AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS])
+ PIE_CFLAGS=
+ PIE_LDFLAGS=
+
+ AS_IF([test "$enable_hardening" = yes], [
+ OLD_CFLAGS=$CFLAGS
+ case "$host" in
+ *-*-mingw* | *-*-msvc* | *-*-cygwin* )
+ ;; dnl All code is position independent on Win32 target
+ *)
+ CFLAGS="-fPIE -DPIE"
+ gl_COMPILER_OPTION_IF([-pie], [
+ PIE_CFLAGS="-fPIE -DPIE"
+ PIE_LDFLAGS="-pie"
+ ], [
+ dnl some versions of clang require -Wl,-pie instead of -pie
+ gl_COMPILER_OPTION_IF([[-Wl,-pie]], [
+ PIE_CFLAGS="-fPIE -DPIE"
+ PIE_LDFLAGS="-Wl,-pie"
+ ], [AC_MSG_RESULT([not supported])],
+ [AC_LANG_PROGRAM()]
+ )
+ ],
+ [AC_LANG_PROGRAM()]
+ )
+ esac
+ CFLAGS=$OLD_CFLAGS
+ ])
+ AC_SUBST([PIE_CFLAGS])
+ AC_SUBST([PIE_LDFLAGS])
+])
+
+dnl
+dnl Check for support for Retpoline
+dnl
+
+AC_DEFUN([AC_CC_RETPOLINE],[
+ AC_ARG_WITH(retpoline,
+ AS_HELP_STRING([--with-retpoline=<choice>], [Retpoline mitigation choice (default: keep)]),
+ with_retpoline=$withval,
+ with_retpoline=keep)
+
+ AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS])
+ AS_IF([test "$enable_hardening" = yes], [
+ case "$host" in
+ *)
+ gl_COMPILER_OPTION_IF([-mfunction-return=$with_retpoline],
+ [CFLAGS="$CFLAGS -mfunction-return=$with_retpoline"],
+ [],
+ [AC_LANG_PROGRAM()]
+ )
+ gl_COMPILER_OPTION_IF([-mindirect-branch=$with_retpoline], [
+ CFLAGS="$CFLAGS -mindirect-branch=$with_retpoline"
+ ],
+ [],
+ [AC_LANG_PROGRAM()]
+ )
+ esac
+ ])
+])
+
+dnl
+dnl Check for support for -fstack-protector or -strong
+dnl
+
+AC_DEFUN([AC_CC_F_STACK_PROTECTOR],[
+ AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS])
+ AS_IF([test "$enable_hardening" = yes], [
+ case "$host" in
+ *)
+ gl_COMPILER_OPTION_IF([-fstack-protector-strong], [
+ CFLAGS="$CFLAGS -fstack-protector-strong"
+ ],
+ [
+ gl_COMPILER_OPTION_IF([-fstack-protector], [
+ CFLAGS="$CFLAGS -fstack-protector"
+ ], [], [AC_LANG_PROGRAM()])
+ ],
+ [AC_LANG_PROGRAM()]
+ )
+ esac
+ ])
+])
+
+AC_DEFUN([DC_DOVECOT_MODULEDIR],[
+ AC_ARG_WITH(moduledir,
+ [ --with-moduledir=DIR Base directory for dynamically loadable modules],
+ [moduledir="$withval"],
+ [moduledir="$dovecot_moduledir"]
+ )
+ AC_SUBST(moduledir)
+])
+
+AC_DEFUN([DC_PLUGIN_DEPS],[
+ _plugin_deps=yes
+ AC_MSG_CHECKING([whether OS supports plugin dependencies])
+ case "$host_os" in
+ darwin*)
+ dnl OSX loads the plugins twice, which breaks stuff
+ _plugin_deps=no
+ ;;
+ esac
+ AC_MSG_RESULT([$_plugin_deps])
+ AM_CONDITIONAL([DOVECOT_PLUGIN_DEPS], [test "x$_plugin_deps" = "xyes"])
+ unset _plugin_deps
+])
+
+AC_DEFUN([DC_DOVECOT_TEST_WRAPPER],[
+ AC_ARG_VAR([VALGRIND], [Path to valgrind])
+ AC_PATH_PROG(VALGRIND, valgrind, reject)
+ AS_IF([test "$VALGRIND" != reject], [
+ cat > run-test.sh <<_DC_EOF
+#!/bin/sh
+top_srcdir=\$[1]
+shift
+
+if test "\$NOUNDEF" != ""; then
+ noundef="--undef-value-errors=no"
+else
+ noundef=""
+fi
+
+if test "\$NOCHILDREN" != ""; then
+ trace_children="--trace-children=no"
+else
+ trace_children="--trace-children=yes"
+fi
+
+skip_path="\$top_srcdir/run-test-valgrind.exclude"
+if test -r "\$skip_path" && grep -w -q "\$(basename \$[1])" "\$skip_path"; then
+ NOVALGRIND=true
+fi
+
+if test "\$NOVALGRIND" != ""; then
+ \$[*]
+ ret=\$?
+else
+ test_out="test.out~\$\$"
+ trap "rm -f \$test_out" 0 1 2 3 15
+ supp_path="\$top_srcdir/run-test-valgrind.supp"
+ if test -r "\$supp_path"; then
+ $VALGRIND -q \$trace_children --error-exitcode=213 --leak-check=full --gen-suppressions=all --suppressions="\$supp_path" --log-file=\$test_out \$noundef \$[*]
+ else
+ $VALGRIND -q \$trace_children --error-exitcode=213 --leak-check=full --gen-suppressions=all --log-file=\$test_out \$noundef \$[*]
+ fi
+ ret=\$?
+ if test -s \$test_out; then
+ cat \$test_out
+ ret=1
+ fi
+fi
+if test \$ret != 0; then
+ echo "Failed to run: \$[*]" >&2
+fi
+exit \$ret
+_DC_EOF
+ RUN_TEST='$(LIBTOOL) execute $(SHELL) $(top_builddir)/run-test.sh $(top_srcdir)'
+ ], [
+ RUN_TEST=''
+ ])
+ AC_SUBST(RUN_TEST)
+])
+
+dnl Substitute every var in the given comma separated list
+AC_DEFUN([AX_SUBST_L],[
+ m4_foreach([__var__], [$@], [AC_SUBST(__var__)])
+])
+
+AC_DEFUN([DC_DOVECOT_HARDENING],[
+ AC_ARG_ENABLE(hardening,
+ AS_HELP_STRING([--enable-hardening=yes], [Enable various hardenings (default: yes)]),
+ enable_hardening=$enableval,
+ enable_hardening=yes)
+
+ AC_MSG_CHECKING([Whether to enable hardening])
+ AC_MSG_RESULT([$enable_hardening])
+
+ AC_CC_PIE
+ AC_CC_F_STACK_PROTECTOR
+ AC_CC_D_FORTIFY_SOURCE
+ AC_CC_RETPOLINE
+ AC_LD_RELRO
+ DOVECOT_WANT_UBSAN
+])
+
+AC_DEFUN([DC_DOVECOT_FUZZER],[
+ AC_ARG_WITH(fuzzer,
+ AS_HELP_STRING([--with-fuzzer=clang], [Build with clang fuzzer (default: no)]),
+ with_fuzzer=$withval,
+ with_fuzzer=no)
+ AS_IF([test x$with_fuzzer = xclang], [
+ CFLAGS="$CFLAGS -fsanitize=fuzzer-no-link"
+ # use $LIB_FUZZING_ENGINE for linking if it exists
+ FUZZER_LDFLAGS=${LIB_FUZZING_ENGINE--fsanitize=fuzzer}
+ # May need to use CXXLINK for linking, which wants sources to
+ # be compiled with -fPIE
+ FUZZER_CPPFLAGS='$(AM_CPPFLAGS) -fPIE -DPIE'
+ ], [test x$with_fuzzer != xno], [
+ AC_MSG_ERROR([Unknown fuzzer $with_fuzzer])
+ ])
+ AC_SUBST([FUZZER_CPPFLAGS])
+ AC_SUBST([FUZZER_LDFLAGS])
+ AM_CONDITIONAL([USE_FUZZER], [test "x$with_fuzzer" != "xno"])
+
+])
+
+AC_DEFUN([DC_DOVECOT],[
+ AC_ARG_WITH(dovecot,
+ [ --with-dovecot=DIR Dovecot base directory],
+ [ dovecotdir="$withval" ], [
+ dc_prefix=$prefix
+ test "x$dc_prefix" = xNONE && dc_prefix=$ac_default_prefix
+ dovecotdir="$dc_prefix/lib/dovecot"
+ ]
+ )
+
+ AC_ARG_WITH(dovecot-install-dirs,
+ [AC_HELP_STRING([--with-dovecot-install-dirs],
+ [Use install directories configured for Dovecot (default)])],
+ AS_IF([test x$withval = xno], [
+ use_install_dirs=no
+ ], [
+ use_install_dirs=yes
+ ]),
+ use_install_dirs=yes)
+
+ AC_MSG_CHECKING([for "$dovecotdir/dovecot-config"])
+ AS_IF([test -f "$dovecotdir/dovecot-config"], [
+ AC_MSG_RESULT([$dovecotdir/dovecot-config])
+ ], [
+ AC_MSG_RESULT([not found])
+ AC_MSG_NOTICE([])
+ AC_MSG_NOTICE([Use --with-dovecot=DIR to provide the path to the dovecot-config file.])
+ AC_MSG_ERROR([dovecot-config not found])
+ ])
+
+ old=`pwd`
+ cd $dovecotdir
+ abs_dovecotdir=`pwd`
+ cd $old
+ DISTCHECK_CONFIGURE_FLAGS="--with-dovecot=$abs_dovecotdir --without-dovecot-install-dirs"
+
+ dnl Make sure dovecot-config doesn't accidentically override flags
+ ORIG_CFLAGS="$CFLAGS"
+ ORIG_LDFLAGS="$LDFLAGS"
+ ORIG_BINARY_CFLAGS="$BINARY_CFLAGS"
+ ORIG_BINARY_LDFLAGS="$BINARY_LDFLAGS"
+
+ eval `grep -i '^dovecot_[[a-z_]]*=' "$dovecotdir"/dovecot-config`
+ eval `grep '^LIBDOVECOT[[A-Z0-9_]]*=' "$dovecotdir"/dovecot-config`
+
+ CFLAGS="$ORIG_CFLAGS"
+ LDFLAGS="$ORIG_LDFLAGS"
+ BINARY_CFLAGS="$ORIG_BINARY_CFLAGS"
+ BINARY_LDFLAGS="$ORIG_BINARY_LDFLAGS"
+
+ dovecot_installed_moduledir="$dovecot_moduledir"
+
+ AS_IF([test "$use_install_dirs" = "no"], [
+ dnl the main purpose of these is to fix make distcheck for plugins
+ dnl other than that, they don't really make much sense
+ dovecot_pkgincludedir='$(pkgincludedir)'
+ dovecot_pkglibdir='$(pkglibdir)'
+ dovecot_pkglibexecdir='$(libexecdir)/dovecot'
+ dovecot_docdir='$(docdir)'
+ dovecot_moduledir='$(moduledir)'
+ dovecot_statedir='$(statedir)'
+ ])
+
+ CC_CLANG
+ DC_DOVECOT_CFLAGS
+ DC_DOVECOT_HARDENING
+
+ AX_SUBST_L([DISTCHECK_CONFIGURE_FLAGS], [dovecotdir], [dovecot_moduledir], [dovecot_installed_moduledir], [dovecot_pkgincludedir], [dovecot_pkglibexecdir], [dovecot_pkglibdir], [dovecot_docdir], [dovecot_statedir])
+ AX_SUBST_L([DOVECOT_INSTALLED], [DOVECOT_CFLAGS], [DOVECOT_LIBS], [DOVECOT_SSL_LIBS], [DOVECOT_SQL_LIBS], [DOVECOT_COMPRESS_LIBS], [DOVECOT_BINARY_CFLAGS], [DOVECOT_BINARY_LDFLAGS])
+ AX_SUBST_L([LIBDOVECOT], [LIBDOVECOT_LOGIN], [LIBDOVECOT_SQL], [LIBDOVECOT_SSL], [LIBDOVECOT_COMPRESS], [LIBDOVECOT_LDA], [LIBDOVECOT_STORAGE], [LIBDOVECOT_DSYNC], [LIBDOVECOT_LIBFTS])
+ AX_SUBST_L([LIBDOVECOT_DEPS], [LIBDOVECOT_LOGIN_DEPS], [LIBDOVECOT_SQL_DEPS], [LIBDOVECOT_SSL_DEPS], [LIBDOVECOT_COMPRESS_DEPS], [LIBDOVECOT_LDA_DEPS], [LIBDOVECOT_STORAGE_DEPS], [LIBDOVECOT_DSYNC_DEPS], [LIBDOVECOT_LIBFTS_DEPS])
+ AX_SUBST_L([LIBDOVECOT_INCLUDE], [LIBDOVECOT_LDA_INCLUDE], [LIBDOVECOT_AUTH_INCLUDE], [LIBDOVECOT_DOVEADM_INCLUDE], [LIBDOVECOT_SERVICE_INCLUDE], [LIBDOVECOT_STORAGE_INCLUDE], [LIBDOVECOT_LOGIN_INCLUDE], [LIBDOVECOT_SQL_INCLUDE])
+ AX_SUBST_L([LIBDOVECOT_IMAP_LOGIN_INCLUDE], [LIBDOVECOT_CONFIG_INCLUDE], [LIBDOVECOT_IMAP_INCLUDE], [LIBDOVECOT_POP3_INCLUDE], [LIBDOVECOT_SUBMISSION_INCLUDE], [LIBDOVECOT_LMTP_INCLUDE], [LIBDOVECOT_DSYNC_INCLUDE], [LIBDOVECOT_IMAPC_INCLUDE], [LIBDOVECOT_FTS_INCLUDE])
+ AX_SUBST_L([LIBDOVECOT_NOTIFY_INCLUDE], [LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE], [LIBDOVECOT_ACL_INCLUDE], [LIBDOVECOT_LIBFTS_INCLUDE], [LIBDOVECOT_LUA_INCLUDE])
+ AX_SUBST_L([DOVECOT_LUA_LIBS], [DOVECOT_LUA_CFLAGS], [LIBDOVECOT_LUA], [LIBDOVECOT_LUA_DEPS])
+
+ AM_CONDITIONAL(DOVECOT_INSTALLED, test "$DOVECOT_INSTALLED" = "yes")
+
+ DC_PLUGIN_DEPS
+ DC_DOVECOT_TEST_WRAPPER
+])
+
+AC_DEFUN([DC_CC_WRAPPER],[
+ AS_IF([test "$want_shared_libs" != "yes"], [
+ dnl want_shared_libs=no is for internal use. the liblib.la check is for plugins
+ AS_IF([test "$want_shared_libs" = "no" || echo "$LIBDOVECOT" | grep "/liblib.la" > /dev/null], [
+ AS_IF([test "$with_gnu_ld" = yes], [
+ dnl libtool can't handle using whole-archive flags, so we need to do this
+ dnl with a CC wrapper.. shouldn't be much of a problem, since most people
+ dnl are building with shared libs.
+ cat > cc-wrapper.sh <<_DC_EOF
+#!/bin/sh
+
+if echo "\$[*]" | grep -- -ldl > /dev/null; then
+ # the binary uses plugins. make sure we include everything from .a libs
+ exec $CC -Wl,--whole-archive \$[*] -Wl,--no-whole-archive
+else
+ exec $CC \$[*]
+fi
+_DC_EOF
+ chmod +x cc-wrapper.sh
+ CC=`pwd`/cc-wrapper.sh
+ ])
+ ])
+ ])
+])
+
+AC_DEFUN([DC_PANDOC], [
+ AC_ARG_VAR(PANDOC, [Path to pandoc program])
+
+ dnl Optional tool for making documentation
+ AC_CHECK_PROGS(PANDOC, [pandoc], [true])
+
+ AS_IF([test "$PANDOC" = "true"], [
+ AS_IF([test ! -e README], [
+ AC_MSG_ERROR([Cannot produce documentation without pandoc - disable with PANDOC=false ./configure])
+ ])
+ ])
+])
+# warnings.m4 serial 11
+dnl Copyright (C) 2008-2015 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Simon Josefsson
+
+# gl_AS_VAR_APPEND(VAR, VALUE)
+# ----------------------------
+# Provide the functionality of AS_VAR_APPEND if Autoconf does not have it.
+m4_ifdef([AS_VAR_APPEND],
+[m4_copy([AS_VAR_APPEND], [gl_AS_VAR_APPEND])],
+[m4_define([gl_AS_VAR_APPEND],
+[AS_VAR_SET([$1], [AS_VAR_GET([$1])$2])])])
+
+
+# gl_COMPILER_OPTION_IF(OPTION, [IF-SUPPORTED], [IF-NOT-SUPPORTED],
+# [PROGRAM = AC_LANG_PROGRAM()])
+# -----------------------------------------------------------------
+# Check if the compiler supports OPTION when compiling PROGRAM.
+#
+# FIXME: gl_Warn must be used unquoted until we can assume Autoconf
+# 2.64 or newer.
+AC_DEFUN([gl_COMPILER_OPTION_IF],
+[AS_VAR_PUSHDEF([gl_Warn], [gl_cv_warn_[]_AC_LANG_ABBREV[]_$1])dnl
+AS_VAR_PUSHDEF([gl_Flags], [_AC_LANG_PREFIX[]FLAGS])dnl
+AS_LITERAL_IF([$1],
+ [m4_pushdef([gl_Positive], m4_bpatsubst([$1], [^-Wno-], [-W]))],
+ [gl_positive="$1"
+case $gl_positive in
+ -Wno-*) gl_positive=-W`expr "X$gl_positive" : 'X-Wno-\(.*\)'` ;;
+esac
+m4_pushdef([gl_Positive], [$gl_positive])])dnl
+AC_CACHE_CHECK([whether _AC_LANG compiler handles $1], m4_defn([gl_Warn]), [
+ gl_save_compiler_FLAGS="$gl_Flags"
+ gl_AS_VAR_APPEND(m4_defn([gl_Flags]),
+ [" $gl_unknown_warnings_are_errors ]m4_defn([gl_Positive])["])
+ AC_LINK_IFELSE([m4_default([$4], [AC_LANG_PROGRAM([])])],
+ [AS_VAR_SET(gl_Warn, [yes])],
+ [AS_VAR_SET(gl_Warn, [no])])
+ gl_Flags="$gl_save_compiler_FLAGS"
+])
+AS_VAR_IF(gl_Warn, [yes], [$2], [$3])
+m4_popdef([gl_Positive])dnl
+AS_VAR_POPDEF([gl_Flags])dnl
+AS_VAR_POPDEF([gl_Warn])dnl
+])
+
+# gl_UNKNOWN_WARNINGS_ARE_ERRORS
+# ------------------------------
+# Clang doesn't complain about unknown warning options unless one also
+# specifies -Wunknown-warning-option -Werror. Detect this.
+AC_DEFUN([gl_UNKNOWN_WARNINGS_ARE_ERRORS],
+[gl_COMPILER_OPTION_IF([-Werror -Wunknown-warning-option],
+ [gl_unknown_warnings_are_errors='-Wunknown-warning-option -Werror'],
+ [gl_unknown_warnings_are_errors=])])
+
+# gl_WARN_ADD(OPTION, [VARIABLE = WARN_CFLAGS],
+# [PROGRAM = AC_LANG_PROGRAM()])
+# ---------------------------------------------
+# Adds parameter to WARN_CFLAGS if the compiler supports it when
+# compiling PROGRAM. For example, gl_WARN_ADD([-Wparentheses]).
+#
+# If VARIABLE is a variable name, AC_SUBST it.
+AC_DEFUN([gl_WARN_ADD],
+[AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS])
+gl_COMPILER_OPTION_IF([$1],
+ [gl_AS_VAR_APPEND(m4_if([$2], [], [[WARN_CFLAGS]], [[$2]]), [" $1"])],
+ [],
+ [$3])
+m4_ifval([$2],
+ [AS_LITERAL_IF([$2], [AC_SUBST([$2])])],
+ [AC_SUBST([WARN_CFLAGS])])dnl
+])
+
+# Local Variables:
+# mode: autoconf
+# End:
+dnl * clang check
+AC_DEFUN([CC_CLANG],[
+ AC_MSG_CHECKING([whether $CC is clang 3.3+])
+ AS_IF([$CC -dM -E -x c /dev/null | grep __clang__ > /dev/null 2>&1], [
+ AS_VAR_SET([have_clang], [yes])
+ ], [
+ AS_VAR_SET([have_clang], [no])
+ ])
+ AC_MSG_RESULT([$have_clang])
+])
+
+AC_DEFUN([DOVECOT_WANT_UBSAN], [
+ AC_ARG_ENABLE(ubsan,
+ AS_HELP_STRING([--enable-ubsan], [Enable undefined behaviour sanitizes (default=no)]),
+ [want_ubsan=yes], [want_ubsan=no])
+ AC_MSG_CHECKING([whether we want undefined behaviour sanitizer])
+ AC_MSG_RESULT([$want_ubsan])
+ AS_IF([test x$want_ubsan = xyes], [
+ san_flags=""
+ gl_COMPILER_OPTION_IF([-fsanitize=undefined], [
+ san_flags="$san_flags -fsanitize=undefined"
+ AC_DEFINE([HAVE_FSANITIZE_UNDEFINED], [1], [Define if your compiler has -fsanitize=undefined])
+ ])
+ gl_COMPILER_OPTION_IF([-fno-sanitize=nonnull-attribute], [
+ san_flags="$san_flags -fno-sanitize=nonnull-attribute"
+ AC_DEFINE([HAVE_FNO_SANITIZE_NONNULL_ATTRIBUTE], [1], [Define if your compiler has -fno-sanitize=nonnull-attribute])
+ ])
+ gl_COMPILER_OPTION_IF([-fsanitize=implicit-integer-truncation], [
+ san_flags="$san_flags -fsanitize=implicit-integer-truncation"
+ AC_DEFINE([HAVE_FSANITIZE_IMPLICIT_INTEGER_TRUNCATION], [1], [Define if your compiler has -fsanitize=implicit-integer-truncation])
+ ])
+ gl_COMPILER_OPTION_IF([-fsanitize=local-bounds], [
+ san_flags="$san_flags -fsanitize=local-bounds"
+ AC_DEFINE([HAVE_FSANITIZE_LOCAL_BOUNDS], [1], [Define if your compiler has -fsanitize=local-bounds])
+ ])
+ gl_COMPILER_OPTION_IF([-fsanitize=integer], [
+ san_flags="$san_flags -fsanitize=integer"
+ AC_DEFINE([HAVE_FSANITIZE_INTEGER], [1], [Define if your compiler has -fsanitize=integer])
+ ])
+ gl_COMPILER_OPTION_IF([-fsanitize=nullability], [
+ san_flags="$san_flags -fsanitize=nullability"
+ AC_DEFINE([HAVE_FSANITIZE_NULLABILITY], [1], [Define if your compiler has -fsanitize=nullability])
+ ])
+ AS_IF([test "$san_flags" != "" ], [
+ EXTRA_CFLAGS="$EXTRA_CFLAGS $san_flags -U_FORTIFY_SOURCE -g -ggdb3 -O0 -fno-omit-frame-pointer"
+ AC_DEFINE([HAVE_UNDEFINED_SANITIZER], [1], [Define if your compiler supports undefined sanitizers])
+ ], [
+ AC_MSG_ERROR([No undefined sanitizer support in your compiler])
+ ])
+ san_flags=""
+ ])
+])
diff --git a/pigeonhole/m4/libtool.m4 b/pigeonhole/m4/libtool.m4
new file mode 100644
index 0000000..c4c0294
--- /dev/null
+++ b/pigeonhole/m4/libtool.m4
@@ -0,0 +1,8394 @@
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+# Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program or library that is built
+# using GNU Libtool, you may include this file under the same
+# distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+])
+
+# serial 58 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+ [m4_default([$3],
+ [m4_fatal([Libtool version $1 or higher is required],
+ 63)])],
+ [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+ *\ * | *\ *)
+ AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS=$ltmain
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_PREPARE_CC_BASENAME
+# -----------------------
+m4_defun([_LT_PREPARE_CC_BASENAME], [
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+ for cc_temp in @S|@*""; do
+ case $cc_temp in
+ compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+ distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+ done
+ func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+])# _LT_PREPARE_CC_BASENAME
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME,
+# but that macro is also expanded into generated libtool script, which
+# arranges for $SED and $ECHO to be set by different means.
+m4_defun([_LT_CC_BASENAME],
+[m4_require([_LT_PREPARE_CC_BASENAME])dnl
+AC_REQUIRE([_LT_DECL_SED])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+func_cc_basename $1
+cc_basename=$func_cc_basename_result
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
+dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_WITH_SYSROOT])dnl
+m4_require([_LT_CMD_TRUNCATE])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options that allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}"; then
+ setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}"; then
+ setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test set != "${COLLECT_NAMES+set}"; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a '.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+old_CC=$CC
+old_CFLAGS=$CFLAGS
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ _LT_PATH_MAGIC
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from 'configure', and 'config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably,
+# 'config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain=$ac_aux_dir/ltmain.sh
+])# _LT_PROG_LTMAIN
+
+
+## ------------------------------------- ##
+## Accumulate code for creating libtool. ##
+## ------------------------------------- ##
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the 'libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+ [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+## ------------------------ ##
+## FIXME: Eliminate VARNAME ##
+## ------------------------ ##
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME. Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+ [m4_ifval([$1], [$1], [$2])])
+ lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+ m4_ifval([$4],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+ lt_dict_add_subkey([lt_decl_dict], [$2],
+ [tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+ [0], [m4_fatal([$0: too few arguments: $#])],
+ [1], [m4_fatal([$0: too few arguments: $#: $1])],
+ [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+ [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+ [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+ m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_if([$2], [],
+ m4_quote(lt_decl_varnames),
+ m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+ lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to 'config.status' so that its
+# declaration there will have the same value as in 'configure'. VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly. In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+# <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+ [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags='_LT_TAGS'dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+# # Some comment about what VAR is for.
+# visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+ [description])))[]dnl
+m4_pushdef([_libtool_name],
+ m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+ [0], [_libtool_name=[$]$1],
+ [1], [_libtool_name=$lt_[]$1],
+ [2], [_libtool_name=$lt_[]$1],
+ [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the 'libtool'
+# script. Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+ m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into 'config.status', and then the shell code to quote escape them in
+# for loops in 'config.status'. Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+ dnl If the libtool generation code has been placed in $CONFIG_LT,
+ dnl instead of duplicating it all over again into config.status,
+ dnl then we will have config.status run $CONFIG_LT later, so it
+ dnl needs to know what name is stored there:
+ [AC_CONFIG_COMMANDS([libtool],
+ [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+ dnl If the libtool generation code is destined for config.status,
+ dnl expand the accumulated commands and init code now:
+ [AC_CONFIG_COMMANDS([libtool],
+ [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable. If COMMENT is supplied, it is inserted after the
+# '#!' sequence but before initialization text begins. After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script. The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test 0 = "$lt_write_fail" && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+ echo
+ AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+'$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+
+Report bugs to <bug-libtool@gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2011 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test 0 != $[#]
+do
+ case $[1] in
+ --version | --v* | -V )
+ echo "$lt_cl_version"; exit 0 ;;
+ --help | --h* | -h )
+ echo "$lt_cl_help"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --quiet | --q* | --silent | --s* | -q )
+ lt_cl_silent=: ;;
+
+ -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try '$[0] --help' for more information.]) ;;
+
+ *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try '$[0] --help' for more information.]) ;;
+ esac
+ shift
+done
+
+if $lt_cl_silent; then
+ exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure. Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test yes = "$silent" &&
+ lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars. Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+ m4_if(_LT_TAG, [C], [
+ # See if we are running on zsh, and set the options that allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}"; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile=${ofile}T
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+# Generated automatically by $as_me ($PACKAGE) $VERSION
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit, 1996
+
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# Configured defaults for sys_lib_dlsearch_path munging.
+: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ cat <<'_LT_EOF' >> "$cfgfile"
+
+# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_PREPARE_MUNGE_PATH_LIST
+_LT_PREPARE_CC_BASENAME
+
+# ### END FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test set != "${COLLECT_NAMES+set}"; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+ _LT_PROG_LTMAIN
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ RM='$RM'
+ ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+# autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+ [C], [_LT_LANG(C)],
+ [C++], [_LT_LANG(CXX)],
+ [Go], [_LT_LANG(GO)],
+ [Java], [_LT_LANG(GCJ)],
+ [Fortran 77], [_LT_LANG(F77)],
+ [Fortran], [_LT_LANG(FC)],
+ [Windows Resource], [_LT_LANG(RC)],
+ [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+ [_LT_LANG($1)],
+ [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+ [LT_SUPPORTED_TAG([$1])dnl
+ m4_append([_LT_TAGS], [$1 ])dnl
+ m4_define([_LT_LANG_]$1[_enabled], [])dnl
+ _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+m4_ifndef([AC_PROG_GO], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_GO. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+############################################################
+m4_defun([AC_PROG_GO],
+[AC_LANG_PUSH(Go)dnl
+AC_ARG_VAR([GOC], [Go compiler command])dnl
+AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
+_AC_ARG_VAR_LDFLAGS()dnl
+AC_CHECK_TOOL(GOC, gccgo)
+if test -z "$GOC"; then
+ if test -n "$ac_tool_prefix"; then
+ AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
+ fi
+fi
+if test -z "$GOC"; then
+ AC_CHECK_PROG(GOC, gccgo, gccgo, false)
+fi
+])#m4_defun
+])#m4_ifndef
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [LT_LANG(CXX)],
+ [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+ [LT_LANG(F77)],
+ [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+ [LT_LANG(FC)],
+ [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [m4_ifdef([AC_PROG_GCJ],
+ [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([A][M_PROG_GCJ],
+ [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([LT_PROG_GCJ],
+ [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([AC_PROG_GO],
+ [LT_LANG(GO)],
+ [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+ [LT_LANG(RC)],
+ [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+ case $host_os in
+ rhapsody* | darwin*)
+ AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+ AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+ AC_CHECK_TOOL([LIPO], [lipo], [:])
+ AC_CHECK_TOOL([OTOOL], [otool], [:])
+ AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+ _LT_DECL([], [DSYMUTIL], [1],
+ [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+ _LT_DECL([], [NMEDIT], [1],
+ [Tool to change global to local symbols on Mac OS X])
+ _LT_DECL([], [LIPO], [1],
+ [Tool to manipulate fat objects and archives on Mac OS X])
+ _LT_DECL([], [OTOOL], [1],
+ [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+ _LT_DECL([], [OTOOL64], [1],
+ [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+ AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+ [lt_cv_apple_cc_single_mod=no
+ if test -z "$LT_MULTI_MODULE"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ # If there is a non-empty error log, and "single_module"
+ # appears in it, assume the flag caused a linker warning
+ if test -s conftest.err && $GREP single_module conftest.err; then
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ # Otherwise, if the output was created with a 0 exit code from
+ # the compiler, it worked.
+ elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi])
+
+ AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+ [lt_cv_ld_exported_symbols_list],
+ [lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [lt_cv_ld_exported_symbols_list=yes],
+ [lt_cv_ld_exported_symbols_list=no])
+ LDFLAGS=$save_LDFLAGS
+ ])
+
+ AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+ [lt_cv_ld_force_load=no
+ cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+ echo "$AR cr libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+ $AR cr libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+ echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
+ $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
+ cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+ _lt_result=$?
+ if test -s conftest.err && $GREP force_load conftest.err; then
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
+ lt_cv_ld_force_load=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -f conftest.err libconftest.a conftest conftest.c
+ rm -rf conftest.dSYM
+ ])
+ case $host_os in
+ rhapsody* | darwin1.[[012]])
+ _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[[912]]*)
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+ 10.[[012]][[,.]]*)
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+ 10.*|11.*)
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test yes = "$lt_cv_apple_cc_single_mod"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test yes = "$lt_cv_ld_exported_symbols_list"; then
+ _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
+ fi
+ if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES([TAG])
+# ---------------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+ m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_automatic, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ if test yes = "$lt_cv_ld_force_load"; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
+ [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes])
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined
+ case $cc_basename in
+ ifort*|nagfor*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test yes = "$_lt_dar_can_shared"; then
+ output_verbose_link_cmd=func_echo_all
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+ _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+ _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
+ m4_if([$1], [CXX],
+[ if test yes != "$lt_cv_apple_cc_single_mod"; then
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
+ fi
+],[])
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
+# ----------------------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+# Store the results from the different compilers for each TAGNAME.
+# Allow to override them for all tags through lt_cv_aix_libpath.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+if test set = "${lt_cv_aix_libpath+set}"; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
+ [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
+ lt_aix_libpath_sed='[
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }]'
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi],[])
+ if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib
+ fi
+ ])
+ aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
+fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script that will find a shell with a builtin
+# printf (that we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO "$*"
+}
+
+case $ECHO in
+ printf*) AC_MSG_RESULT([printf]) ;;
+ print*) AC_MSG_RESULT([print -r]) ;;
+ *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+ PATH=/empty FPATH=/empty; export PATH FPATH
+ test "X`printf %s $ECHO`" = "X$ECHO" \
+ || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_WITH_SYSROOT
+# ----------------
+AC_DEFUN([_LT_WITH_SYSROOT],
+[AC_MSG_CHECKING([for sysroot])
+AC_ARG_WITH([sysroot],
+[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@],
+ [Search for dependent libraries within DIR (or the compiler's sysroot
+ if not specified).])],
+[], [with_sysroot=no])
+
+dnl lt_sysroot will always be passed unquoted. We quote it here
+dnl in case the user passed a directory name.
+lt_sysroot=
+case $with_sysroot in #(
+ yes)
+ if test yes = "$GCC"; then
+ lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+ fi
+ ;; #(
+ /*)
+ lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+ ;; #(
+ no|'')
+ ;; #(
+ *)
+ AC_MSG_RESULT([$with_sysroot])
+ AC_MSG_ERROR([The sysroot must be an absolute path.])
+ ;;
+esac
+
+ AC_MSG_RESULT([${lt_sysroot:-no}])
+_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
+[dependent libraries, and where our libraries should be installed.])])
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+ [AS_HELP_STRING([--disable-libtool-lock],
+ [avoid locking (might break parallel builds)])])
+test no = "$enable_libtool_lock" || enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out what ABI is being produced by ac_compile, and set mode
+ # options accordingly.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE=32
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE=64
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ if test yes = "$lt_cv_prog_gnu_ld"; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+mips64*-*linux*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ emul=elf
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ emul="${emul}32"
+ ;;
+ *64-bit*)
+ emul="${emul}64"
+ ;;
+ esac
+ case `/usr/bin/file conftest.$ac_objext` in
+ *MSB*)
+ emul="${emul}btsmip"
+ ;;
+ *LSB*)
+ emul="${emul}ltsmip"
+ ;;
+ esac
+ case `/usr/bin/file conftest.$ac_objext` in
+ *N32*)
+ emul="${emul}n32"
+ ;;
+ esac
+ LD="${LD-ld} -m $emul"
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly. Note that the listed cases only cover the
+ # situations where additional linker options are needed (such as when
+ # doing 32-bit compilation for a host where ld defaults to 64-bit, or
+ # vice versa); the common cases where no linker options are needed do
+ # not appear in the list.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ case `/usr/bin/file conftest.o` in
+ *x86-64*)
+ LD="${LD-ld} -m elf32_x86_64"
+ ;;
+ *)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ esac
+ ;;
+ powerpc64le-*linux*)
+ LD="${LD-ld} -m elf32lppclinux"
+ ;;
+ powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ powerpcle-*linux*)
+ LD="${LD-ld} -m elf64lppc"
+ ;;
+ powerpc-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -belf"
+ AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+ [AC_LANG_PUSH(C)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+ AC_LANG_POP])
+ if test yes != "$lt_cv_cc_needs_belf"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS=$SAVE_CFLAGS
+ fi
+ ;;
+*-*solaris*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*)
+ case $host in
+ i?86-*-solaris*|x86_64-*-solaris*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ sparc*-*-solaris*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
+ if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+ LD=${LD-ld}_sol2
+ fi
+ ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks=$enable_libtool_lock
+])# _LT_ENABLE_LOCK
+
+
+# _LT_PROG_AR
+# -----------
+m4_defun([_LT_PROG_AR],
+[AC_CHECK_TOOLS(AR, [ar], false)
+: ${AR=ar}
+: ${AR_FLAGS=cr}
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
+
+AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
+ [lt_cv_ar_at_file=no
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
+ [echo conftest.$ac_objext > conftest.lst
+ lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
+ AC_TRY_EVAL([lt_ar_try])
+ if test 0 -eq "$ac_status"; then
+ # Ensure the archiver fails upon bogus file names.
+ rm -f conftest.$ac_objext libconftest.a
+ AC_TRY_EVAL([lt_ar_try])
+ if test 0 -ne "$ac_status"; then
+ lt_cv_ar_at_file=@
+ fi
+ fi
+ rm -f conftest.* libconftest.a
+ ])
+ ])
+
+if test no = "$lt_cv_ar_at_file"; then
+ archiver_list_spec=
+else
+ archiver_list_spec=$lt_cv_ar_at_file
+fi
+_LT_DECL([], [archiver_list_spec], [1],
+ [How to feed a file listing to the archiver])
+])# _LT_PROG_AR
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[_LT_PROG_AR
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+ [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ bitrig* | openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+ darwin*)
+ lock_old_archive_extraction=yes ;;
+ *)
+ lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+ [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+ [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ fi
+ $RM conftest*
+])
+
+if test yes = "[$]$2"; then
+ m4_if([$5], , :, [$5])
+else
+ m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ save_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS $3"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&AS_MESSAGE_LOG_FD
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ else
+ $2=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS=$save_LDFLAGS
+])
+
+if test yes = "[$]$2"; then
+ m4_if([$4], , :, [$4])
+else
+ m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+ i=0
+ teststring=ABCD
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ os2*)
+ # The test takes a long time on OS/2.
+ lt_cv_sys_max_cmd_len=8192
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len" && \
+ test undefined != "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test X`env echo "$teststring$teststring" 2>/dev/null` \
+ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+ test 17 != "$i" # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+])
+if test -n "$lt_cv_sys_max_cmd_len"; then
+ AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+ AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+ [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test yes = "$cross_compiling"; then :
+ [$4]
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+[#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisibility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}]
+_LT_EOF
+ if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then
+ (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) $1 ;;
+ x$lt_dlneed_uscore) $2 ;;
+ x$lt_dlunknown|x*) $3 ;;
+ esac
+ else :
+ # compilation failed
+ $3
+ fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test yes != "$enable_dlopen"; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen=load_add_on
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen=LoadLibrary
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen=dlopen
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[
+ lt_cv_dlopen=dyld
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ])
+ ;;
+
+ tpf*)
+ # Don't try to run any link tests for TPF. We know it's impossible
+ # because TPF is a cross-compiler, and we know how we open DSOs.
+ lt_cv_dlopen=dlopen
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=no
+ ;;
+
+ *)
+ AC_CHECK_FUNC([shl_load],
+ [lt_cv_dlopen=shl_load],
+ [AC_CHECK_LIB([dld], [shl_load],
+ [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld],
+ [AC_CHECK_FUNC([dlopen],
+ [lt_cv_dlopen=dlopen],
+ [AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],
+ [AC_CHECK_LIB([svld], [dlopen],
+ [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld],
+ [AC_CHECK_LIB([dld], [dld_link],
+ [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld])
+ ])
+ ])
+ ])
+ ])
+ ])
+ ;;
+ esac
+
+ if test no = "$lt_cv_dlopen"; then
+ enable_dlopen=no
+ else
+ enable_dlopen=yes
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS=$CPPFLAGS
+ test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS=$LDFLAGS
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS=$LIBS
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ AC_CACHE_CHECK([whether a program can dlopen itself],
+ lt_cv_dlopen_self, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+ lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+ ])
+
+ if test yes = "$lt_cv_dlopen_self"; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+ lt_cv_dlopen_self_static, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+ lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
+ ])
+ fi
+
+ CPPFLAGS=$save_CPPFLAGS
+ LDFLAGS=$save_LDFLAGS
+ LIBS=$save_LIBS
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+ [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+ [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+ [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+ fi
+ fi
+ chmod u+w . 2>&AS_MESSAGE_LOG_FD
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+ [Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links=nottested
+if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then
+ # do not overwrite the value of need_locks provided by the user
+ AC_MSG_CHECKING([if we can lock with hard links])
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ AC_MSG_RESULT([$hard_links])
+ if test no = "$hard_links"; then
+ AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe])
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+ [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/",
+ [Define to the sub-directory where libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+ test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+ test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then
+
+ # We can hardcode non-existent directories.
+ if test no != "$_LT_TAGVAR(hardcode_direct, $1)" &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" &&
+ test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then
+ # Linking always hardcodes the temporary library directory.
+ _LT_TAGVAR(hardcode_action, $1)=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ _LT_TAGVAR(hardcode_action, $1)=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test relink = "$_LT_TAGVAR(hardcode_action, $1)" ||
+ test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test yes = "$shlibpath_overrides_runpath" ||
+ test no = "$enable_shared"; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+ [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP"; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ ;;
+ *)
+ AC_MSG_RESULT([no])
+ ;;
+ esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_PREPARE_MUNGE_PATH_LIST
+# ---------------------------
+# Make sure func_munge_path_list() is defined correctly.
+m4_defun([_LT_PREPARE_MUNGE_PATH_LIST],
+[[# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+# string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+# string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+# string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+# "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+# VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+ case x@S|@2 in
+ x)
+ ;;
+ *:)
+ eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\"
+ ;;
+ x:*)
+ eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\"
+ ;;
+ *::*)
+ eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+ eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\"
+ ;;
+ *)
+ eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\"
+ ;;
+ esac
+}
+]])# _LT_PREPARE_PATH_LIST
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+ [], [
+if test yes = "$GCC"; then
+ case $host_os in
+ darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
+ *) lt_awk_arg='/^libraries:/' ;;
+ esac
+ case $host_os in
+ mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;;
+ *) lt_sed_strip_eq='s|=/|/|g' ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+ case $lt_search_path_spec in
+ *\;*)
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+ ;;
+ *)
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ esac
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary...
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ # ...but if some path component already ends with the multilib dir we assume
+ # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
+ case "$lt_multi_os_dir; $lt_search_path_spec " in
+ "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
+ lt_multi_os_dir=
+ ;;
+ esac
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
+ elif test -n "$lt_multi_os_dir"; then
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS = " "; FS = "/|\n";} {
+ lt_foo = "";
+ lt_count = 0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo = "/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+ if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+ # AWK program above erroneously prepends '/' to C:/dos/paths
+ # for these hosts.
+ case $host_os in
+ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;;
+ esac
+ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=.so
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+AC_ARG_VAR([LT_SYS_LIBRARY_PATH],
+[User-defined run-time library search path.])
+
+case $host_os in
+aix3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+
+aix[[4-9]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 supports IA64
+ library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line '#! .'. This would cause the generated library to
+ # depend on '.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[[01]] | aix4.[[01]].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # Using Import Files as archive members, it is possible to support
+ # filename-based versioning of shared library archives on AIX. While
+ # this would work for both with and without runtime linking, it will
+ # prevent static linking of such archives. So we do filename-based
+ # shared library versioning with .so extension only, which is used
+ # when both runtime linking and shared linking is enabled.
+ # Unfortunately, runtime linking may impact performance, so we do
+ # not want this to be the default eventually. Also, we use the
+ # versioned .so libs for executables only if there is the -brtl
+ # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+ # To allow for filename-based versioning support, we need to create
+ # libNAME.so.V as an archive file, containing:
+ # *) an Import File, referring to the versioned filename of the
+ # archive as well as the shared archive member, telling the
+ # bitwidth (32 or 64) of that shared object, and providing the
+ # list of exported symbols of that shared object, eventually
+ # decorated with the 'weak' keyword
+ # *) the shared object with the F_LOADONLY flag set, to really avoid
+ # it being seen by the linker.
+ # At run time we better use the real file rather than another symlink,
+ # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+ case $with_aix_soname,$aix_use_runtimelinking in
+ # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ aix,yes) # traditional libtool
+ dynamic_linker='AIX unversionable lib.so'
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ ;;
+ aix,no) # traditional AIX only
+ dynamic_linker='AIX lib.a[(]lib.so.V[)]'
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+ svr4,*) # full svr4 only
+ dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,yes) # both, prefer svr4
+ dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # unpreferred sharedlib libNAME.a needs extra handling
+ postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+ postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,no) # both, prefer aix
+ dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]"
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+ postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+ postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+ ;;
+ esac
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='$libname$shared_ext'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[[45]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=.dll
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$cc_basename in
+ yes,*)
+ # gcc
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ ;;
+
+ *,cl*)
+ # Native MSVC
+ libname_spec='$name'
+ soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+ library_names_spec='$libname.dll.lib'
+
+ case $build_os in
+ mingw*)
+ sys_lib_search_path_spec=
+ lt_save_ifs=$IFS
+ IFS=';'
+ for lt_path in $LIB
+ do
+ IFS=$lt_save_ifs
+ # Let DOS variable expansion print the short 8.3 style file name.
+ lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+ sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+ done
+ IFS=$lt_save_ifs
+ # Convert to MSYS style.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
+ ;;
+ cygwin*)
+ # Convert to unix form, then to dos form, then back to unix form
+ # but this time dos style (no spaces!) so that the unix form looks
+ # like /cygdrive/c/PROGRA~1:/cygdr...
+ sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+ sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+ sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ *)
+ sys_lib_search_path_spec=$LIB
+ if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+ # It is most probably a Windows format PATH.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # FIXME: find the short name or the path components, as spaces are
+ # common. (e.g. "Program Files" -> "PROGRA~1")
+ ;;
+ esac
+
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+ dynamic_linker='Win32 link.exe'
+ ;;
+
+ *)
+ # Assume MSVC wrapper
+ library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib'
+ dynamic_linker='Win32 ld.exe'
+ ;;
+ esac
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$major$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[[23]].*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2.*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+haiku*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ if test 32 = "$HPUX_IA64_MODE"; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux32
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux64
+ fi
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[[3-9]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test yes = "$lt_cv_prog_gnu_ld"; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+ sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+linux*android*)
+ version_type=none # Android doesn't support versioned libraries.
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext'
+ soname_spec='$libname$release$shared_ext'
+ finish_cmds=
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ dynamic_linker='Android linker'
+ # Don't embed -rpath directories since the linker doesn't support them.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+ [lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+ [lt_cv_shlibpath_overrides_runpath=yes])])
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+ ])
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Ideally, we could use ldconfig to report *all* directores which are
+ # searched for libraries, however this is still not possible. Aside from not
+ # being certain /sbin/ldconfig is available, command
+ # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+ # even though it is searched at run-time. Try to do the best guess by
+ # appending ld.so.conf contents (and includes) to the search path.
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsdelf*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='NetBSD ld.elf_so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd* | bitrig*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec=/usr/lib
+ need_lib_prefix=no
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ need_version=no
+ else
+ need_version=yes
+ fi
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+os2*)
+ libname_spec='$name'
+ version_type=windows
+ shrext_cmds=.dll
+ need_version=no
+ need_lib_prefix=no
+ # OS/2 can only load a DLL with a base name of 8 characters or less.
+ soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+ v=$($ECHO $release$versuffix | tr -d .-);
+ n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+ $ECHO $n$v`$shared_ext'
+ library_names_spec='${libname}_dll.$libext'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=BEGINLIBPATH
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test yes = "$with_gnu_ld"; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+ soname_spec='$libname$shared_ext.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=sco
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test yes = "$with_gnu_ld"; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test no = "$dynamic_linker" && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test yes = "$GCC"; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+ sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
+fi
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+ sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
+fi
+
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+ [Variables whose values should be saved in libtool wrapper scripts and
+ restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+ [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+ [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+ [[List of archive names. First name is the real one, the rest are links.
+ The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+ [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+ [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+ [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+ [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+ [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+ [[As "finish_cmds", except a single script fragment to be evaled but
+ not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+ [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+ [Compile-time system search path for libraries])
+_LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2],
+ [Detected run-time system search path for libraries])
+_LT_DECL([], [configure_time_lt_sys_library_path], [2],
+ [Explicit LT_SYS_LIBRARY_PATH set during ./configure time])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program that can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] | ?:[\\/]*])
+ lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD=$MAGIC_CMD
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word. This closes a longstanding sh security hole.
+ ac_dummy="m4_if([$2], , $PATH, [$2])"
+ for ac_dir in $ac_dummy; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$1"; then
+ lt_cv_path_MAGIC_CMD=$ac_dir/"$1"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS=$lt_save_ifs
+ MAGIC_CMD=$lt_save_MAGIC_CMD
+ ;;
+esac])
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+if test -n "$MAGIC_CMD"; then
+ AC_MSG_RESULT($MAGIC_CMD)
+else
+ AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+ [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program that can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+ else
+ MAGIC_CMD=:
+ fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+ [AS_HELP_STRING([--with-gnu-ld],
+ [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+ [test no = "$withval" || with_gnu_ld=yes],
+ [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test yes = "$GCC"; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by $CC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return, which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]]* | ?:[[\\/]]*)
+ re_direlt='/[[^/]][[^/]]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD=$ac_prog
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test yes = "$with_gnu_ld"; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD=$ac_dir/$ac_prog
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test no != "$with_gnu_ld" && break
+ ;;
+ *)
+ test yes != "$with_gnu_ld" && break
+ ;;
+ esac
+ fi
+ done
+ IFS=$lt_save_ifs
+else
+ lt_cv_path_LD=$LD # Let the user override the test with a path.
+fi])
+LD=$lt_cv_path_LD
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+# -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+ lt_cv_ld_reload_flag,
+ [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ if test yes != "$GCC"; then
+ reload_cmds=false
+ fi
+ ;;
+ darwin*)
+ if test yes = "$GCC"; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_PATH_DD
+# -----------
+# find a working dd
+m4_defun([_LT_PATH_DD],
+[AC_CACHE_CHECK([for a working dd], [ac_cv_path_lt_DD],
+[printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+: ${lt_DD:=$DD}
+AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd],
+[if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+ cmp -s conftest.i conftest.out \
+ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
+fi])
+rm -f conftest.i conftest2.i conftest.out])
+])# _LT_PATH_DD
+
+
+# _LT_CMD_TRUNCATE
+# ----------------
+# find command to truncate a binary pipe
+m4_defun([_LT_CMD_TRUNCATE],
+[m4_require([_LT_PATH_DD])
+AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin],
+[printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+lt_cv_truncate_bin=
+if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+ cmp -s conftest.i conftest.out \
+ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
+fi
+rm -f conftest.i conftest2.i conftest.out
+test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"])
+_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1],
+ [Command to truncate a binary pipe])
+])# _LT_CMD_TRUNCATE
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+# -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# 'unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# that responds to the $file_magic_cmd with a given extended regex.
+# If you have 'file' or equivalent on your system and you're not sure
+# whether 'pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[[45]]*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ if ( file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ # Keep this pattern in sync with the one in func_win32_libid.
+ lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc*)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+haiku*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[[3-9]]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd* | bitrig*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+os2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+])
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+ case $host_os in
+ mingw* | pw32*)
+ if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+ want_nocaseglob=yes
+ else
+ file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
+ fi
+ ;;
+ esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+ [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+ [Command to use when deplibs_check_method = "file_magic"])
+_LT_DECL([], [file_magic_glob], [1],
+ [How to find potential files when deplibs_check_method = "file_magic"])
+_LT_DECL([], [want_nocaseglob], [1],
+ [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM=$NM
+else
+ lt_nm_to_check=${ac_tool_prefix}nm
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm=$ac_dir/$lt_tmp_nm
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the 'sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
+ case $build_os in
+ mingw*) lt_bad_file=conftest.nm/nofile ;;
+ *) lt_bad_file=/dev/null ;;
+ esac
+ case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+ *$lt_bad_file* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break 2
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break 2
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS=$lt_save_ifs
+ done
+ : ${lt_cv_path_NM=no}
+fi])
+if test no != "$lt_cv_path_NM"; then
+ NM=$lt_cv_path_NM
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$DUMPBIN"; then :
+ # Let the user override the test.
+ else
+ AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+ case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
+ *COFF*)
+ DUMPBIN="$DUMPBIN -symbols -headers"
+ ;;
+ *)
+ DUMPBIN=:
+ ;;
+ esac
+ fi
+ AC_SUBST([DUMPBIN])
+ if test : != "$DUMPBIN"; then
+ NM=$DUMPBIN
+ fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+ [lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+ cat conftest.out >&AS_MESSAGE_LOG_FD
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+# --------------------------------
+# how to determine the name of the shared library
+# associated with a specific link library.
+# -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+m4_require([_LT_DECL_DLLTOOL])
+AC_CACHE_CHECK([how to associate runtime and link libraries],
+lt_cv_sharedlib_from_linklib_cmd,
+[lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+ # two different shell functions defined in ltmain.sh;
+ # decide which one to use based on capabilities of $DLLTOOL
+ case `$DLLTOOL --help 2>&1` in
+ *--identify-strict*)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+ ;;
+ *)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+ ;;
+ esac
+ ;;
+*)
+ # fallback: assume linklib IS sharedlib
+ lt_cv_sharedlib_from_linklib_cmd=$ECHO
+ ;;
+esac
+])
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
+ [Command to associate shared and link libraries])
+])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+
+
+# _LT_PATH_MANIFEST_TOOL
+# ----------------------
+# locate the manifest tool
+m4_defun([_LT_PATH_MANIFEST_TOOL],
+[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
+ [lt_cv_path_mainfest_tool=no
+ echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
+ $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+ lt_cv_path_mainfest_tool=yes
+ fi
+ rm -f conftest*])
+if test yes != "$lt_cv_path_mainfest_tool"; then
+ MANIFEST_TOOL=:
+fi
+_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
+])# _LT_PATH_MANIFEST_TOOL
+
+
+# _LT_DLL_DEF_P([FILE])
+# ---------------------
+# True iff FILE is a Windows DLL '.def' file.
+# Keep in sync with func_dll_def_p in the libtool script
+AC_DEFUN([_LT_DLL_DEF_P],
+[dnl
+ test DEF = "`$SED -n dnl
+ -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace
+ -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments
+ -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl
+ -e q dnl Only consider the first "real" line
+ $1`" dnl
+])# _LT_DLL_DEF_P
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+ # These system don't have libm, or don't need it
+ ;;
+*-ncr-sysv4.3*)
+ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw)
+ AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+ ;;
+*)
+ AC_CHECK_LIB(m, cos, LIBM=-lm)
+ ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test yes = "$GCC"; then
+ case $cc_basename in
+ nvcc*)
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+ esac
+
+ _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+ lt_cv_prog_compiler_rtti_exceptions,
+ [-fno-rtti -fno-exceptions], [],
+ [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+ [Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[[BCDT]]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[[ABCDGISTW]]'
+ ;;
+hpux*)
+ if test ia64 = "$host_cpu"; then
+ symcode='[[ABCDEGRST]]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[[BCDEGRST]]'
+ ;;
+osf*)
+ symcode='[[BCDEGQRST]]'
+ ;;
+solaris*)
+ symcode='[[BDRT]]'
+ ;;
+sco3.2v5*)
+ symcode='[[DT]]'
+ ;;
+sysv4.2uw2*)
+ symcode='[[DT]]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[[ABDT]]'
+ ;;
+sysv4)
+ symcode='[[DFNSTU]]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Gets list of data symbols to import.
+ lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
+ # Adjust the below global symbol transforms to fixup imported variables.
+ lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
+ lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'"
+ lt_c_name_lib_hook="\
+ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\
+ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'"
+else
+ # Disable hooks by default.
+ lt_cv_sys_global_symbol_to_import=
+ lt_cdecl_hook=
+ lt_c_name_hook=
+ lt_c_name_lib_hook=
+fi
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n"\
+$lt_cdecl_hook\
+" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
+$lt_c_name_hook\
+" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'"
+
+# Transform an extracted symbol line into symbol name with lib prefix and
+# symbol address.
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
+$lt_c_name_lib_hook\
+" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function,
+ # D for any global variable and I for any imported variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK ['"\
+" {last_section=section; section=\$ 3};"\
+" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
+" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
+" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
+" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
+" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx]"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+ lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if AC_TRY_EVAL(ac_compile); then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&AS_MESSAGE_LOG_FD
+ if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&AS_MESSAGE_LOG_FD && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
+ relocations are performed -- see ld's documentation on pseudo-relocs. */
+# define LT@&t@_DLSYM_CONST
+#elif defined __osf__
+/* This system does not cope well with relocations in const data. */
+# define LT@&t@_DLSYM_CONST
+#else
+# define LT@&t@_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+LT@&t@_DLSYM_CONST struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_globsym_save_LIBS=$LIBS
+ lt_globsym_save_CFLAGS=$CFLAGS
+ LIBS=conftstm.$ac_objext
+ CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+ if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then
+ pipe_works=yes
+ fi
+ LIBS=$lt_globsym_save_LIBS
+ CFLAGS=$lt_globsym_save_CFLAGS
+ else
+ echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test yes = "$pipe_works"; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ AC_MSG_RESULT(failed)
+else
+ AC_MSG_RESULT(ok)
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
+ nm_file_list_spec='@'
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+ [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+ [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1],
+ [Transform the output of nm into a list of symbols to manually relocate])
+_LT_DECL([global_symbol_to_c_name_address],
+ [lt_cv_sys_global_symbol_to_c_name_address], [1],
+ [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+ [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+ [Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([nm_interface], [lt_cv_nm_interface], [1],
+ [The name lister interface])
+_LT_DECL([], [nm_file_list_spec], [1],
+ [Specify filename containing input files for $NM])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+m4_if([$1], [CXX], [
+ # C++ specific cases for pic, static, wl, etc.
+ if test yes = "$GXX"; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the '-m68020' flag to GCC prevents building anything better,
+ # like '-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ case $host_os in
+ os2*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+ ;;
+ esac
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)=
+ ;;
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix[[4-9]]*)
+ # All AIX code is PIC.
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68*)
+ # Green Hills C++ Compiler
+ # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | dragonfly*)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+ if test ia64 != "$host_cpu"; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ fi
+ ;;
+ aCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ interix*)
+ # This is c89, which is MS Visual C++ (no shared libs)
+ # Anyone wants to do a port?
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ KCC*)
+ # KAI C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ ecpc* )
+ # old Intel C++ for x86_64, which still supported -KPIC.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ icpc* )
+ # Intel C++, used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ cxx*)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+ # IBM XL 8.0, 9.0 on PPC and BlueGene
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd* | netbsdelf*-gnu)
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ cxx*)
+ # Digital/Compaq C++
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ lcc*)
+ # Lucid
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ vxworks*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+],
+[
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the '-m68020' flag to GCC prevents building anything better,
+ # like '-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ case $host_os in
+ os2*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+ ;;
+ esac
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+ if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
+ fi
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ case $cc_basename in
+ nagfor*)
+ # NAG Fortran compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ case $host_os in
+ os2*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+ ;;
+ esac
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC (with -KPIC) is the default.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ # old Intel for x86_64, which still supported -KPIC.
+ ecc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # flang / f18. f95 an alias for gfortran or flang on Debian
+ flang* | f18* | f95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+ ;;
+ nagfor*)
+ # NAG Fortran compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ tcc*)
+ # Fabrice Bellard et al's Tiny C Compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ ccc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All Alpha code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+ ;;
+ *Sun\ F* | *Sun*Fortran*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ ;;
+ *Intel*\ [[CF]]*Compiler*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ *Portland\ Group*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All OSF/1 code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ rdos*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ unicos*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+])
+case $host_os in
+ # For platforms that do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+ ;;
+esac
+
+AC_CACHE_CHECK([for $compiler option to produce PIC],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+ [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+ [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+ "" | " "*) ;;
+ *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+ esac],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+ [Additional compiler flags for building library objects])
+
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+ [How to pass a linker flag through the compiler])
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+ _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+ $lt_tmp_static_flag,
+ [],
+ [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+ [Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+ case $host_os in
+ aix[[4-9]]*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+ # Without the "-l" option, or with the "-B" option, AIX nm treats
+ # weak defined symbols like other global defined symbols, whereas
+ # GNU nm marks them as "W".
+ # While the 'weak' keyword is ignored in the Export File, we need
+ # it in the Import File for the 'aix-soname' feature, so we have
+ # to replace the "-B" option with "-P" for AIX nm.
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds
+ ;;
+ cygwin* | mingw* | cegcc*)
+ case $cc_basename in
+ cl*)
+ _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ ;;
+ *)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | gnu*)
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+], [
+ runpath_var=
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(archive_cmds, $1)=
+ _LT_TAGVAR(archive_expsym_cmds, $1)=
+ _LT_TAGVAR(compiler_needs_object, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(hardcode_automatic, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ _LT_TAGVAR(hardcode_minus_L, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_TAGVAR(inherit_rpath, $1)=no
+ _LT_TAGVAR(link_all_deplibs, $1)=unknown
+ _LT_TAGVAR(module_cmds, $1)=
+ _LT_TAGVAR(module_expsym_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+ _LT_TAGVAR(thread_safe_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ _LT_TAGVAR(include_expsyms, $1)=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ' (' and ')$', so one must not match beginning or
+ # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
+ # as well as any symbol that contains 'd'.
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test yes != "$GCC"; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd* | bitrig*)
+ with_gnu_ld=no
+ ;;
+ linux* | k*bsd*-gnu | gnu*)
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ ;;
+ esac
+
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test yes = "$with_gnu_ld"; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+ *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test yes = "$lt_use_gnu_ld_interface"; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='$wl'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[[3-9]]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test ia64 != "$host_cpu"; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file, use it as
+ # is; otherwise, prepend EXPORTS...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ haiku*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ shrext_cmds=.dll
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test linux-dietlibc = "$host_os"; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test no = "$tmp_diet"
+ then
+ tmp_addflag=' $pic_flag'
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ tmp_sharedflag='--shared' ;;
+ nagfor*) # NAGFOR 5.3
+ tmp_sharedflag='-Wl,-shared' ;;
+ xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+
+ if test yes = "$supports_anon_versioning"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ tcc*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic'
+ ;;
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+ if test yes = "$supports_anon_versioning"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+
+ if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then
+ runpath_var=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test ia64 = "$host_cpu"; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+ # Without the "-l" option, or with the "-B" option, AIX nm treats
+ # weak defined symbols like other global defined symbols, whereas
+ # GNU nm marks them as "W".
+ # While the 'weak' keyword is ignored in the Export File, we need
+ # it in the Import File for the 'aix-soname' feature, so we have
+ # to replace the "-B" option with "-P" for AIX nm.
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # have runtime linking enabled, and use it for executables.
+ # For shared libraries, we enable/disable runtime linking
+ # depending on the kind of the shared library created -
+ # when "with_aix_soname,aix_use_runtimelinking" is:
+ # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
+ # "aix,yes" lib.so shared, rtl:yes, for executables
+ # lib.a static archive
+ # "both,no" lib.so.V(shr.o) shared, rtl:yes
+ # lib.a(lib.so.V) shared, rtl:no, for executables
+ # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a(lib.so.V) shared, rtl:no
+ # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a static archive
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # With aix-soname=svr4, we create the lib.so.V shared archives only,
+ # so we don't have lib.a shared libs to link our executables.
+ # We have to force runtime linking in this case.
+ aix_use_runtimelinking=yes
+ LDFLAGS="$LDFLAGS -Wl,-brtl"
+ fi
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+ case $with_aix_soname,$aix_use_runtimelinking in
+ aix,*) ;; # traditional, no import file
+ svr4,* | *,yes) # use import file
+ # The Import File defines what to hardcode.
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ ;;
+ esac
+
+ if test yes = "$GCC"; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`$CC -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag="$shared_flag "'$wl-G'
+ fi
+ # Need to ensure runtime linking is disabled for the traditional
+ # shared library, or the linker may eventually find shared libraries
+ # /with/ Import File - we do not want to mix them.
+ shared_flag_aix='-shared'
+ shared_flag_svr4='-shared $wl-G'
+ else
+ # not using gcc
+ if test ia64 = "$host_cpu"; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag='$wl-G'
+ else
+ shared_flag='$wl-bM:SRE'
+ fi
+ shared_flag_aix='$wl-bM:SRE'
+ shared_flag_svr4='$wl-G'
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
+ else
+ if test ia64 = "$host_cpu"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
+ if test yes = "$with_gnu_ld"; then
+ # We only use this code for GNU lds that support --whole-archive.
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+ # -brtl affects multiple linker settings, -berok does not and is overridden later
+ compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+ if test svr4 != "$with_aix_soname"; then
+ # This is similar to how AIX traditionally builds its shared libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+ fi
+ if test aix != "$with_aix_soname"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+ else
+ # used by -dlpreopen to get the symbols
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
+ fi
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[[45]]*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ case $cc_basename in
+ cl*)
+ # Native MSVC
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=.dll
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp "$export_symbols" "$output_objdir/$soname.def";
+ echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+ else
+ $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+ # Don't use ranlib
+ _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+ _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile=$lt_outputfile.exe
+ lt_tool_outputfile=$lt_tool_outputfile.exe
+ ;;
+ esac~
+ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # Assume MSVC wrapper
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=.dll
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ # FIXME: Should let the user specify the lib program.
+ _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+ esac
+ ;;
+
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2.*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ hpux9*)
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ ;;
+
+ hpux10*)
+ if test yes,no = "$GCC,$with_gnu_ld"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test yes,no = "$GCC,$with_gnu_ld"; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ m4_if($1, [], [
+ # Older versions of the 11.00 compiler do not understand -b yet
+ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+ _LT_LINKER_OPTION([if $CC understands -b],
+ _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+ [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+ ;;
+ esac
+ fi
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ # This should be the same for all languages, so no per-tag cache variable.
+ AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
+ [lt_cv_irix_exported_symbol],
+ [save_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
+ AC_LINK_IFELSE(
+ [AC_LANG_SOURCE(
+ [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
+ [C++], [[int foo (void) { return 0; }]],
+ [Fortran 77], [[
+ subroutine foo
+ end]],
+ [Fortran], [[
+ subroutine foo
+ end]])])],
+ [lt_cv_irix_exported_symbol=yes],
+ [lt_cv_irix_exported_symbol=no])
+ LDFLAGS=$save_LDFLAGS])
+ if test yes = "$lt_cv_irix_exported_symbol"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ linux*)
+ case $cc_basename in
+ tcc*)
+ # Fabrice Bellard et al's Tiny C Compiler
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd* | bitrig*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ fi
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ shrext_cmds=.dll
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
+ osf3*)
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+ if test yes = "$GCC"; then
+ wlarc='$wl'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='$wl'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands '-z linker_flag'. GCC discards it without '$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ sunos4*)
+ if test sequent = "$host_vendor"; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ ;;
+ motorola)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4.3*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We CANNOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ if test sni = "$host_vendor"; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+ [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+ # Assume -lc should be added
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+ if test yes,yes = "$GCC,$enable_shared"; then
+ case $_LT_TAGVAR(archive_cmds, $1) in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+ [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+ [$RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+ pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+ then
+ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ else
+ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ fi
+ _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+ ])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+ [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+ [enable_shared_with_static_runtimes], [0],
+ [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+ [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+ [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+ [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+ [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+ [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+ [Commands used to build a loadable module if different from building
+ a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+ [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+ [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+ [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+ [Flag to hardcode $libdir into a binary during linking.
+ This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+ [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+ [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
+ DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+ [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
+ DIR into the resulting binary and the resulting library dependency is
+ "absolute", i.e impossible to change by setting $shlibpath_var if the
+ library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+ [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+ [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+ [Set to "yes" if building a shared library automatically hardcodes DIR
+ into the library and all subsequent libraries and executables linked
+ against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+ [Set to yes if linker adds runtime paths of dependent libraries
+ to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+ [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [always_export_symbols], [0],
+ [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+ [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+ [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+ [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+ [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [postlink_cmds], [2],
+ [Commands necessary for finishing linking programs])
+_LT_TAGDECL([], [file_list_spec], [1],
+ [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC=$CC
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+ LT_SYS_DLOPEN_SELF
+ _LT_CMD_STRIPLIB
+
+ # Report what library types will actually be built
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test no = "$can_build_shared" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test yes = "$enable_shared" && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test yes = "$enable_shared" || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC=$lt_save_CC
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+if test -n "$CXX" && ( test no != "$CXX" &&
+ ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) ||
+ (test g++ != "$CXX"))); then
+ AC_PROG_CXXCPP
+else
+ _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_caught_CXX_error"; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="int some_variable = 0;"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_CFLAGS=$CFLAGS
+ lt_save_LD=$LD
+ lt_save_GCC=$GCC
+ GCC=$GXX
+ lt_save_with_gnu_ld=$with_gnu_ld
+ lt_save_path_LD=$lt_cv_path_LD
+ if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+ else
+ $as_unset lt_cv_prog_gnu_ld
+ fi
+ if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+ else
+ $as_unset lt_cv_path_LD
+ fi
+ test -z "${LDCXX+set}" || LD=$LDCXX
+ CC=${CXX-"c++"}
+ CFLAGS=$CXXFLAGS
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ # We don't want -fno-exception when compiling C++ code, so set the
+ # no_builtin_flag separately
+ if test yes = "$GXX"; then
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+ else
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+ fi
+
+ if test yes = "$GXX"; then
+ # Set up default GNU C++ configuration
+
+ LT_PATH_LD
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test yes = "$with_gnu_ld"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='$wl'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+ $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"'
+
+ else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+ fi
+
+ # PORTME: fill in a description of your system's C++ link characteristics
+ AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aix[[4-9]]*)
+ if test ia64 = "$host_cpu"; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # have runtime linking enabled, and use it for executables.
+ # For shared libraries, we enable/disable runtime linking
+ # depending on the kind of the shared library created -
+ # when "with_aix_soname,aix_use_runtimelinking" is:
+ # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
+ # "aix,yes" lib.so shared, rtl:yes, for executables
+ # lib.a static archive
+ # "both,no" lib.so.V(shr.o) shared, rtl:yes
+ # lib.a(lib.so.V) shared, rtl:no, for executables
+ # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a(lib.so.V) shared, rtl:no
+ # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a static archive
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # With aix-soname=svr4, we create the lib.so.V shared archives only,
+ # so we don't have lib.a shared libs to link our executables.
+ # We have to force runtime linking in this case.
+ aix_use_runtimelinking=yes
+ LDFLAGS="$LDFLAGS -Wl,-brtl"
+ fi
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+ case $with_aix_soname,$aix_use_runtimelinking in
+ aix,*) ;; # no import file
+ svr4,* | *,yes) # use import file
+ # The Import File defines what to hardcode.
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ ;;
+ esac
+
+ if test yes = "$GXX"; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`$CC -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ esac
+ shared_flag='-shared'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag=$shared_flag' $wl-G'
+ fi
+ # Need to ensure runtime linking is disabled for the traditional
+ # shared library, or the linker may eventually find shared libraries
+ # /with/ Import File - we do not want to mix them.
+ shared_flag_aix='-shared'
+ shared_flag_svr4='-shared $wl-G'
+ else
+ # not using gcc
+ if test ia64 = "$host_cpu"; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag='$wl-G'
+ else
+ shared_flag='$wl-bM:SRE'
+ fi
+ shared_flag_aix='$wl-bM:SRE'
+ shared_flag_svr4='$wl-G'
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to
+ # export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ # The "-G" linker flag allows undefined symbols.
+ _LT_TAGVAR(no_undefined_flag, $1)='-bernotok'
+ # Determine the default libpath from the value encoded in an empty
+ # executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
+ else
+ if test ia64 = "$host_cpu"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
+ if test yes = "$with_gnu_ld"; then
+ # We only use this code for GNU lds that support --whole-archive.
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+ # -brtl affects multiple linker settings, -berok does not and is overridden later
+ compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+ if test svr4 != "$with_aix_soname"; then
+ # This is similar to how AIX traditionally builds its shared
+ # libraries. Need -bnortl late, we may have -brtl in LDFLAGS.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+ fi
+ if test aix != "$with_aix_soname"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+ else
+ # used by -dlpreopen to get the symbols
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
+ fi
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
+ fi
+ fi
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ case $GXX,$cc_basename in
+ ,cl* | no,cl*)
+ # Native MSVC
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=.dll
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp "$export_symbols" "$output_objdir/$soname.def";
+ echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+ else
+ $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ # Don't use ranlib
+ _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+ _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile=$lt_outputfile.exe
+ lt_tool_outputfile=$lt_tool_outputfile.exe
+ ;;
+ esac~
+ func_to_tool_file "$lt_outputfile"~
+ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # g++
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file, use it as
+ # is; otherwise, prepend EXPORTS...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ shrext_cmds=.dll
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ freebsd2.*)
+ # C++ shared libraries reported to be fairly broken before
+ # switch to ELF
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ freebsd-elf*)
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ ;;
+
+ freebsd* | dragonfly*)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ haiku*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ hpux9*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test yes = "$GXX"; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ hpux10*|hpux11*)
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ ;;
+ esac
+ fi
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test yes = "$GXX"; then
+ if test no = "$with_gnu_ld"; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC*)
+ # SGI C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test yes = "$GXX"; then
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib'
+ fi
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+ esac
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc* | ecpc* )
+ # Intel C++
+ with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ tmp_idyn=
+ case $host_cpu in
+ ia64*) tmp_idyn=' -i_dynamic';;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ case `$CC -V` in
+ *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+ _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ ;;
+ cxx*)
+ # Compaq C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+ ;;
+ xl* | mpixl* | bgxl*)
+ # IBM XL 8.0 on PPC, with GNU ld
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ if test yes = "$supports_anon_versioning"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+ # Not sure whether something based on
+ # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+ # would be better.
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ m88k*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+
+ *nto* | *qnx*)
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ openbsd* | bitrig*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+ fi
+ output_verbose_link_cmd=func_echo_all
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ case $host in
+ osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+ *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+ esac
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ cxx*)
+ case $host in
+ osf3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~
+ $RM $lib.exp'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test yes,no = "$GXX,$with_gnu_ld"; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ case $host in
+ osf3*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ psos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ lcc*)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands '-z linker_flag'.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test yes,no = "$GXX,$with_gnu_ld"; then
+ _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs'
+ if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"'
+ else
+ # g++ 2.7 appears to require '-G' NOT '-shared' on this
+ # platform.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"'
+ fi
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir'
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We CANNOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+ '"$_LT_TAGVAR(old_archive_cmds, $1)"
+ _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+ '"$_LT_TAGVAR(reload_cmds, $1)"
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+ test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
+
+ _LT_TAGVAR(GCC, $1)=$GXX
+ _LT_TAGVAR(LD, $1)=$LD
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+ LDCXX=$LD
+ LD=$lt_save_LD
+ GCC=$lt_save_GCC
+ with_gnu_ld=$lt_save_with_gnu_ld
+ lt_cv_path_LDCXX=$lt_cv_path_LD
+ lt_cv_path_LD=$lt_save_path_LD
+ lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+ lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test yes != "$_lt_caught_CXX_error"
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_FUNC_STRIPNAME_CNF
+# ----------------------
+# func_stripname_cnf prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+#
+# This function is identical to the (non-XSI) version of func_stripname,
+# except this one can be used by m4 code that may be executed by configure,
+# rather than the libtool script.
+m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
+AC_REQUIRE([_LT_DECL_SED])
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
+func_stripname_cnf ()
+{
+ case @S|@2 in
+ .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;;
+ *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;;
+ esac
+} # func_stripname_cnf
+])# _LT_FUNC_STRIPNAME_CNF
+
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library. It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer*4 a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+ private int a;
+ public void bar (void) {
+ a = 0;
+ }
+};
+_LT_EOF
+], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
+package foo
+func foo() {
+}
+_LT_EOF
+])
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ for p in `eval "$output_verbose_link_cmd"`; do
+ case $prev$p in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test x-L = "$p" ||
+ test x-R = "$p"; then
+ prev=$p
+ continue
+ fi
+
+ # Expand the sysroot to ease extracting the directories later.
+ if test -z "$prev"; then
+ case $p in
+ -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+ -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+ -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+ esac
+ fi
+ case $p in
+ =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+ esac
+ if test no = "$pre_test_object_deps_done"; then
+ case $prev in
+ -L | -R)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+ _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p
+ else
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+ _LT_TAGVAR(postdeps, $1)=$prev$p
+ else
+ _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p"
+ fi
+ fi
+ prev=
+ ;;
+
+ *.lto.$objext) ;; # Ignore GCC LTO objects
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test no = "$pre_test_object_deps_done"; then
+ if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+ _LT_TAGVAR(predep_objects, $1)=$p
+ else
+ _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+ fi
+ else
+ if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+ _LT_TAGVAR(postdep_objects, $1)=$p
+ else
+ _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+ # Interix 3.5 installs completely hosed .la files for C++, so rather than
+ # hack all around it, let's just trust "g++" to DTRT.
+ _LT_TAGVAR(predep_objects,$1)=
+ _LT_TAGVAR(postdep_objects,$1)=
+ _LT_TAGVAR(postdeps,$1)=
+ ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+ [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+ [Dependencies to place before and after the objects being linked to
+ create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+ [The library search path used internally by the compiler when linking
+ a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test no = "$F77"; then
+ _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_disable_F77"; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_GCC=$GCC
+ lt_save_CFLAGS=$CFLAGS
+ CC=${F77-"f77"}
+ CFLAGS=$FFLAGS
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+ GCC=$G77
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test no = "$can_build_shared" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test yes = "$enable_shared" && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test yes = "$enable_shared" || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)=$G77
+ _LT_TAGVAR(LD, $1)=$LD
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+fi # test yes != "$_lt_disable_F77"
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test no = "$FC"; then
+ _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_disable_FC"; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_GCC=$GCC
+ lt_save_CFLAGS=$CFLAGS
+ CC=${FC-"f95"}
+ CFLAGS=$FCFLAGS
+ compiler=$CC
+ GCC=$ac_cv_fc_compiler_gnu
+
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test no = "$can_build_shared" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test yes = "$enable_shared" && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test yes = "$enable_shared" || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu
+ _LT_TAGVAR(LD, $1)=$LD
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+fi # test yes != "$_lt_disable_FC"
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+CFLAGS=$GCJFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)=$LD
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_GO_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Go compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_GO_CONFIG],
+[AC_REQUIRE([LT_PROG_GO])dnl
+AC_LANG_SAVE
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GOC-"gccgo"}
+CFLAGS=$GOFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)=$LD
+_LT_CC_BASENAME([$compiler])
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GO_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code=$lt_simple_compile_test_code
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+CFLAGS=
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+ :
+ _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+ [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+ [AC_CHECK_TOOL(GCJ, gcj,)
+ test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2"
+ AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_GO
+# ----------
+AC_DEFUN([LT_PROG_GO],
+[AC_CHECK_TOOL(GOC, gccgo,)
+])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+# _LT_DECL_DLLTOOL
+# ----------------
+# Ensure DLLTOOL variable is set.
+m4_defun([_LT_DECL_DLLTOOL],
+[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
+AC_SUBST([DLLTOOL])
+])
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible. Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+ [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_SED. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+############################################################
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for lt_ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+ fi
+ done
+ done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+ test ! -f "$lt_ac_sed" && continue
+ cat /dev/null > conftest.in
+ lt_ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+ # Check for GNU sed and select it if it is found.
+ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+ lt_cv_path_SED=$lt_ac_sed
+ break
+ fi
+ while true; do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo >>conftest.nl
+ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+ cmp -s conftest.out conftest.nl || break
+ # 10000 chars as input seems more than enough
+ test 10 -lt "$lt_ac_count" && break
+ lt_ac_count=`expr $lt_ac_count + 1`
+ if test "$lt_ac_count" -gt "$lt_ac_max"; then
+ lt_ac_max=$lt_ac_count
+ lt_cv_path_SED=$lt_ac_sed
+ fi
+ done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PATH_CONVERSION_FUNCTIONS
+# -----------------------------
+# Determine what file name conversion functions should be used by
+# func_to_host_file (and, implicitly, by func_to_host_path). These are needed
+# for certain cross-compile configurations and native mingw.
+m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_MSG_CHECKING([how to convert $build file names to $host format])
+AC_CACHE_VAL(lt_cv_to_host_file_cmd,
+[case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+ ;;
+ esac
+ ;;
+ *-*-cygwin* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+ ;;
+ esac
+ ;;
+ * ) # unhandled hosts (and "normal" native builds)
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+esac
+])
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
+_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
+ [0], [convert $build file names to $host format])dnl
+
+AC_MSG_CHECKING([how to convert $build file names to toolchain format])
+AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
+[#assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ esac
+ ;;
+esac
+])
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
+_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
+ [0], [convert $build files to toolchain format])dnl
+])# _LT_PATH_CONVERSION_FUNCTIONS
diff --git a/pigeonhole/m4/ltoptions.m4 b/pigeonhole/m4/ltoptions.m4
new file mode 100644
index 0000000..94b0829
--- /dev/null
+++ b/pigeonhole/m4/ltoptions.m4
@@ -0,0 +1,437 @@
+# Helper functions for option handling. -*- Autoconf -*-
+#
+# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
+# Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 8 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it. Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+ _LT_MANGLE_DEFUN([$1], [$2]),
+ [m4_warning([Unknown $1 option '$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+ [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME. If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+ dnl
+ dnl Simply set some default values (i.e off) if boolean options were not
+ dnl specified:
+ _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+ ])
+ _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+ ])
+ dnl
+ dnl If no reference was made to various pairs of opposing options, then
+ dnl we run the default mode handler for the pair. For example, if neither
+ dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
+ dnl archives by default:
+ _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+ _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+ [_LT_ENABLE_FAST_INSTALL])
+ _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
+ [_LT_WITH_AIX_SONAME([aix])])
+ ])
+])# _LT_SET_OPTIONS
+
+
+## --------------------------------- ##
+## Macros to handle LT_INIT options. ##
+## --------------------------------- ##
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the 'dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+ AC_CHECK_TOOL(AS, as, false)
+ AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+ AC_CHECK_TOOL(OBJDUMP, objdump, false)
+ ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS], [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the 'win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the 'shared' and
+# 'disable-shared' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+ [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+ [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for pkg in $enableval; do
+ IFS=$lt_save_ifs
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac],
+ [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+ _LT_DECL([build_libtool_libs], [enable_shared], [0],
+ [Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the 'static' and
+# 'disable-static' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+ [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+ [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for pkg in $enableval; do
+ IFS=$lt_save_ifs
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac],
+ [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+ _LT_DECL([build_old_libs], [enable_static], [0],
+ [Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the 'fast-install'
+# and 'disable-fast-install' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+ [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+ [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for pkg in $enableval; do
+ IFS=$lt_save_ifs
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac],
+ [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+ [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the 'fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the 'disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_AIX_SONAME([DEFAULT])
+# ----------------------------------
+# implement the --with-aix-soname flag, and support the `aix-soname=aix'
+# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
+# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'.
+m4_define([_LT_WITH_AIX_SONAME],
+[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
+shared_archive_member_spec=
+case $host,$enable_shared in
+power*-*-aix[[5-9]]*,yes)
+ AC_MSG_CHECKING([which variant of shared library versioning to provide])
+ AC_ARG_WITH([aix-soname],
+ [AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
+ [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
+ [case $withval in
+ aix|svr4|both)
+ ;;
+ *)
+ AC_MSG_ERROR([Unknown argument to --with-aix-soname])
+ ;;
+ esac
+ lt_cv_with_aix_soname=$with_aix_soname],
+ [AC_CACHE_VAL([lt_cv_with_aix_soname],
+ [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
+ with_aix_soname=$lt_cv_with_aix_soname])
+ AC_MSG_RESULT([$with_aix_soname])
+ if test aix != "$with_aix_soname"; then
+ # For the AIX way of multilib, we name the shared archive member
+ # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
+ # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
+ # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
+ # the AIX toolchain works better with OBJECT_MODE set (default 32).
+ if test 64 = "${OBJECT_MODE-32}"; then
+ shared_archive_member_spec=shr_64
+ else
+ shared_archive_member_spec=shr
+ fi
+ fi
+ ;;
+*)
+ with_aix_soname=aix
+ ;;
+esac
+
+_LT_DECL([], [shared_archive_member_spec], [0],
+ [Shared archive member basename, for filename based shared library versioning on AIX])dnl
+])# _LT_WITH_AIX_SONAME
+
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
+# LT_INIT options.
+# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+ [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
+ [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+ [lt_p=${PACKAGE-default}
+ case $withval in
+ yes|no) pic_mode=$withval ;;
+ *)
+ pic_mode=default
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for lt_pkg in $withval; do
+ IFS=$lt_save_ifs
+ if test "X$lt_pkg" = "X$lt_p"; then
+ pic_mode=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac],
+ [pic_mode=m4_default([$1], [default])])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the 'pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+## ----------------- ##
+## LTDL_INIT Options ##
+## ----------------- ##
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+ [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+ [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+ [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+ [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+ [m4_define([_LTDL_TYPE], [convenience])])
diff --git a/pigeonhole/m4/ltsugar.m4 b/pigeonhole/m4/ltsugar.m4
new file mode 100644
index 0000000..48bc934
--- /dev/null
+++ b/pigeonhole/m4/ltsugar.m4
@@ -0,0 +1,124 @@
+# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
+#
+# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
+# Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+ [$#], [2], [[$2]],
+ [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+ [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59, which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+ [$#], 1, [],
+ [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+ m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+ [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+ [m4_foreach([_Lt_suffix],
+ ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+ [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+ [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+ [lt_append([$1], [$2], [$3])$4],
+ [$5])],
+ [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+ m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+ m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+ [$5],
+ [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+ [lt_join(m4_quote(m4_default([$4], [[, ]])),
+ lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+ [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
diff --git a/pigeonhole/m4/ltversion.m4 b/pigeonhole/m4/ltversion.m4
new file mode 100644
index 0000000..fa04b52
--- /dev/null
+++ b/pigeonhole/m4/ltversion.m4
@@ -0,0 +1,23 @@
+# ltversion.m4 -- version numbers -*- Autoconf -*-
+#
+# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# @configure_input@
+
+# serial 4179 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.4.6])
+m4_define([LT_PACKAGE_REVISION], [2.4.6])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.4.6'
+macro_revision='2.4.6'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
diff --git a/pigeonhole/m4/lt~obsolete.m4 b/pigeonhole/m4/lt~obsolete.m4
new file mode 100644
index 0000000..c6b26f8
--- /dev/null
+++ b/pigeonhole/m4/lt~obsolete.m4
@@ -0,0 +1,99 @@
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
+#
+# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
+# Foundation, Inc.
+# Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 5 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else. This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
diff --git a/pigeonhole/missing b/pigeonhole/missing
new file mode 100755
index 0000000..8d0eaad
--- /dev/null
+++ b/pigeonhole/missing
@@ -0,0 +1,215 @@
+#! /bin/sh
+# Common wrapper for a few potentially missing GNU programs.
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+fi
+
+case $1 in
+
+ --is-lightweight)
+ # Used by our autoconf macros to check whether the available missing
+ # script is modern enough.
+ exit 0
+ ;;
+
+ --run)
+ # Back-compat with the calling convention used by older automake.
+ shift
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
+to PROGRAM being missing or too old.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+
+Supported PROGRAM values:
+ aclocal autoconf autoheader autom4te automake makeinfo
+ bison yacc flex lex help2man
+
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: unknown '$1' option"
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# Run the given program, remember its exit status.
+"$@"; st=$?
+
+# If it succeeded, we are done.
+test $st -eq 0 && exit 0
+
+# Also exit now if we it failed (or wasn't found), and '--version' was
+# passed; such an option is passed most likely to detect whether the
+# program is present and works.
+case $2 in --version|--help) exit $st;; esac
+
+# Exit code 63 means version mismatch. This often happens when the user
+# tries to use an ancient version of a tool on a file that requires a
+# minimum version.
+if test $st -eq 63; then
+ msg="probably too old"
+elif test $st -eq 127; then
+ # Program was missing.
+ msg="missing on your system"
+else
+ # Program was found and executed, but failed. Give up.
+ exit $st
+fi
+
+perl_URL=https://www.perl.org/
+flex_URL=https://github.com/westes/flex
+gnu_software_URL=https://www.gnu.org/software
+
+program_details ()
+{
+ case $1 in
+ aclocal|automake)
+ echo "The '$1' program is part of the GNU Automake package:"
+ echo "<$gnu_software_URL/automake>"
+ echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/autoconf>"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ autoconf|autom4te|autoheader)
+ echo "The '$1' program is part of the GNU Autoconf package:"
+ echo "<$gnu_software_URL/autoconf/>"
+ echo "It also requires GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ esac
+}
+
+give_advice ()
+{
+ # Normalize program name to check for.
+ normalized_program=`echo "$1" | sed '
+ s/^gnu-//; t
+ s/^gnu//; t
+ s/^g//; t'`
+
+ printf '%s\n' "'$1' is $msg."
+
+ configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
+ case $normalized_program in
+ autoconf*)
+ echo "You should only need it if you modified 'configure.ac',"
+ echo "or m4 files included by it."
+ program_details 'autoconf'
+ ;;
+ autoheader*)
+ echo "You should only need it if you modified 'acconfig.h' or"
+ echo "$configure_deps."
+ program_details 'autoheader'
+ ;;
+ automake*)
+ echo "You should only need it if you modified 'Makefile.am' or"
+ echo "$configure_deps."
+ program_details 'automake'
+ ;;
+ aclocal*)
+ echo "You should only need it if you modified 'acinclude.m4' or"
+ echo "$configure_deps."
+ program_details 'aclocal'
+ ;;
+ autom4te*)
+ echo "You might have modified some maintainer files that require"
+ echo "the 'autom4te' program to be rebuilt."
+ program_details 'autom4te'
+ ;;
+ bison*|yacc*)
+ echo "You should only need it if you modified a '.y' file."
+ echo "You may want to install the GNU Bison package:"
+ echo "<$gnu_software_URL/bison/>"
+ ;;
+ lex*|flex*)
+ echo "You should only need it if you modified a '.l' file."
+ echo "You may want to install the Fast Lexical Analyzer package:"
+ echo "<$flex_URL>"
+ ;;
+ help2man*)
+ echo "You should only need it if you modified a dependency" \
+ "of a man page."
+ echo "You may want to install the GNU Help2man package:"
+ echo "<$gnu_software_URL/help2man/>"
+ ;;
+ makeinfo*)
+ echo "You should only need it if you modified a '.texi' file, or"
+ echo "any other file indirectly affecting the aspect of the manual."
+ echo "You might want to install the Texinfo package:"
+ echo "<$gnu_software_URL/texinfo/>"
+ echo "The spurious makeinfo call might also be the consequence of"
+ echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
+ echo "want to install GNU make:"
+ echo "<$gnu_software_URL/make/>"
+ ;;
+ *)
+ echo "You might have modified some files without having the proper"
+ echo "tools for further handling them. Check the 'README' file, it"
+ echo "often tells you about the needed prerequisites for installing"
+ echo "this package. You may also peek at any GNU archive site, in"
+ echo "case some other package contains this missing '$1' program."
+ ;;
+ esac
+}
+
+give_advice "$1" | sed -e '1s/^/WARNING: /' \
+ -e '2,$s/^/ /' >&2
+
+# Propagate the correct exit status (expected to be 127 for a program
+# not found, 63 for a program that failed due to version mismatch).
+exit $st
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/pigeonhole/pigeonhole-config.h.in b/pigeonhole/pigeonhole-config.h.in
new file mode 100644
index 0000000..60b0ff9
--- /dev/null
+++ b/pigeonhole/pigeonhole-config.h.in
@@ -0,0 +1,15 @@
+
+/* Define to the full name of Pigeonhole for Dovecot. */
+#undef PIGEONHOLE_NAME
+
+/* Define to the version of Pigeonhole for Dovecot. */
+#undef PIGEONHOLE_VERSION
+
+/* Pigeonhole ABI version */
+#undef PIGEONHOLE_ABI_VERSION
+
+/* Define to build unfinished features/extensions. */
+#undef HAVE_SIEVE_UNFINISHED
+
+/* LDAP support is built in */
+#undef SIEVE_BUILTIN_LDAP
diff --git a/pigeonhole/pigeonhole-version.h b/pigeonhole/pigeonhole-version.h
new file mode 100644
index 0000000..8ef02ff
--- /dev/null
+++ b/pigeonhole/pigeonhole-version.h
@@ -0,0 +1,6 @@
+#ifndef PIGEONHOLE_VERSION_H
+#define PIGEONHOLE_VERSION_H
+
+#define PIGEONHOLE_VERSION_FULL PIGEONHOLE_VERSION" (f6cd4b8e)"
+
+#endif /* PIGEONHOLE_VERSION_H */
diff --git a/pigeonhole/src/Makefile.am b/pigeonhole/src/Makefile.am
new file mode 100644
index 0000000..85c1e44
--- /dev/null
+++ b/pigeonhole/src/Makefile.am
@@ -0,0 +1,21 @@
+
+
+sieve_subdirs = \
+ lib-sieve \
+ plugins \
+ lib-sieve-tool \
+ sieve-tools \
+ testsuite
+
+if BUILD_MANAGESIEVE
+managesieve_subdirs = \
+ lib-managesieve \
+ managesieve \
+ managesieve-login
+else
+managesieve_subdirs =
+endif
+
+SUBDIRS = \
+ $(sieve_subdirs) \
+ $(managesieve_subdirs)
diff --git a/pigeonhole/src/Makefile.in b/pigeonhole/src/Makefile.in
new file mode 100644
index 0000000..4b09bcb
--- /dev/null
+++ b/pigeonhole/src/Makefile.in
@@ -0,0 +1,709 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = lib-sieve plugins lib-sieve-tool sieve-tools testsuite \
+ lib-managesieve managesieve managesieve-login
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+sieve_subdirs = \
+ lib-sieve \
+ plugins \
+ lib-sieve-tool \
+ sieve-tools \
+ testsuite
+
+@BUILD_MANAGESIEVE_FALSE@managesieve_subdirs =
+@BUILD_MANAGESIEVE_TRUE@managesieve_subdirs = \
+@BUILD_MANAGESIEVE_TRUE@ lib-managesieve \
+@BUILD_MANAGESIEVE_TRUE@ managesieve \
+@BUILD_MANAGESIEVE_TRUE@ managesieve-login
+
+SUBDIRS = \
+ $(sieve_subdirs) \
+ $(managesieve_subdirs)
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-managesieve/Makefile.am b/pigeonhole/src/lib-managesieve/Makefile.am
new file mode 100644
index 0000000..b036680
--- /dev/null
+++ b/pigeonhole/src/lib-managesieve/Makefile.am
@@ -0,0 +1,15 @@
+noinst_LTLIBRARIES = libmanagesieve.la
+
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ -I$(top_srcdir)
+
+libmanagesieve_la_SOURCES = \
+ managesieve-arg.c \
+ managesieve-quote.c \
+ managesieve-parser.c
+
+noinst_HEADERS = \
+ managesieve-arg.h \
+ managesieve-quote.h \
+ managesieve-parser.h
diff --git a/pigeonhole/src/lib-managesieve/Makefile.in b/pigeonhole/src/lib-managesieve/Makefile.in
new file mode 100644
index 0000000..c52cc11
--- /dev/null
+++ b/pigeonhole/src/lib-managesieve/Makefile.in
@@ -0,0 +1,691 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-managesieve
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libmanagesieve_la_LIBADD =
+am_libmanagesieve_la_OBJECTS = managesieve-arg.lo managesieve-quote.lo \
+ managesieve-parser.lo
+libmanagesieve_la_OBJECTS = $(am_libmanagesieve_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/managesieve-arg.Plo \
+ ./$(DEPDIR)/managesieve-parser.Plo \
+ ./$(DEPDIR)/managesieve-quote.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libmanagesieve_la_SOURCES)
+DIST_SOURCES = $(libmanagesieve_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libmanagesieve.la
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ -I$(top_srcdir)
+
+libmanagesieve_la_SOURCES = \
+ managesieve-arg.c \
+ managesieve-quote.c \
+ managesieve-parser.c
+
+noinst_HEADERS = \
+ managesieve-arg.h \
+ managesieve-quote.h \
+ managesieve-parser.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-managesieve/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-managesieve/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libmanagesieve.la: $(libmanagesieve_la_OBJECTS) $(libmanagesieve_la_DEPENDENCIES) $(EXTRA_libmanagesieve_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libmanagesieve_la_OBJECTS) $(libmanagesieve_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-arg.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-parser.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-quote.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/managesieve-arg.Plo
+ -rm -f ./$(DEPDIR)/managesieve-parser.Plo
+ -rm -f ./$(DEPDIR)/managesieve-quote.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/managesieve-arg.Plo
+ -rm -f ./$(DEPDIR)/managesieve-parser.Plo
+ -rm -f ./$(DEPDIR)/managesieve-quote.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-managesieve/managesieve-arg.c b/pigeonhole/src/lib-managesieve/managesieve-arg.c
new file mode 100644
index 0000000..178bf45
--- /dev/null
+++ b/pigeonhole/src/lib-managesieve/managesieve-arg.c
@@ -0,0 +1,207 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "strescape.h"
+#include "managesieve-arg.h"
+
+bool managesieve_arg_get_atom(const struct managesieve_arg *arg,
+ const char **str_r)
+{
+ if (arg->type != MANAGESIEVE_ARG_ATOM)
+ return FALSE;
+
+ *str_r = arg->_data.str;
+ return TRUE;
+}
+
+bool managesieve_arg_get_number(const struct managesieve_arg *arg,
+ uoff_t *number_r)
+{
+ const char *data;
+ uoff_t num = 0;
+ size_t i;
+
+ if (arg->type != MANAGESIEVE_ARG_ATOM)
+ return FALSE;
+
+ data = arg->_data.str;
+ for (i = 0; i < arg->str_len; i++) {
+ uoff_t newnum;
+
+ if (data[i] < '0' || data[i] > '9')
+ return FALSE;
+
+ newnum = num*10 + (data[i] -'0');
+ if (newnum < num)
+ return FALSE;
+
+ num = newnum;
+ }
+
+ *number_r = num;
+ return TRUE;
+}
+
+bool managesieve_arg_get_quoted(const struct managesieve_arg *arg,
+ const char **str_r)
+{
+ if (arg->type != MANAGESIEVE_ARG_STRING)
+ return FALSE;
+
+ *str_r = arg->_data.str;
+ return TRUE;
+}
+
+bool managesieve_arg_get_string(const struct managesieve_arg *arg,
+ const char **str_r)
+{
+ if (arg->type != MANAGESIEVE_ARG_STRING &&
+ arg->type != MANAGESIEVE_ARG_LITERAL)
+ return FALSE;
+
+ *str_r = arg->_data.str;
+ return TRUE;
+}
+
+bool managesieve_arg_get_string_stream(const struct managesieve_arg *arg,
+ struct istream **stream_r)
+{
+ if (arg->type != MANAGESIEVE_ARG_STRING_STREAM)
+ return FALSE;
+
+ *stream_r = arg->_data.str_stream;
+ return TRUE;
+}
+
+bool managesieve_arg_get_list(const struct managesieve_arg *arg,
+ const struct managesieve_arg **list_r)
+{
+ unsigned int count;
+
+ return managesieve_arg_get_list_full(arg, list_r, &count);
+}
+
+bool managesieve_arg_get_list_full(const struct managesieve_arg *arg,
+ const struct managesieve_arg **list_r,
+ unsigned int *list_count_r)
+{
+ unsigned int count;
+
+ if (arg->type != MANAGESIEVE_ARG_LIST)
+ return FALSE;
+
+ *list_r = array_get(&arg->_data.list, &count);
+
+ /* drop MANAGESIEVE_ARG_EOL from list size */
+ i_assert(count > 0);
+ *list_count_r = count - 1;
+ return TRUE;
+}
+
+const char *managesieve_arg_as_atom(const struct managesieve_arg *arg)
+{
+ const char *str;
+
+ if (!managesieve_arg_get_atom(arg, &str))
+ i_unreached();
+ return str;
+}
+
+const char *managesieve_arg_as_string(const struct managesieve_arg *arg)
+{
+ const char *str;
+
+ if (!managesieve_arg_get_string(arg, &str))
+ i_unreached();
+ return str;
+}
+
+struct istream *
+managesieve_arg_as_string_stream(const struct managesieve_arg *arg)
+{
+ struct istream *stream;
+
+ if (!managesieve_arg_get_string_stream(arg, &stream))
+ i_unreached();
+ return stream;
+}
+
+const struct managesieve_arg *
+managesieve_arg_as_list(const struct managesieve_arg *arg)
+{
+ const struct managesieve_arg *ret;
+
+ if (!managesieve_arg_get_list(arg, &ret))
+ i_unreached();
+ return ret;
+}
+
+bool managesieve_arg_atom_equals(const struct managesieve_arg *arg,
+ const char *str)
+{
+ const char *value;
+
+ if (!managesieve_arg_get_atom(arg, &value))
+ return FALSE;
+ return strcasecmp(value, str) == 0;
+}
+
+void managesieve_write_arg(string_t *dest, const struct managesieve_arg *arg)
+{
+ const char *strval;
+
+ switch (arg->type) {
+ case MANAGESIEVE_ARG_ATOM:
+ str_append(dest, managesieve_arg_as_atom(arg));
+ break;
+ case MANAGESIEVE_ARG_STRING:
+ strval = managesieve_arg_as_string(arg);
+ str_append_c(dest, '"');
+ str_append_escaped(dest, strval, strlen(strval));
+ str_append_c(dest, '"');
+ break;
+ case MANAGESIEVE_ARG_STRING_STREAM:
+ str_append(dest, "\"<too large>\"");
+ break;
+ case MANAGESIEVE_ARG_LITERAL: {
+ const char *strarg = managesieve_arg_as_string(arg);
+ str_printfa(dest, "{%zu}\r\n",
+ strlen(strarg));
+ str_append(dest, strarg);
+ break;
+ }
+ case MANAGESIEVE_ARG_LIST:
+ str_append_c(dest, '(');
+ managesieve_write_args(dest, managesieve_arg_as_list(arg));
+ str_append_c(dest, ')');
+ break;
+ case MANAGESIEVE_ARG_NONE:
+ case MANAGESIEVE_ARG_EOL:
+ i_unreached();
+ }
+}
+
+void managesieve_write_args(string_t *dest, const struct managesieve_arg *args)
+{
+ bool first = TRUE;
+
+ for (; !MANAGESIEVE_ARG_IS_EOL(args); args++) {
+ if (first)
+ first = FALSE;
+ else
+ str_append_c(dest, ' ');
+ managesieve_write_arg(dest, args);
+ }
+}
+
+const char *managesieve_args_to_str(const struct managesieve_arg *args)
+{
+ string_t *str;
+
+ str = t_str_new(128);
+ managesieve_write_args(str, args);
+ return str_c(str);
+}
+
diff --git a/pigeonhole/src/lib-managesieve/managesieve-arg.h b/pigeonhole/src/lib-managesieve/managesieve-arg.h
new file mode 100644
index 0000000..23f7c05
--- /dev/null
+++ b/pigeonhole/src/lib-managesieve/managesieve-arg.h
@@ -0,0 +1,117 @@
+#ifndef MANAGESIEVE_ARG_H
+#define MANAGESIEVE_ARG_H
+
+#include "array.h"
+
+/*
+ * QUOTED-SPECIALS = <"> / "\"
+ */
+#define IS_QUOTED_SPECIAL(c) \
+ ((c) == '"' || (c) == '\\')
+
+/*
+ * ATOM-SPECIALS = "(" / ")" / "{" / SP / CTL / QUOTED-SPECIALS
+ */
+#define IS_ATOM_SPECIAL(c) \
+ ((c) == '(' || (c) == ')' || (c) == '{' || \
+ (c) <= 32 || (c) == 0x7f || \
+ IS_QUOTED_SPECIAL(c))
+
+/*
+ * CHAR = %x01-7F
+ */
+#define IS_CHAR(c) \
+ (((c) & 0x80) == 0)
+
+/*
+ * TEXT-CHAR = %x01-09 / %x0B-0C / %x0E-7F
+ * ;; any CHAR except CR and LF
+ */
+#define IS_TEXT_CHAR(c) \
+ (IS_CHAR(c) && (c) != '\r' && (c) != '\n')
+
+/*
+ * SAFE-CHAR = %x01-09 / %x0B-0C / %x0E-21 /
+ * %x23-5B / %x5D-7F
+ * ;; any TEXT-CHAR except QUOTED-SPECIALS
+ */
+#define IS_SAFE_CHAR(c) \
+ (IS_TEXT_CHAR(c) && !IS_QUOTED_SPECIAL(c))
+
+enum managesieve_arg_type {
+ MANAGESIEVE_ARG_NONE = 0,
+ MANAGESIEVE_ARG_ATOM,
+ MANAGESIEVE_ARG_STRING,
+ MANAGESIEVE_ARG_STRING_STREAM,
+
+ MANAGESIEVE_ARG_LIST,
+
+ /* literals are returned as MANAGESIEVE_ARG_STRING by default */
+ MANAGESIEVE_ARG_LITERAL,
+
+ MANAGESIEVE_ARG_EOL /* end of argument list */
+};
+
+ARRAY_DEFINE_TYPE(managesieve_arg_list, struct managesieve_arg);
+struct managesieve_arg {
+ enum managesieve_arg_type type;
+ /* parent argument; always of type MANAGESIEVE_ARG_LIST */
+ struct managesieve_arg *parent;
+
+ /* Set when _data.str is set */
+ size_t str_len;
+
+ union {
+ const char *str;
+ struct istream *str_stream;
+ ARRAY_TYPE(managesieve_arg_list) list;
+ } _data;
+};
+
+#define MANAGESIEVE_ARG_IS_EOL(arg) \
+ ((arg)->type == MANAGESIEVE_ARG_EOL)
+
+bool managesieve_arg_get_atom(const struct managesieve_arg *arg,
+ const char **str_r) ATTR_WARN_UNUSED_RESULT;
+bool managesieve_arg_get_number(const struct managesieve_arg *arg,
+ uoff_t *number_r) ATTR_WARN_UNUSED_RESULT;
+bool managesieve_arg_get_quoted(const struct managesieve_arg *arg,
+ const char **str_r) ATTR_WARN_UNUSED_RESULT;
+bool managesieve_arg_get_string(const struct managesieve_arg *arg,
+ const char **str_r) ATTR_WARN_UNUSED_RESULT;
+
+bool managesieve_arg_get_string_stream(const struct managesieve_arg *arg,
+ struct istream **stream_r)
+ ATTR_WARN_UNUSED_RESULT;
+
+bool managesieve_arg_get_list(const struct managesieve_arg *arg,
+ const struct managesieve_arg **list_r)
+ ATTR_WARN_UNUSED_RESULT;
+bool managesieve_arg_get_list_full(const struct managesieve_arg *arg,
+ const struct managesieve_arg **list_r,
+ unsigned int *list_count_r)
+ ATTR_WARN_UNUSED_RESULT;
+
+/* Similar to above, but assumes that arg is already of correct type. */
+const char *managesieve_arg_as_atom(const struct managesieve_arg *arg);
+const char *managesieve_arg_as_string(const struct managesieve_arg *arg);
+struct istream *
+managesieve_arg_as_string_stream(const struct managesieve_arg *arg);
+const struct managesieve_arg *
+managesieve_arg_as_list(const struct managesieve_arg *arg);
+
+/* Returns TRUE if arg is atom and case-insensitively matches str */
+bool managesieve_arg_atom_equals(const struct managesieve_arg *arg,
+ const char *str);
+
+/* Write ManageSieve arg to the given string. Because
+ MANAGESIVE_ARG_LITERAL_SIZE* have no content, they're written as
+ "{size}\r\n<too large>". */
+void managesieve_write_arg(string_t *dest, const struct managesieve_arg *arg);
+/* Same as managesieve_write_arg(), but write all the args until EOL. */
+void managesieve_write_args(string_t *dest, const struct managesieve_arg *args);
+/* Like managesieve_write_args(), but return the string allocated from data
+ stack. */
+const char *managesieve_args_to_str(const struct managesieve_arg *args);
+
+#endif
diff --git a/pigeonhole/src/lib-managesieve/managesieve-parser.c b/pigeonhole/src/lib-managesieve/managesieve-parser.c
new file mode 100644
index 0000000..546e431
--- /dev/null
+++ b/pigeonhole/src/lib-managesieve/managesieve-parser.c
@@ -0,0 +1,757 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "unichar.h"
+#include "istream-private.h"
+#include "ostream.h"
+#include "strescape.h"
+#include "managesieve-parser.h"
+
+#define is_linebreak(c) \
+ ((c) == '\r' || (c) == '\n')
+
+#define LIST_INIT_COUNT 7
+
+enum arg_parse_type {
+ ARG_PARSE_NONE = 0,
+ ARG_PARSE_ATOM,
+ ARG_PARSE_STRING,
+ ARG_PARSE_LITERAL,
+ ARG_PARSE_LITERAL_DATA
+};
+
+struct managesieve_parser {
+ /* permanent */
+ pool_t pool;
+ struct istream *input;
+ size_t max_line_size;
+ enum managesieve_parser_flags flags;
+
+ /* reset by managesieve_parser_reset(): */
+ size_t line_size;
+ ARRAY_TYPE(managesieve_arg_list) root_list;
+ ARRAY_TYPE(managesieve_arg_list) *cur_list;
+ struct managesieve_arg *list_arg;
+
+ enum arg_parse_type cur_type;
+ size_t cur_pos; /* parser position in input buffer */
+
+ int str_first_escape; /* ARG_PARSE_STRING: index to first '\' */
+ uoff_t literal_size; /* ARG_PARSE_LITERAL: string size */
+
+ struct istream *str_stream;
+
+ const char *error;
+
+ bool literal_skip_crlf:1;
+ bool literal_nonsync:1;
+ bool eol:1;
+ bool fatal_error:1;
+};
+
+static struct istream *quoted_string_istream_create
+ (struct managesieve_parser *parser);
+
+struct managesieve_parser *
+managesieve_parser_create(struct istream *input, size_t max_line_size)
+{
+ struct managesieve_parser *parser;
+
+ parser = i_new(struct managesieve_parser, 1);
+ parser->pool = pool_alloconly_create("MANAGESIEVE parser", 8192);
+ parser->input = input;
+ parser->max_line_size = max_line_size;
+
+ p_array_init(&parser->root_list, parser->pool, LIST_INIT_COUNT);
+ parser->cur_list = &parser->root_list;
+ return parser;
+}
+
+void managesieve_parser_destroy(struct managesieve_parser **parser)
+{
+ i_stream_unref(&(*parser)->str_stream);
+
+ pool_unref(&(*parser)->pool);
+ i_free(*parser);
+ *parser = NULL;
+}
+
+void managesieve_parser_reset(struct managesieve_parser *parser)
+{
+ p_clear(parser->pool);
+
+ parser->line_size = 0;
+
+ p_array_init(&parser->root_list, parser->pool, LIST_INIT_COUNT);
+ parser->cur_list = &parser->root_list;
+ parser->list_arg = NULL;
+
+ parser->cur_type = ARG_PARSE_NONE;
+ parser->cur_pos = 0;
+
+ parser->str_first_escape = 0;
+ parser->literal_size = 0;
+
+ parser->error = NULL;
+
+ parser->literal_skip_crlf = FALSE;
+ parser->eol = FALSE;
+
+ i_stream_unref(&parser->str_stream);
+}
+
+const char *
+managesieve_parser_get_error(struct managesieve_parser *parser, bool *fatal)
+{
+ *fatal = parser->fatal_error;
+ return parser->error;
+}
+
+/* Skip over everything parsed so far, plus the following whitespace */
+static bool
+managesieve_parser_skip_to_next(struct managesieve_parser *parser,
+ const unsigned char **data, size_t *data_size)
+{
+ size_t i;
+
+ for (i = parser->cur_pos; i < *data_size; i++) {
+ if ((*data)[i] != ' ')
+ break;
+ }
+
+ parser->line_size += i;
+ i_stream_skip(parser->input, i);
+ parser->cur_pos = 0;
+
+ *data += i;
+ *data_size -= i;
+ return *data_size > 0;
+}
+
+static struct managesieve_arg *
+managesieve_arg_create(struct managesieve_parser *parser)
+{
+ struct managesieve_arg *arg;
+
+ arg = array_append_space(parser->cur_list);
+ arg->parent = parser->list_arg;
+
+ return arg;
+}
+
+static void
+managesieve_parser_save_arg(struct managesieve_parser *parser,
+ const unsigned char *data, size_t size)
+{
+ struct managesieve_arg *arg;
+ char *str;
+
+ arg = managesieve_arg_create(parser);
+
+ switch (parser->cur_type) {
+ case ARG_PARSE_ATOM:
+ /* Simply save the string */
+ arg->type = MANAGESIEVE_ARG_ATOM;
+ arg->_data.str = p_strndup(parser->pool, data, size);
+ arg->str_len = size;
+ break;
+ case ARG_PARSE_STRING:
+ /* Data is quoted and may contain escapes. */
+ if ((parser->flags &
+ MANAGESIEVE_PARSE_FLAG_STRING_STREAM) != 0) {
+ arg->type = MANAGESIEVE_ARG_STRING_STREAM;
+ arg->_data.str_stream = parser->str_stream;
+ } else {
+ i_assert(size > 0);
+
+ arg->type = MANAGESIEVE_ARG_STRING;
+ str = p_strndup(parser->pool, data+1, size-1);
+
+ /* remove the escapes */
+ if (parser->str_first_escape >= 0 &&
+ (parser->flags &
+ MANAGESIEVE_PARSE_FLAG_NO_UNESCAPE) == 0)
+ (void)str_unescape(str);
+
+ arg->_data.str = str;
+ arg->str_len = strlen(str);
+ }
+ break;
+ case ARG_PARSE_LITERAL_DATA:
+ if ((parser->flags &
+ MANAGESIEVE_PARSE_FLAG_STRING_STREAM) != 0) {
+ arg->type = MANAGESIEVE_ARG_STRING_STREAM;
+ arg->_data.str_stream = parser->str_stream;
+ } else if ((parser->flags &
+ MANAGESIEVE_PARSE_FLAG_LITERAL_TYPE) != 0) {
+ arg->type = MANAGESIEVE_ARG_LITERAL;
+ arg->_data.str = p_strndup(parser->pool, data, size);
+ arg->str_len = size;
+ } else {
+ arg->type = MANAGESIEVE_ARG_STRING;
+ arg->_data.str = p_strndup(parser->pool, data, size);
+ arg->str_len = size;
+ }
+ break;
+ default:
+ i_unreached();
+ }
+
+ parser->cur_type = ARG_PARSE_NONE;
+}
+
+static bool is_valid_atom_char(struct managesieve_parser *parser, char chr)
+{
+ if (IS_ATOM_SPECIAL((unsigned char)chr)) {
+ parser->error = "Invalid characters in atom";
+ return FALSE;
+ } else if ((((unsigned char)chr) & 0x80) != 0) {
+ parser->error = "8bit data in atom";
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool
+managesieve_parser_read_atom(struct managesieve_parser *parser,
+ const unsigned char *data, size_t data_size)
+{
+ size_t i;
+
+ /* Read until we've found space, CR or LF. */
+ for (i = parser->cur_pos; i < data_size; i++) {
+ if (data[i] == ' ' || data[i] == ')' ||
+ is_linebreak(data[i])) {
+ managesieve_parser_save_arg(parser, data, i);
+ break;
+ } else if (!is_valid_atom_char(parser, data[i]))
+ return FALSE;
+ }
+
+ parser->cur_pos = i;
+ return (parser->cur_type == ARG_PARSE_NONE);
+}
+
+static bool
+managesieve_parser_read_string(struct managesieve_parser *parser,
+ const unsigned char *data, size_t data_size)
+{
+ size_t i;
+
+ /* QUOTED-CHAR = SAFE-UTF8-CHAR / "\" QUOTED-SPECIALS
+ quoted = <"> *QUOTED-CHAR <">
+ ;; limited to 1024 octets between the <">s
+ */
+
+ /* Read until we've found non-escaped ", CR or LF */
+ for (i = parser->cur_pos; i < data_size; i++) {
+ if (data[i] == '"') {
+ if (!uni_utf8_data_is_valid(data+1, i-1)) {
+ parser->error =
+ "Invalid UTF-8 character in quoted-string.";
+ return FALSE;
+ }
+
+ managesieve_parser_save_arg(parser, data, i);
+ i++; /* skip the trailing '"' too */
+ break;
+ }
+
+ if (data[i] == '\0') {
+ parser->error = "NULs not allowed in strings";
+ return FALSE;
+ }
+
+ if (data[i] == '\\') {
+ if (i+1 == data_size) {
+ /* Known data ends with '\' - leave it to next
+ time as well if it happens to be \" */
+ break;
+ }
+
+ /* Save the first escaped char */
+ if (parser->str_first_escape < 0)
+ parser->str_first_escape = i;
+
+ /* Skip the escaped char */
+ i++;
+
+ if (!IS_QUOTED_SPECIAL(data[i])) {
+ parser->error =
+ "Escaped quoted-string character is not a QUOTED-SPECIAL.";
+ return FALSE;
+ }
+ continue;
+ }
+
+ if ((data[i] & 0x80) == 0 && !IS_SAFE_CHAR(data[i])) {
+ parser->error = "String contains invalid character.";
+ return FALSE;
+ }
+ }
+
+ parser->cur_pos = i;
+ return (parser->cur_type == ARG_PARSE_NONE);
+}
+
+static bool managesieve_parser_literal_end(struct managesieve_parser *parser)
+{
+ if ((parser->flags & MANAGESIEVE_PARSE_FLAG_STRING_STREAM) == 0) {
+ if (parser->line_size >= parser->max_line_size ||
+ (parser->literal_size >
+ (parser->max_line_size - parser->line_size))) {
+ /* Too long string, abort. */
+ parser->error = "Literal size too large";
+ parser->fatal_error = TRUE;
+ return FALSE;
+ }
+ }
+
+ parser->cur_type = ARG_PARSE_LITERAL_DATA;
+ parser->literal_skip_crlf = TRUE;
+
+ parser->cur_pos = 0;
+ return TRUE;
+}
+
+static bool
+managesieve_parser_read_literal(struct managesieve_parser *parser,
+ const unsigned char *data, size_t data_size)
+{
+ size_t i;
+
+ /* Expecting digits + "}" */
+ for (i = parser->cur_pos; i < data_size; i++) {
+ if (data[i] == '}') {
+ parser->line_size += i+1;
+ i_stream_skip(parser->input, i+1);
+
+ return managesieve_parser_literal_end(parser);
+ }
+
+ if (parser->literal_nonsync) {
+ parser->error = "Expecting '}' after '+'";
+ return FALSE;
+ }
+
+ if (data[i] == '+') {
+ parser->literal_nonsync = TRUE;
+ continue;
+ }
+
+ if (data[i] < '0' || data[i] > '9') {
+ parser->error = "Invalid literal size";
+ return FALSE;
+ }
+
+ if (parser->literal_size >= ((uoff_t)-1 / 10)) {
+ if (parser->literal_size > ((uoff_t)-1 / 10) ||
+ (uoff_t)(data[i] - '0') > ((uoff_t)-1 % 10)) {
+ parser->error = "Literal size too large";
+ return FALSE;
+ }
+ }
+ parser->literal_size = parser->literal_size * 10 +
+ (data[i] - '0');
+ }
+
+ parser->cur_pos = i;
+ return FALSE;
+}
+
+static bool
+managesieve_parser_read_literal_data(struct managesieve_parser *parser,
+ const unsigned char *data,
+ size_t data_size)
+{
+ if (parser->literal_skip_crlf) {
+ /* Skip \r\n or \n, anything else gives an error */
+ if (data_size == 0)
+ return FALSE;
+
+ if (*data == '\r') {
+ parser->line_size++;
+ data++; data_size--;
+ i_stream_skip(parser->input, 1);
+
+ if (data_size == 0)
+ return FALSE;
+ }
+
+ if (*data != '\n') {
+ parser->error = "Missing LF after literal size";
+ return FALSE;
+ }
+
+ parser->line_size++;
+ data++; data_size--;
+ i_stream_skip(parser->input, 1);
+
+ parser->literal_skip_crlf = FALSE;
+
+ i_assert(parser->cur_pos == 0);
+ }
+
+ if ((parser->flags & MANAGESIEVE_PARSE_FLAG_STRING_STREAM) == 0) {
+ /* Now we just wait until we've read enough data */
+ if (data_size < parser->literal_size) {
+ return FALSE;
+ } else {
+ if (!uni_utf8_data_is_valid(
+ data, (size_t)parser->literal_size)) {
+ parser->error =
+ "Invalid UTF-8 character in literal string.";
+ return FALSE;
+ }
+
+ managesieve_parser_save_arg(
+ parser, data, (size_t)parser->literal_size);
+ parser->cur_pos = (size_t)parser->literal_size;
+ return TRUE;
+ }
+ } else {
+ /* We don't read the data; we just create a stream for the
+ literal */
+ parser->eol = TRUE;
+ parser->str_stream = i_stream_create_limit(
+ parser->input, parser->literal_size);
+ managesieve_parser_save_arg(parser, NULL, 0);
+ return TRUE;
+ }
+}
+
+/* Returns TRUE if argument was fully processed. Also returns TRUE if an
+ argument inside a list was processed. */
+static bool managesieve_parser_read_arg(struct managesieve_parser *parser)
+{
+ const unsigned char *data;
+ size_t data_size;
+
+ data = i_stream_get_data(parser->input, &data_size);
+ if (data_size == 0)
+ return FALSE;
+
+ while (parser->cur_type == ARG_PARSE_NONE) {
+ /* We haven't started parsing yet */
+ if (!managesieve_parser_skip_to_next(parser, &data, &data_size))
+ return FALSE;
+ i_assert(parser->cur_pos == 0);
+
+ switch (data[0]) {
+ case '\r':
+ case '\n':
+ /* Unexpected end of line */
+ parser->eol = TRUE;
+ return FALSE;
+ case '"':
+ parser->cur_type = ARG_PARSE_STRING;
+ parser->str_first_escape = -1;
+ break;
+ case '{':
+ parser->cur_type = ARG_PARSE_LITERAL;
+ parser->literal_size = 0;
+ parser->literal_nonsync = FALSE;
+ break;
+ default:
+ if (!is_valid_atom_char(parser, data[0]))
+ return FALSE;
+ parser->cur_type = ARG_PARSE_ATOM;
+ break;
+ }
+ parser->cur_pos++;
+ }
+
+ i_assert(data_size > 0);
+
+ switch (parser->cur_type) {
+ case ARG_PARSE_ATOM:
+ if (!managesieve_parser_read_atom(parser, data, data_size))
+ return FALSE;
+ break;
+ case ARG_PARSE_STRING:
+ if ((parser->flags &
+ MANAGESIEVE_PARSE_FLAG_STRING_STREAM) != 0) {
+ parser->eol = TRUE;
+ parser->line_size += parser->cur_pos;
+ i_stream_skip(parser->input, parser->cur_pos);
+ parser->cur_pos = 0;
+ parser->str_stream =
+ quoted_string_istream_create(parser);
+ managesieve_parser_save_arg(parser, NULL, 0);
+
+ } else if (!managesieve_parser_read_string(parser,
+ data, data_size)) {
+ return FALSE;
+ }
+ break;
+ case ARG_PARSE_LITERAL:
+ if (!managesieve_parser_read_literal(parser, data, data_size))
+ return FALSE;
+
+ /* Pass through to parsing data. since input->skip was
+ modified, we need to get the data start position again. */
+ data = i_stream_get_data(parser->input, &data_size);
+
+ /* fall through */
+ case ARG_PARSE_LITERAL_DATA:
+ if (!managesieve_parser_read_literal_data(parser,
+ data, data_size))
+ return FALSE;
+ break;
+ default:
+ i_unreached();
+ }
+
+ i_assert(parser->cur_type == ARG_PARSE_NONE);
+ return TRUE;
+}
+
+/* ARG_PARSE_NONE checks that last argument isn't only partially parsed. */
+#define IS_UNFINISHED(parser) \
+ ((parser)->cur_type != ARG_PARSE_NONE || \
+ (parser)->cur_list != &parser->root_list)
+
+static int
+finish_line(struct managesieve_parser *parser, unsigned int count,
+ const struct managesieve_arg **args_r)
+{
+ struct managesieve_arg *arg;
+ int ret = array_count(&parser->root_list);
+
+ parser->line_size += parser->cur_pos;
+ i_stream_skip(parser->input, parser->cur_pos);
+ parser->cur_pos = 0;
+
+ /* Fill the missing parameters with NILs */
+ while (count > array_count(&parser->root_list)) {
+ arg = array_append_space(&parser->root_list);
+ arg->type = MANAGESIEVE_ARG_NONE;
+ }
+ arg = array_append_space(&parser->root_list);
+ arg->type = MANAGESIEVE_ARG_EOL;
+
+ *args_r = array_get(&parser->root_list, &count);
+ return ret;
+}
+
+int managesieve_parser_read_args(struct managesieve_parser *parser,
+ unsigned int count,
+ enum managesieve_parser_flags flags,
+ const struct managesieve_arg **args_r)
+{
+ parser->flags = flags;
+
+ while (!parser->eol && (count == 0 || IS_UNFINISHED(parser) ||
+ array_count(&parser->root_list) < count)) {
+ if (!managesieve_parser_read_arg(parser))
+ break;
+
+ if (parser->line_size > parser->max_line_size) {
+ parser->error = "MANAGESIEVE command line too large";
+ break;
+ }
+ }
+
+ if (parser->error != NULL) {
+ /* Error, abort */
+ parser->line_size += parser->cur_pos;
+ i_stream_skip(parser->input, parser->cur_pos);
+ parser->cur_pos = 0;
+ *args_r = NULL;
+ return -1;
+ } else if ((!IS_UNFINISHED(parser) && count > 0 &&
+ array_count(&parser->root_list) >= count) || parser->eol) {
+ /* All arguments read / end of line. */
+ return finish_line(parser, count, args_r);
+ } else {
+ /* Need more data */
+ *args_r = NULL;
+ return -2;
+ }
+}
+
+int managesieve_parser_finish_line(struct managesieve_parser *parser,
+ unsigned int count,
+ enum managesieve_parser_flags flags,
+ const struct managesieve_arg **args_r)
+{
+ const unsigned char *data;
+ size_t data_size;
+ int ret;
+
+ ret = managesieve_parser_read_args(parser, count, flags, args_r);
+ if (ret == -2) {
+ /* We should have noticed end of everything except atom */
+ if (parser->cur_type == ARG_PARSE_ATOM) {
+ data = i_stream_get_data(parser->input, &data_size);
+ managesieve_parser_save_arg(parser, data, data_size);
+ }
+ }
+ return finish_line(parser, count, args_r);
+}
+
+const char *managesieve_parser_read_word(struct managesieve_parser *parser)
+{
+ const unsigned char *data;
+ size_t i, data_size;
+
+ data = i_stream_get_data(parser->input, &data_size);
+
+ for (i = 0; i < data_size; i++) {
+ if (data[i] == ' ' || data[i] == '\r' || data[i] == '\n')
+ break;
+ }
+
+ if (i < data_size) {
+ data_size = i + (data[i] == ' ' ? 1 : 0);
+ parser->line_size += data_size;
+ i_stream_skip(parser->input, data_size);
+ return p_strndup(parser->pool, data, i);
+ } else {
+ return NULL;
+ }
+}
+
+/*
+ * Quoted string stream
+ */
+
+struct quoted_string_istream {
+ struct istream_private istream;
+
+ /* The end '"' was found */
+ bool str_end:1;
+};
+
+static int
+quoted_string_istream_read_parent(struct quoted_string_istream *qsstream,
+ unsigned int min_bytes)
+{
+ struct istream_private *stream = &qsstream->istream;
+ size_t size, avail;
+ ssize_t ret;
+
+ size = i_stream_get_data_size(stream->parent);
+ while (size < min_bytes) {
+ ret = i_stream_read_memarea(stream->parent);
+ if (ret <= 0) {
+ if (ret == -2) {
+ /* Tiny parent buffer size - shouldn't happen */
+ return -2;
+ }
+ stream->istream.stream_errno =
+ stream->parent->stream_errno;
+ stream->istream.eof = stream->parent->eof;
+ if (ret == -1 && stream->istream.stream_errno == 0) {
+ io_stream_set_error(&stream->iostream,
+ "Quoted string ends without closing quotes");
+ stream->istream.stream_errno = EPIPE;
+ }
+ return ret;
+ }
+ size = i_stream_get_data_size(stream->parent);
+ }
+
+ if (!i_stream_try_alloc(stream, size, &avail))
+ return -2;
+ return 1;
+}
+
+static ssize_t quoted_string_istream_read(struct istream_private *stream)
+{
+ struct quoted_string_istream *qsstream =
+ (struct quoted_string_istream *)stream;
+ const unsigned char *data;
+ unsigned int extra;
+ size_t i, dest, size;
+ ssize_t ret;
+
+ if (qsstream->str_end) {
+ stream->istream.eof = TRUE;
+ return -1;
+ }
+
+ ret = quoted_string_istream_read_parent(qsstream, 1);
+ if (ret <= 0)
+ return ret;
+
+ /* @UNSAFE */
+ dest = stream->pos;
+ extra = 0;
+
+ data = i_stream_get_data(stream->parent, &size);
+ for (i = 0; i < size && dest < stream->buffer_size; ) {
+ if (data[i] == '"') {
+ i++;
+ qsstream->str_end = TRUE;
+ if (dest == stream->pos) {
+ i_stream_skip(stream->parent, i);
+ stream->istream.eof = TRUE;
+ return -1;
+ }
+ break;
+ } else if (data[i] == '\\') {
+ if (i+1 == size) {
+ /* Not enough input for \x */
+ extra = 1;
+ break;
+ }
+ i++;
+
+ if (!IS_QUOTED_SPECIAL(data[i])) {
+ /* Invalid string */
+ io_stream_set_error(&stream->iostream,
+ "Escaped quoted-string character is not a QUOTED-SPECIAL");
+ stream->istream.stream_errno = EINVAL;
+ return -1;
+ }
+ stream->w_buffer[dest++] = data[i];
+ i++;
+ } else {
+ if (data[i] == '\r' || data[i] == '\n') {
+ io_stream_set_error(&stream->iostream,
+ "Quoted string contains an invalid character");
+ stream->istream.stream_errno = EINVAL;
+ return -1;
+ }
+
+ stream->w_buffer[dest++] = data[i];
+ i++;
+ }
+ i_assert(dest <= stream->buffer_size);
+ }
+ i_stream_skip(stream->parent, i);
+
+ ret = dest - stream->pos;
+ if (ret == 0) {
+ /* Not enough input */
+ i_assert(i == 0);
+ i_assert(extra > 0);
+ ret = quoted_string_istream_read_parent(qsstream, extra+1);
+ if (ret <= 0)
+ return ret;
+ return quoted_string_istream_read(stream);
+ }
+ i_assert(ret > 0);
+ stream->pos = dest;
+ return ret;
+}
+
+static struct
+istream *quoted_string_istream_create(struct managesieve_parser *parser)
+{
+ struct quoted_string_istream *qsstream;
+
+ qsstream = i_new(struct quoted_string_istream, 1);
+ qsstream->istream.max_buffer_size =
+ parser->input->real_stream->max_buffer_size;
+ qsstream->istream.read = quoted_string_istream_read;
+
+ qsstream->istream.istream.readable_fd = FALSE;
+ qsstream->istream.istream.blocking = parser->input->blocking;
+ qsstream->istream.istream.seekable = FALSE;
+ return i_stream_create(&qsstream->istream, parser->input,
+ i_stream_get_fd(parser->input), 0);
+}
diff --git a/pigeonhole/src/lib-managesieve/managesieve-parser.h b/pigeonhole/src/lib-managesieve/managesieve-parser.h
new file mode 100644
index 0000000..93e67ae
--- /dev/null
+++ b/pigeonhole/src/lib-managesieve/managesieve-parser.h
@@ -0,0 +1,67 @@
+#ifndef MANAGESIEVE_PARSER_H
+#define MANAGESIEVE_PARSER_H
+
+#include "managesieve-arg.h"
+
+enum managesieve_parser_flags {
+ /* Set this flag if you want to read a string argument as as stream.
+ Useful when you need to deal with large strings. The string must be
+ the last read argument. */
+ MANAGESIEVE_PARSE_FLAG_STRING_STREAM = 0x01,
+ /* Don't remove '\' chars from string arguments */
+ MANAGESIEVE_PARSE_FLAG_NO_UNESCAPE = 0x02,
+ /* Return literals as MANAGESIEVE_ARG_LITERAL instead of
+ MANAGESIEVE_ARG_STRING */
+ MANAGESIEVE_PARSE_FLAG_LITERAL_TYPE = 0x04
+};
+
+struct managesieve_parser;
+
+/* Create new MANAGESIEVE argument parser.
+
+ max_line_size can be used to approximately limit the maximum amount of memory
+ that gets allocated when parsing a line. Input buffer size limits the maximum
+ size of each parsed token.
+
+ Usually the largest lines are large only because they have a one huge message
+ set token, so you'll probably want to keep input buffer size the same as
+ max_line_size. That means the maximum memory usage is around
+ 2 * max_line_size. */
+struct managesieve_parser *
+managesieve_parser_create(struct istream *input, size_t max_line_size);
+void managesieve_parser_destroy(struct managesieve_parser **parser);
+
+/* Reset the parser to initial state. */
+void managesieve_parser_reset(struct managesieve_parser *parser);
+
+/* Return the last error in parser. fatal is set to TRUE if there's no way to
+ continue parsing, currently only if too large non-sync literal size was
+ given. */
+const char *
+managesieve_parser_get_error(struct managesieve_parser *parser, bool *fatal);
+
+/* Read a number of arguments. This function doesn't call i_stream_read(), you
+ need to do that. Returns number of arguments read (may be less than count
+ in case of EOL), -2 if more data is needed or -1 if error occurred.
+
+ count-sized array of arguments are stored into args when return value is 0 or
+ larger. If all arguments weren't read, they're set to NIL. count can be set
+ to 0 to read all arguments in the line. Last element in args is always of
+ type MANAGESIEVE_ARG_EOL. */
+int managesieve_parser_read_args(struct managesieve_parser *parser,
+ unsigned int count,
+ enum managesieve_parser_flags flags,
+ const struct managesieve_arg **args_r);
+
+/* Just like managesieve_parser_read_args(), but assume \n at end of data in
+ input stream. */
+int managesieve_parser_finish_line(struct managesieve_parser *parser,
+ unsigned int count,
+ enum managesieve_parser_flags flags,
+ const struct managesieve_arg **args_r);
+
+/* Read one word - used for reading command name. Returns NULL if more data is
+ needed. */
+const char *managesieve_parser_read_word(struct managesieve_parser *parser);
+
+#endif
diff --git a/pigeonhole/src/lib-managesieve/managesieve-quote.c b/pigeonhole/src/lib-managesieve/managesieve-quote.c
new file mode 100644
index 0000000..a86818c
--- /dev/null
+++ b/pigeonhole/src/lib-managesieve/managesieve-quote.c
@@ -0,0 +1,121 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "unichar.h"
+#include "managesieve-parser.h"
+#include "managesieve-quote.h"
+
+/* Turn the value string into a valid MANAGESIEVE string or literal, no matter
+ * what. QUOTED-SPECIALS are escaped, but any invalid (UTF-8) character
+ * is simply removed. Linebreak characters are not considered invalid, but
+ * they do force the generation of a string literal.
+ */
+void managesieve_quote_append(string_t *str, const unsigned char *value,
+ size_t value_len, bool compress_lwsp)
+{
+ size_t i, extra = 0, escape = 0;
+ string_t *tmp;
+ bool
+ last_lwsp = TRUE,
+ literal = FALSE,
+ modify = FALSE;
+
+ if (value == NULL) {
+ str_append(str, "\"\"");
+ return;
+ }
+
+ if (value_len == (size_t)-1)
+ value_len = strlen((const char *) value);
+
+ for (i = 0; i < value_len; i++) {
+ switch (value[i]) {
+ case ' ':
+ case '\t':
+ if (last_lwsp && compress_lwsp) {
+ modify = TRUE;
+ extra++;
+ }
+ last_lwsp = TRUE;
+ break;
+ case '"':
+ case '\\':
+ escape++;
+ last_lwsp = FALSE;
+ break;
+ case 13:
+ case 10:
+ literal = TRUE;
+ last_lwsp = TRUE;
+ break;
+ default:
+ last_lwsp = FALSE;
+ }
+ }
+
+ if (!literal) {
+ /* no linebreak chars, return as (escaped) "string" */
+ str_append_c(str, '"');
+ } else {
+ /* return as literal */
+ str_printfa(str, "{%zu}\r\n", value_len - extra);
+ }
+
+ tmp = t_str_new(value_len+escape+4);
+ if (!modify && (literal || escape == 0))
+ str_append_data(tmp, value, value_len);
+ else {
+ last_lwsp = TRUE;
+ for (i = 0; i < value_len; i++) {
+ switch (value[i]) {
+ case '"':
+ case '\\':
+ last_lwsp = FALSE;
+ if (!literal)
+ str_append_c(tmp, '\\');
+ str_append_c(tmp, value[i]);
+ break;
+ case ' ':
+ case '\t':
+ if (!last_lwsp || !compress_lwsp)
+ str_append_c(tmp, ' ');
+ last_lwsp = TRUE;
+ break;
+ case 13:
+ case 10:
+ last_lwsp = TRUE;
+ str_append_c(tmp, value[i]);
+ break;
+ default:
+ last_lwsp = FALSE;
+ str_append_c(tmp, value[i]);
+ break;
+ }
+ }
+ }
+
+ if ( uni_utf8_get_valid_data(str_data(tmp), str_len(tmp), str) )
+ str_append_str(str, tmp);
+
+ if (!literal)
+ str_append_c(str, '"');
+}
+
+char *managesieve_quote(pool_t pool, const unsigned char *value, size_t value_len)
+{
+ string_t *str;
+ char *ret;
+
+ if (value == NULL)
+ return "\"\"";
+
+ T_BEGIN {
+ str = t_str_new(value_len + MAX_INT_STRLEN + 5);
+ managesieve_quote_append(str, value, value_len, TRUE);
+ ret = p_strndup(pool, str_data(str), str_len(str));
+ } T_END;
+
+ return ret;
+}
diff --git a/pigeonhole/src/lib-managesieve/managesieve-quote.h b/pigeonhole/src/lib-managesieve/managesieve-quote.h
new file mode 100644
index 0000000..cae5491
--- /dev/null
+++ b/pigeonhole/src/lib-managesieve/managesieve-quote.h
@@ -0,0 +1,17 @@
+#ifndef IMAP_QUOTE_H
+#define IMAP_QUOTE_H
+
+/* Return value suitable for sending to client, either as quoted-string or
+ literal. Note that this also converts TABs into spaces, multiple spaces
+ into single space and NULs to #128. */
+char *managesieve_quote(pool_t pool, const unsigned char *value, size_t value_len);
+
+/* Append to existing string. */
+void managesieve_quote_append(string_t *str, const unsigned char *value,
+ size_t value_len, bool compress_lwsp);
+
+#define managesieve_quote_append_string(str, value, compress_lwsp) \
+ managesieve_quote_append(str, (const unsigned char *)(value), \
+ (size_t)-1, compress_lwsp)
+
+#endif
diff --git a/pigeonhole/src/lib-sieve-tool/Makefile.am b/pigeonhole/src/lib-sieve-tool/Makefile.am
new file mode 100644
index 0000000..3386824
--- /dev/null
+++ b/pigeonhole/src/lib-sieve-tool/Makefile.am
@@ -0,0 +1,13 @@
+noinst_LTLIBRARIES = libsieve-tool.la
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib-sieve \
+ -I$(top_srcdir)/src/lib-sieve/util \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_SERVICE_INCLUDE)
+
+libsieve_tool_la_SOURCES = \
+ sieve-tool.c
+
+noinst_HEADERS = \
+ sieve-tool.h
diff --git a/pigeonhole/src/lib-sieve-tool/Makefile.in b/pigeonhole/src/lib-sieve-tool/Makefile.in
new file mode 100644
index 0000000..c56deeb
--- /dev/null
+++ b/pigeonhole/src/lib-sieve-tool/Makefile.in
@@ -0,0 +1,680 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve-tool
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_tool_la_LIBADD =
+am_libsieve_tool_la_OBJECTS = sieve-tool.lo
+libsieve_tool_la_OBJECTS = $(am_libsieve_tool_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/sieve-tool.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_tool_la_SOURCES)
+DIST_SOURCES = $(libsieve_tool_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve-tool.la
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib-sieve \
+ -I$(top_srcdir)/src/lib-sieve/util \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_SERVICE_INCLUDE)
+
+libsieve_tool_la_SOURCES = \
+ sieve-tool.c
+
+noinst_HEADERS = \
+ sieve-tool.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve-tool/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve-tool/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve-tool.la: $(libsieve_tool_la_OBJECTS) $(libsieve_tool_la_DEPENDENCIES) $(EXTRA_libsieve_tool_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_tool_la_OBJECTS) $(libsieve_tool_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-tool.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/sieve-tool.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/sieve-tool.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve-tool/sieve-tool.c b/pigeonhole/src/lib-sieve-tool/sieve-tool.c
new file mode 100644
index 0000000..435f973
--- /dev/null
+++ b/pigeonhole/src/lib-sieve-tool/sieve-tool.c
@@ -0,0 +1,672 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "lib-signals.h"
+#include "array.h"
+#include "ioloop.h"
+#include "ostream.h"
+#include "hostpid.h"
+#include "dict.h"
+#include "mail-namespace.h"
+#include "mail-storage.h"
+#include "mail-user.h"
+#include "message-address.h"
+#include "smtp-params.h"
+#include "master-service.h"
+#include "master-service-settings.h"
+#include "mail-storage-service.h"
+
+#include "sieve.h"
+#include "sieve-plugins.h"
+#include "sieve-extensions.h"
+
+#include "mail-raw.h"
+
+#include "sieve-tool.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <sysexits.h>
+
+/*
+ * Global state
+ */
+
+struct sieve_tool {
+ char *name;
+
+ bool no_config;
+
+ char *username;
+ char *homedir;
+
+ char *sieve_extensions;
+ ARRAY_TYPE(const_string) sieve_plugins;
+
+ sieve_tool_setting_callback_t setting_callback;
+ void *setting_callback_context;
+
+ struct sieve_instance *svinst;
+
+ struct mail_storage_service_ctx *storage_service;
+ struct mail_storage_service_user *service_user;
+ struct mail_user *mail_user_dovecot;
+ struct mail_user *mail_user;
+
+ struct mail_user *mail_raw_user;
+ struct mail_raw *mail_raw;
+
+ bool debug:1;
+};
+
+struct sieve_tool *sieve_tool;
+
+/*
+ * Settings management
+ */
+
+static const char *
+sieve_tool_sieve_get_setting(void *context, const char *identifier)
+{
+ struct sieve_tool *tool = (struct sieve_tool *) context;
+
+ if (tool->setting_callback != NULL) {
+ return tool->setting_callback(tool->setting_callback_context,
+ identifier);
+ }
+
+ if (tool->mail_user_dovecot == NULL)
+ return NULL;
+
+ return mail_user_plugin_getenv(tool->mail_user_dovecot, identifier);
+}
+
+static const char *sieve_tool_sieve_get_homedir(void *context)
+{
+ struct sieve_tool *tool = (struct sieve_tool *) context;
+
+ return sieve_tool_get_homedir(tool);
+}
+
+const struct sieve_callbacks sieve_tool_callbacks = {
+ sieve_tool_sieve_get_homedir,
+ sieve_tool_sieve_get_setting
+};
+
+/*
+ * Initialization
+ */
+
+static void
+sieve_tool_get_user_data(const char **username_r, const char **homedir_r)
+{
+ uid_t process_euid = geteuid();
+ struct passwd *pw;
+ const char *user = NULL, *home = NULL;
+
+ user = getenv("USER");
+ home = getenv("HOME");
+
+ if (user == NULL || *user == '\0' || home == NULL || *home == '\0') {
+ if ((pw = getpwuid(process_euid)) != NULL) {
+ user = pw->pw_name;
+ home = pw->pw_dir;
+ }
+ }
+
+ if (username_r != NULL) {
+ if (user == NULL || *user == '\0') {
+ i_fatal("couldn't lookup our username (uid=%s)",
+ dec2str(process_euid));
+ }
+
+ *username_r = t_strdup(user);
+ }
+
+ if (homedir_r != NULL)
+ *homedir_r = t_strdup(home);
+}
+
+struct sieve_tool *
+sieve_tool_init(const char *name, int *argc, char **argv[],
+ const char *getopt_str, bool no_config)
+{
+ struct sieve_tool *tool;
+ enum master_service_flags service_flags =
+ MASTER_SERVICE_FLAG_STANDALONE |
+ MASTER_SERVICE_FLAG_DONT_SEND_STATS |
+ MASTER_SERVICE_FLAG_NO_INIT_DATASTACK_FRAME |
+ MASTER_SERVICE_FLAG_DISABLE_SSL_SET;
+
+ if (no_config)
+ service_flags |= MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS;
+
+ master_service = master_service_init(name, service_flags,
+ argc, argv, getopt_str);
+
+ tool = i_new(struct sieve_tool, 1);
+ tool->name = i_strdup(name);
+ tool->no_config = no_config;
+
+ i_array_init(&tool->sieve_plugins, 16);
+
+ return tool;
+}
+
+int sieve_tool_getopt(struct sieve_tool *tool)
+{
+ int c;
+
+ while ((c = master_getopt(master_service)) > 0) {
+ switch (c) {
+ case 'x':
+ /* extensions */
+ if (tool->sieve_extensions != NULL) {
+ i_fatal_status(
+ EX_USAGE,
+ "duplicate -x option specified, "
+ "but only one allowed.");
+ }
+ tool->sieve_extensions = i_strdup(optarg);
+ break;
+ case 'u':
+ if (tool->username == NULL)
+ tool->username = i_strdup(optarg);
+ break;
+ case 'P':
+ /* Plugin */
+ {
+ const char *plugin;
+
+ plugin = t_strdup(optarg);
+ array_append(&tool->sieve_plugins, &plugin, 1);
+ }
+ break;
+ case 'D':
+ tool->debug = TRUE;
+ break;
+ default:
+ return c;
+ }
+ }
+
+ return c;
+}
+
+static void sieve_tool_load_plugins(struct sieve_tool *tool)
+{
+ unsigned int i, count;
+ const char * const *plugins;
+
+ plugins = array_get(&tool->sieve_plugins, &count);
+ for (i = 0; i < count; i++) {
+ const char *path, *file = strrchr(plugins[i], '/');
+
+ if (file != NULL) {
+ path = t_strdup_until(plugins[i], file);
+ file = file+1;
+ } else {
+ path = NULL;
+ file = plugins[i];
+ }
+
+ sieve_plugins_load(tool->svinst, path, file);
+ }
+}
+
+struct sieve_instance *
+sieve_tool_init_finish(struct sieve_tool *tool, bool init_mailstore,
+ bool preserve_root)
+{
+ enum mail_storage_service_flags storage_service_flags =
+ MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR |
+ MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT |
+ MAIL_STORAGE_SERVICE_FLAG_USE_SYSEXITS;
+ struct mail_storage_service_input service_input;
+ struct sieve_environment svenv;
+ const char *username = tool->username;
+ const char *homedir = tool->homedir;
+ const char *errstr;
+
+ master_service_init_finish(master_service);
+
+ if (username == NULL) {
+ sieve_tool_get_user_data(&username, &homedir);
+
+ username = tool->username = i_strdup(username);
+
+ if (tool->homedir != NULL)
+ i_free(tool->homedir);
+ tool->homedir = i_strdup(homedir);
+
+ if (preserve_root) {
+ storage_service_flags |=
+ MAIL_STORAGE_SERVICE_FLAG_NO_RESTRICT_ACCESS;
+ }
+ } else {
+ storage_service_flags |=
+ MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
+ }
+
+ if (!init_mailstore)
+ storage_service_flags |=
+ MAIL_STORAGE_SERVICE_FLAG_NO_NAMESPACES;
+
+ i_zero(&service_input);
+ service_input.module = "mail";
+ service_input.service = tool->name;
+ service_input.username = username;
+
+ tool->storage_service = mail_storage_service_init(
+ master_service, NULL, storage_service_flags);
+ if (mail_storage_service_lookup_next(
+ tool->storage_service, &service_input, &tool->service_user,
+ &tool->mail_user_dovecot, &errstr) <= 0)
+ i_fatal("%s", errstr);
+
+ if (master_service_set(master_service,
+ "mail_full_filesystem_access=yes") < 0)
+ i_unreached();
+
+ memset((void *)&svenv, 0, sizeof(svenv));
+ svenv.username = username;
+ (void)mail_user_get_home(tool->mail_user_dovecot, &svenv.home_dir);
+ svenv.hostname = my_hostdomain();
+ svenv.base_dir = tool->mail_user_dovecot->set->base_dir;
+ svenv.temp_dir = tool->mail_user_dovecot->set->mail_temp_dir;
+ svenv.location = SIEVE_ENV_LOCATION_MS;
+ svenv.delivery_phase = SIEVE_DELIVERY_PHASE_POST;
+
+ /* Initialize Sieve Engine */
+ if ((tool->svinst = sieve_init(&svenv, &sieve_tool_callbacks,
+ tool, tool->debug)) == NULL)
+ i_fatal("failed to initialize sieve implementation");
+
+ /* Load Sieve plugins */
+ if (array_count(&tool->sieve_plugins) > 0)
+ sieve_tool_load_plugins(tool);
+
+ /* Set active Sieve extensions */
+ if (tool->sieve_extensions != NULL) {
+ sieve_set_extensions(tool->svinst, tool->sieve_extensions);
+ } else if (tool->no_config) {
+ sieve_set_extensions(tool->svinst, NULL);
+ }
+
+ return tool->svinst;
+}
+
+void sieve_tool_deinit(struct sieve_tool **_tool)
+{
+ struct sieve_tool *tool = *_tool;
+
+ *_tool = NULL;
+
+ /* Deinitialize Sieve engine */
+ sieve_deinit(&tool->svinst);
+
+ /* Free options */
+
+ if (tool->username != NULL)
+ i_free(tool->username);
+ if (tool->homedir != NULL)
+ i_free(tool->homedir);
+
+ if (tool->sieve_extensions != NULL)
+ i_free(tool->sieve_extensions);
+ array_free(&tool->sieve_plugins);
+
+ /* Free raw mail */
+
+ if (tool->mail_raw != NULL)
+ mail_raw_close(&tool->mail_raw);
+
+ if (tool->mail_raw_user != NULL)
+ mail_user_unref(&tool->mail_raw_user);
+
+ /* Free mail service */
+
+ if (tool->mail_user != NULL)
+ mail_user_unref(&tool->mail_user);
+ if (tool->mail_user_dovecot != NULL)
+ mail_user_unref(&tool->mail_user_dovecot);
+
+ mail_storage_service_user_unref(&tool->service_user);
+ mail_storage_service_deinit(&tool->storage_service);
+
+ /* Free sieve tool object */
+
+ i_free(tool->name);
+ i_free(tool);
+
+ /* Deinitialize service */
+ master_service_deinit(&master_service);
+}
+
+/*
+ * Mail environment
+ */
+
+void sieve_tool_init_mail_user(struct sieve_tool *tool,
+ const char *mail_location)
+{
+ struct mail_user *mail_user_dovecot = tool->mail_user_dovecot;
+ const char *username = tool->username;
+ struct mail_namespace *ns = NULL;
+ const char *home = NULL, *errstr = NULL;
+
+ tool->mail_user = mail_user_alloc(NULL, username,
+ mail_user_dovecot->set_info,
+ mail_user_dovecot->unexpanded_set);
+
+ if ((home = sieve_tool_get_homedir(sieve_tool)) != NULL)
+ mail_user_set_home(tool->mail_user, home);
+
+ if (mail_user_init(tool->mail_user, &errstr) < 0)
+ i_fatal("Test user initialization failed: %s", errstr);
+
+ if (mail_namespaces_init_location(tool->mail_user, mail_location,
+ &errstr) < 0)
+ i_fatal("Test storage creation failed: %s", errstr);
+
+ ns = tool->mail_user->namespaces;
+ ns->flags |= NAMESPACE_FLAG_NOQUOTA | NAMESPACE_FLAG_NOACL;
+}
+
+static void sieve_tool_init_mail_raw_user(struct sieve_tool *tool)
+{
+ if (tool->mail_raw_user == NULL) {
+ tool->mail_raw_user = mail_raw_user_create(
+ master_service, tool->mail_user_dovecot);
+ }
+}
+
+struct mail *
+sieve_tool_open_file_as_mail(struct sieve_tool *tool, const char *path)
+{
+ sieve_tool_init_mail_raw_user(tool);
+
+ if (tool->mail_raw != NULL)
+ mail_raw_close(&tool->mail_raw);
+
+ tool->mail_raw = mail_raw_open_file(tool->mail_raw_user, path);
+
+ return tool->mail_raw->mail;
+}
+
+struct mail *
+sieve_tool_open_data_as_mail(struct sieve_tool *tool, string_t *mail_data)
+{
+ sieve_tool_init_mail_raw_user(tool);
+
+ if (tool->mail_raw != NULL)
+ mail_raw_close(&tool->mail_raw);
+
+ tool->mail_raw = mail_raw_open_data(tool->mail_raw_user, mail_data);
+
+ return tool->mail_raw->mail;
+}
+
+/*
+ * Configuration
+ */
+
+void sieve_tool_set_homedir(struct sieve_tool *tool, const char *homedir)
+{
+ if (tool->homedir != NULL) {
+ if (strcmp(homedir, tool->homedir) == 0)
+ return;
+
+ i_free(tool->homedir);
+ }
+
+ tool->homedir = i_strdup(homedir);
+
+ if (tool->mail_user_dovecot != NULL)
+ mail_user_set_home(tool->mail_user_dovecot, tool->homedir);
+ if (tool->mail_user != NULL)
+ mail_user_set_home(tool->mail_user, tool->homedir);
+}
+
+void sieve_tool_set_setting_callback(struct sieve_tool *tool,
+ sieve_tool_setting_callback_t callback,
+ void *context)
+{
+ tool->setting_callback = callback;
+ tool->setting_callback_context = context;
+}
+
+/*
+ * Accessors
+ */
+
+const char *sieve_tool_get_username(struct sieve_tool *tool)
+{
+ const char *username;
+
+ if (tool->username == NULL) {
+ sieve_tool_get_user_data(&username, NULL);
+ return username;
+ }
+
+ return tool->username;
+}
+
+const char *sieve_tool_get_homedir(struct sieve_tool *tool)
+{
+ const char *homedir = NULL;
+
+ if (tool->homedir != NULL)
+ return tool->homedir;
+
+ if (tool->mail_user_dovecot != NULL &&
+ mail_user_get_home(tool->mail_user_dovecot, &homedir) > 0)
+ return tool->homedir;
+
+ sieve_tool_get_user_data(NULL, &homedir);
+ return homedir;
+}
+
+struct mail_user *sieve_tool_get_mail_user(struct sieve_tool *tool)
+{
+ return (tool->mail_user == NULL ?
+ tool->mail_user_dovecot : tool->mail_user);
+}
+
+struct mail_user *sieve_tool_get_mail_raw_user(struct sieve_tool *tool)
+{
+ sieve_tool_init_mail_raw_user(tool);
+ return tool->mail_raw_user;
+}
+
+/*
+ * Commonly needed functionality
+ */
+
+static const struct smtp_address *
+sieve_tool_get_address(struct mail *mail, const char *header)
+{
+ struct message_address *addr;
+ struct smtp_address *smtp_addr;
+ const char *str;
+
+ if (mail_get_first_header(mail, header, &str) <= 0)
+ return NULL;
+ addr = message_address_parse(pool_datastack_create(),
+ (const unsigned char *)str,
+ strlen(str), 1, 0);
+ if (addr == NULL || addr->mailbox == NULL ||
+ addr->domain == NULL || *addr->mailbox == '\0' ||
+ *addr->domain == '\0')
+ return NULL;
+ if (smtp_address_create_from_msg_temp(addr, &smtp_addr) < 0)
+ return NULL;
+ return smtp_addr;
+}
+
+void sieve_tool_get_envelope_data(struct sieve_message_data *msgdata,
+ struct mail *mail,
+ const struct smtp_address *sender,
+ const struct smtp_address *rcpt_orig,
+ const struct smtp_address *rcpt_final)
+{
+ struct smtp_params_rcpt *rcpt_params;
+
+ /* Get sender address */
+ if (sender == NULL)
+ sender = sieve_tool_get_address(mail, "Return-path");
+ if (sender == NULL)
+ sender = sieve_tool_get_address(mail, "Sender");
+ if (sender == NULL)
+ sender = sieve_tool_get_address(mail, "From");
+ if (sender == NULL)
+ sender = smtp_address_create_temp("sender", "example.com");
+
+ /* Get recipient address */
+ if (rcpt_final == NULL)
+ rcpt_final = sieve_tool_get_address(mail, "Envelope-To");
+ if (rcpt_final == NULL)
+ rcpt_final = sieve_tool_get_address(mail, "To");
+ if (rcpt_final == NULL) {
+ rcpt_final = smtp_address_create_temp("recipient",
+ "example.com");
+ }
+ if (rcpt_orig == NULL)
+ rcpt_orig = rcpt_final;
+
+ msgdata->envelope.mail_from = sender;
+ msgdata->envelope.rcpt_to = rcpt_final;
+
+ rcpt_params = t_new(struct smtp_params_rcpt, 1);
+ rcpt_params->orcpt.addr = rcpt_orig;
+
+ msgdata->envelope.rcpt_params = rcpt_params;
+}
+
+/*
+ * File I/O
+ */
+
+struct ostream *sieve_tool_open_output_stream(const char *filename)
+{
+ struct ostream *outstream;
+ int fd;
+
+ if (strcmp(filename, "-") == 0)
+ outstream = o_stream_create_fd(1, 0);
+ else {
+ if ((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT,
+ 0600)) < 0)
+ i_fatal("failed to open file for writing: %m");
+
+ outstream = o_stream_create_fd_autoclose(&fd, 0);
+ }
+
+ return outstream;
+}
+
+/*
+ * Sieve script handling
+ */
+
+struct sieve_binary *
+sieve_tool_script_compile(struct sieve_instance *svinst,
+ const char *filename, const char *name)
+{
+ struct sieve_error_handler *ehandler;
+ struct sieve_binary *sbin;
+
+ ehandler = sieve_stderr_ehandler_create(svinst, 0);
+ sieve_error_handler_accept_infolog(ehandler, TRUE);
+ sieve_error_handler_accept_debuglog(ehandler, svinst->debug);
+
+ if ((sbin = sieve_compile(svinst, filename, name, ehandler,
+ 0, NULL)) == NULL)
+ i_fatal("failed to compile sieve script '%s'", filename);
+
+ sieve_error_handler_unref(&ehandler);
+ return sbin;
+}
+
+struct sieve_binary *
+sieve_tool_script_open(struct sieve_instance *svinst, const char *filename)
+{
+ struct sieve_error_handler *ehandler;
+ struct sieve_binary *sbin;
+
+ ehandler = sieve_stderr_ehandler_create(svinst, 0);
+ sieve_error_handler_accept_infolog(ehandler, TRUE);
+ sieve_error_handler_accept_debuglog(ehandler, svinst->debug);
+
+ if ((sbin = sieve_open(svinst, filename, NULL, ehandler,
+ 0, NULL)) == NULL) {
+ sieve_error_handler_unref(&ehandler);
+ i_fatal("failed to compile sieve script");
+ }
+
+ sieve_error_handler_unref(&ehandler);
+
+ sieve_save(sbin, FALSE, NULL);
+ return sbin;
+}
+
+void sieve_tool_dump_binary_to(struct sieve_binary *sbin,
+ const char *filename, bool hexdump)
+{
+ struct ostream *dumpstream;
+
+ if (filename == NULL)
+ return;
+
+ dumpstream = sieve_tool_open_output_stream(filename);
+ if (dumpstream != NULL) {
+ if (hexdump)
+ (void)sieve_hexdump(sbin, dumpstream);
+ else
+ (void)sieve_dump(sbin, dumpstream, FALSE);
+ if (o_stream_finish(dumpstream) < 0) {
+ i_fatal("write(%s) failed: %s", filename,
+ o_stream_get_error(dumpstream));
+ }
+ o_stream_destroy(&dumpstream);
+ } else {
+ i_fatal("Failed to create stream for sieve code dump.");
+ }
+}
+
+/*
+ * Commandline option parsing
+ */
+
+void sieve_tool_parse_trace_option(struct sieve_trace_config *tr_config,
+ const char *tr_option)
+{
+ if (str_begins(tr_option, "level=")) {
+ const char *lvl = &tr_option[6];
+
+ if (strcmp(lvl, "none") == 0) {
+ tr_config->level = SIEVE_TRLVL_NONE;
+ } else if (strcmp(lvl, "actions") == 0) {
+ tr_config->level = SIEVE_TRLVL_ACTIONS;
+ } else if (strcmp(lvl, "commands") == 0) {
+ tr_config->level = SIEVE_TRLVL_COMMANDS;
+ } else if (strcmp(lvl, "tests") == 0) {
+ tr_config->level = SIEVE_TRLVL_TESTS;
+ } else if (strcmp(lvl, "matching") == 0) {
+ tr_config->level = SIEVE_TRLVL_MATCHING;
+ } else {
+ i_fatal_status(EX_USAGE,
+ "Unknown -tlevel= trace level: %s", lvl);
+ }
+ } else if (strcmp(tr_option, "debug") == 0) {
+ tr_config->flags |= SIEVE_TRFLG_DEBUG;
+ } else if (strcmp(tr_option, "addresses") == 0) {
+ tr_config->flags |= SIEVE_TRFLG_ADDRESSES;
+ } else {
+ i_fatal_status(EX_USAGE, "Unknown -t trace option value: %s",
+ tr_option);
+ }
+}
diff --git a/pigeonhole/src/lib-sieve-tool/sieve-tool.h b/pigeonhole/src/lib-sieve-tool/sieve-tool.h
new file mode 100644
index 0000000..02f4198
--- /dev/null
+++ b/pigeonhole/src/lib-sieve-tool/sieve-tool.h
@@ -0,0 +1,100 @@
+#ifndef SIEVE_TOOL_H
+#define SIEVE_TOOL_H
+
+#include "sieve-common.h"
+
+/*
+ * Types
+ */
+
+typedef const char *
+(*sieve_tool_setting_callback_t)(void *context, const char *identifier);
+
+/*
+ * Global variables
+ */
+
+extern struct sieve_tool *sieve_tool;
+
+/*
+ * Initialization
+ */
+
+struct sieve_tool *
+sieve_tool_init(const char *name, int *argc, char **argv[],
+ const char *getopt_str, bool no_config);
+
+int sieve_tool_getopt(struct sieve_tool *tool);
+
+struct sieve_instance *
+sieve_tool_init_finish(struct sieve_tool *tool, bool init_mailstore,
+ bool preserve_root);
+
+void sieve_tool_deinit(struct sieve_tool **_tool);
+
+/*
+ * Mail environment
+ */
+
+void sieve_tool_init_mail_user(struct sieve_tool *tool,
+ const char *mail_location);
+
+struct mail *
+sieve_tool_open_file_as_mail(struct sieve_tool *tool, const char *path);
+struct mail *
+sieve_tool_open_data_as_mail(struct sieve_tool *tool, string_t *mail_data);
+
+/*
+ * Accessors
+ */
+
+const char *sieve_tool_get_username(struct sieve_tool *tool);
+const char *sieve_tool_get_homedir(struct sieve_tool *tool);
+struct mail_user *sieve_tool_get_mail_user(struct sieve_tool *tool);
+struct mail_user *sieve_tool_get_mail_raw_user(struct sieve_tool *tool);
+
+/*
+ * Configuration
+ */
+
+void sieve_tool_set_homedir(struct sieve_tool *tool, const char *homedir);
+void sieve_tool_set_setting_callback(struct sieve_tool *tool,
+ sieve_tool_setting_callback_t callback,
+ void *context);
+
+/*
+ * Commonly needed functionality
+ */
+
+void sieve_tool_get_envelope_data(struct sieve_message_data *msgdata,
+ struct mail *mail,
+ const struct smtp_address *sender,
+ const struct smtp_address *rcpt_orig,
+ const struct smtp_address *rcpt_final);
+
+/*
+ * File I/O
+ */
+
+struct ostream *sieve_tool_open_output_stream(const char *filename);
+
+/*
+ * Sieve script handling
+ */
+
+struct sieve_binary *
+sieve_tool_script_compile(struct sieve_instance *svinst,
+ const char *filename, const char *name);
+struct sieve_binary *
+sieve_tool_script_open(struct sieve_instance *svinst, const char *filename);
+void sieve_tool_dump_binary_to(struct sieve_binary *sbin,
+ const char *filename, bool hexdump);
+
+/*
+ * Command line option parsing
+ */
+
+void sieve_tool_parse_trace_option(struct sieve_trace_config *tr_config,
+ const char *tr_option);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/Makefile.am b/pigeonhole/src/lib-sieve/Makefile.am
new file mode 100644
index 0000000..2e80871
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/Makefile.am
@@ -0,0 +1,188 @@
+SUBDIRS = util storage plugins
+
+dovecot_pkglib_LTLIBRARIES = libdovecot-sieve.la
+
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_SERVICE_INCLUDE) \
+ -I$(top_srcdir)/src/lib-sieve/util \
+ -DMODULEDIR=\""$(dovecot_moduledir)"\"
+
+tests = \
+ tst-truefalse.c \
+ tst-not.c \
+ tst-anyof.c \
+ tst-allof.c \
+ tst-address.c \
+ tst-header.c \
+ tst-exists.c \
+ tst-size.c
+
+commands = \
+ cmd-require.c \
+ cmd-stop.c \
+ cmd-if.c \
+ cmd-keep.c \
+ cmd-redirect.c \
+ cmd-discard.c
+
+extensions = \
+ ext-fileinto.c \
+ ext-reject.c \
+ ext-envelope.c \
+ ext-encoded-character.c
+
+match_types = \
+ mcht-is.c \
+ mcht-contains.c \
+ mcht-matches.c
+
+comparators = \
+ cmp-i-octet.c \
+ cmp-i-ascii-casemap.c
+
+if BUILD_UNFINISHED
+unfinished_storages =
+unfinished_plugins =
+endif
+
+strgdir = $(top_builddir)/src/lib-sieve/storage
+storages = \
+ $(strgdir)/data/libsieve_storage_data.la \
+ $(strgdir)/file/libsieve_storage_file.la \
+ $(strgdir)/dict/libsieve_storage_dict.la \
+ $(strgdir)/ldap/libsieve_storage_ldap.la \
+ $(unfinished_storages)
+
+extdir = $(top_builddir)/src/lib-sieve/plugins
+plugins = \
+ $(extdir)/vacation/libsieve_ext_vacation.la \
+ $(extdir)/subaddress/libsieve_ext_subaddress.la \
+ $(extdir)/comparator-i-ascii-numeric/libsieve_ext_comparator-i-ascii-numeric.la \
+ $(extdir)/relational/libsieve_ext_relational.la \
+ $(extdir)/regex/libsieve_ext_regex.la \
+ $(extdir)/copy/libsieve_ext_copy.la \
+ $(extdir)/imap4flags/libsieve_ext_imap4flags.la \
+ $(extdir)/include/libsieve_ext_include.la \
+ $(extdir)/body/libsieve_ext_body.la \
+ $(extdir)/variables/libsieve_ext_variables.la \
+ $(extdir)/enotify/libsieve_ext_enotify.la \
+ $(extdir)/notify/libsieve_ext_notify.la \
+ $(extdir)/environment/libsieve_ext_environment.la \
+ $(extdir)/mailbox/libsieve_ext_mailbox.la \
+ $(extdir)/date/libsieve_ext_date.la \
+ $(extdir)/spamvirustest/libsieve_ext_spamvirustest.la \
+ $(extdir)/ihave/libsieve_ext_ihave.la \
+ $(extdir)/editheader/libsieve_ext_editheader.la \
+ $(extdir)/duplicate/libsieve_ext_duplicate.la \
+ $(extdir)/index/libsieve_ext_index.la \
+ $(extdir)/metadata/libsieve_ext_metadata.la \
+ $(extdir)/mime/libsieve_ext_mime.la \
+ $(extdir)/special-use/libsieve_ext_special_use.la \
+ $(extdir)/vnd.dovecot/debug/libsieve_ext_debug.la \
+ $(extdir)/vnd.dovecot/environment/libsieve_ext_vnd_environment.la \
+ $(extdir)/vnd.dovecot/report/libsieve_ext_vnd_report.la \
+ $(unfinished_plugins)
+
+libdovecot_sieve_la_DEPENDENCIES = \
+ $(storages) \
+ $(plugins) \
+ $(top_builddir)/src/lib-sieve/util/libsieve_util.la \
+ $(LIBDOVECOT_STORAGE_DEPS) \
+ $(LIBDOVECOT_DEPS)
+libdovecot_sieve_la_LIBADD = \
+ $(storages) \
+ $(plugins) \
+ $(top_builddir)/src/lib-sieve/util/libsieve_util.la \
+ $(LIBDOVECOT_STORAGE) \
+ $(LIBDOVECOT)
+
+libdovecot_sieve_la_SOURCES = \
+ sieve-settings.c \
+ sieve-message.c \
+ sieve-smtp.c \
+ sieve-lexer.c \
+ sieve-script.c \
+ sieve-storage.c \
+ sieve-storage-sync.c \
+ sieve-ast.c \
+ sieve-binary.c \
+ sieve-binary-file.c \
+ sieve-binary-code.c \
+ sieve-binary-debug.c \
+ sieve-parser.c \
+ sieve-address.c \
+ sieve-validator.c \
+ sieve-generator.c \
+ sieve-execute.c \
+ sieve-interpreter.c \
+ sieve-runtime-trace.c \
+ sieve-code-dumper.c \
+ sieve-binary-dumper.c \
+ sieve-result.c \
+ sieve-error.c \
+ sieve-objects.c \
+ sieve-stringlist.c \
+ sieve-comparators.c \
+ sieve-match-types.c \
+ sieve-address-parts.c \
+ sieve-address-source.c \
+ sieve-match.c \
+ sieve-commands.c \
+ sieve-code.c \
+ sieve-actions.c \
+ sieve-extensions.c \
+ sieve-plugins.c \
+ $(comparators) \
+ $(match_types) \
+ $(tests) \
+ $(commands) \
+ $(extensions) \
+ sieve.c
+
+headers = \
+ sieve-config.h \
+ sieve-types.h \
+ sieve-common.h \
+ sieve-limits.h \
+ sieve-settings.h \
+ sieve-message.h \
+ sieve-smtp.h \
+ sieve-lexer.h \
+ sieve-script.h \
+ sieve-script-private.h \
+ sieve-storage.h \
+ sieve-storage-private.h \
+ sieve-ast.h \
+ sieve-binary.h \
+ sieve-binary-private.h \
+ sieve-parser.h \
+ sieve-address.h \
+ sieve-validator.h \
+ sieve-generator.h \
+ sieve-execute.h \
+ sieve-interpreter.h \
+ sieve-runtime-trace.h \
+ sieve-runtime.h \
+ sieve-code-dumper.h \
+ sieve-binary-dumper.h \
+ sieve-dump.h \
+ sieve-result.h \
+ sieve-error.h \
+ sieve-error-private.h \
+ sieve-objects.h \
+ sieve-stringlist.h \
+ sieve-match.h \
+ sieve-comparators.h \
+ sieve-match-types.h \
+ sieve-address-parts.h \
+ sieve-address-source.h \
+ sieve-commands.h \
+ sieve-code.h \
+ sieve-actions.h \
+ sieve-extensions.h \
+ sieve-plugins.h \
+ sieve.h
+
+pkginc_libdir=$(dovecot_pkgincludedir)/sieve
+pkginc_lib_HEADERS = $(headers)
diff --git a/pigeonhole/src/lib-sieve/Makefile.in b/pigeonhole/src/lib-sieve/Makefile.in
new file mode 100644
index 0000000..104d4df
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/Makefile.in
@@ -0,0 +1,1311 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(pkginc_lib_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(dovecot_pkglibdir)" \
+ "$(DESTDIR)$(pkginc_libdir)"
+LTLIBRARIES = $(dovecot_pkglib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+am__DEPENDENCIES_2 = $(strgdir)/data/libsieve_storage_data.la \
+ $(strgdir)/file/libsieve_storage_file.la \
+ $(strgdir)/dict/libsieve_storage_dict.la \
+ $(strgdir)/ldap/libsieve_storage_ldap.la $(am__DEPENDENCIES_1)
+am__DEPENDENCIES_3 = $(extdir)/vacation/libsieve_ext_vacation.la \
+ $(extdir)/subaddress/libsieve_ext_subaddress.la \
+ $(extdir)/comparator-i-ascii-numeric/libsieve_ext_comparator-i-ascii-numeric.la \
+ $(extdir)/relational/libsieve_ext_relational.la \
+ $(extdir)/regex/libsieve_ext_regex.la \
+ $(extdir)/copy/libsieve_ext_copy.la \
+ $(extdir)/imap4flags/libsieve_ext_imap4flags.la \
+ $(extdir)/include/libsieve_ext_include.la \
+ $(extdir)/body/libsieve_ext_body.la \
+ $(extdir)/variables/libsieve_ext_variables.la \
+ $(extdir)/enotify/libsieve_ext_enotify.la \
+ $(extdir)/notify/libsieve_ext_notify.la \
+ $(extdir)/environment/libsieve_ext_environment.la \
+ $(extdir)/mailbox/libsieve_ext_mailbox.la \
+ $(extdir)/date/libsieve_ext_date.la \
+ $(extdir)/spamvirustest/libsieve_ext_spamvirustest.la \
+ $(extdir)/ihave/libsieve_ext_ihave.la \
+ $(extdir)/editheader/libsieve_ext_editheader.la \
+ $(extdir)/duplicate/libsieve_ext_duplicate.la \
+ $(extdir)/index/libsieve_ext_index.la \
+ $(extdir)/metadata/libsieve_ext_metadata.la \
+ $(extdir)/mime/libsieve_ext_mime.la \
+ $(extdir)/special-use/libsieve_ext_special_use.la \
+ $(extdir)/vnd.dovecot/debug/libsieve_ext_debug.la \
+ $(extdir)/vnd.dovecot/environment/libsieve_ext_vnd_environment.la \
+ $(extdir)/vnd.dovecot/report/libsieve_ext_vnd_report.la \
+ $(am__DEPENDENCIES_1)
+am__objects_1 = cmp-i-octet.lo cmp-i-ascii-casemap.lo
+am__objects_2 = mcht-is.lo mcht-contains.lo mcht-matches.lo
+am__objects_3 = tst-truefalse.lo tst-not.lo tst-anyof.lo tst-allof.lo \
+ tst-address.lo tst-header.lo tst-exists.lo tst-size.lo
+am__objects_4 = cmd-require.lo cmd-stop.lo cmd-if.lo cmd-keep.lo \
+ cmd-redirect.lo cmd-discard.lo
+am__objects_5 = ext-fileinto.lo ext-reject.lo ext-envelope.lo \
+ ext-encoded-character.lo
+am_libdovecot_sieve_la_OBJECTS = sieve-settings.lo sieve-message.lo \
+ sieve-smtp.lo sieve-lexer.lo sieve-script.lo sieve-storage.lo \
+ sieve-storage-sync.lo sieve-ast.lo sieve-binary.lo \
+ sieve-binary-file.lo sieve-binary-code.lo \
+ sieve-binary-debug.lo sieve-parser.lo sieve-address.lo \
+ sieve-validator.lo sieve-generator.lo sieve-execute.lo \
+ sieve-interpreter.lo sieve-runtime-trace.lo \
+ sieve-code-dumper.lo sieve-binary-dumper.lo sieve-result.lo \
+ sieve-error.lo sieve-objects.lo sieve-stringlist.lo \
+ sieve-comparators.lo sieve-match-types.lo \
+ sieve-address-parts.lo sieve-address-source.lo sieve-match.lo \
+ sieve-commands.lo sieve-code.lo sieve-actions.lo \
+ sieve-extensions.lo sieve-plugins.lo $(am__objects_1) \
+ $(am__objects_2) $(am__objects_3) $(am__objects_4) \
+ $(am__objects_5) sieve.lo
+libdovecot_sieve_la_OBJECTS = $(am_libdovecot_sieve_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cmd-discard.Plo \
+ ./$(DEPDIR)/cmd-if.Plo ./$(DEPDIR)/cmd-keep.Plo \
+ ./$(DEPDIR)/cmd-redirect.Plo ./$(DEPDIR)/cmd-require.Plo \
+ ./$(DEPDIR)/cmd-stop.Plo ./$(DEPDIR)/cmp-i-ascii-casemap.Plo \
+ ./$(DEPDIR)/cmp-i-octet.Plo \
+ ./$(DEPDIR)/ext-encoded-character.Plo \
+ ./$(DEPDIR)/ext-envelope.Plo ./$(DEPDIR)/ext-fileinto.Plo \
+ ./$(DEPDIR)/ext-reject.Plo ./$(DEPDIR)/mcht-contains.Plo \
+ ./$(DEPDIR)/mcht-is.Plo ./$(DEPDIR)/mcht-matches.Plo \
+ ./$(DEPDIR)/sieve-actions.Plo \
+ ./$(DEPDIR)/sieve-address-parts.Plo \
+ ./$(DEPDIR)/sieve-address-source.Plo \
+ ./$(DEPDIR)/sieve-address.Plo ./$(DEPDIR)/sieve-ast.Plo \
+ ./$(DEPDIR)/sieve-binary-code.Plo \
+ ./$(DEPDIR)/sieve-binary-debug.Plo \
+ ./$(DEPDIR)/sieve-binary-dumper.Plo \
+ ./$(DEPDIR)/sieve-binary-file.Plo ./$(DEPDIR)/sieve-binary.Plo \
+ ./$(DEPDIR)/sieve-code-dumper.Plo ./$(DEPDIR)/sieve-code.Plo \
+ ./$(DEPDIR)/sieve-commands.Plo \
+ ./$(DEPDIR)/sieve-comparators.Plo ./$(DEPDIR)/sieve-error.Plo \
+ ./$(DEPDIR)/sieve-execute.Plo ./$(DEPDIR)/sieve-extensions.Plo \
+ ./$(DEPDIR)/sieve-generator.Plo \
+ ./$(DEPDIR)/sieve-interpreter.Plo ./$(DEPDIR)/sieve-lexer.Plo \
+ ./$(DEPDIR)/sieve-match-types.Plo ./$(DEPDIR)/sieve-match.Plo \
+ ./$(DEPDIR)/sieve-message.Plo ./$(DEPDIR)/sieve-objects.Plo \
+ ./$(DEPDIR)/sieve-parser.Plo ./$(DEPDIR)/sieve-plugins.Plo \
+ ./$(DEPDIR)/sieve-result.Plo \
+ ./$(DEPDIR)/sieve-runtime-trace.Plo \
+ ./$(DEPDIR)/sieve-script.Plo ./$(DEPDIR)/sieve-settings.Plo \
+ ./$(DEPDIR)/sieve-smtp.Plo ./$(DEPDIR)/sieve-storage-sync.Plo \
+ ./$(DEPDIR)/sieve-storage.Plo ./$(DEPDIR)/sieve-stringlist.Plo \
+ ./$(DEPDIR)/sieve-validator.Plo ./$(DEPDIR)/sieve.Plo \
+ ./$(DEPDIR)/tst-address.Plo ./$(DEPDIR)/tst-allof.Plo \
+ ./$(DEPDIR)/tst-anyof.Plo ./$(DEPDIR)/tst-exists.Plo \
+ ./$(DEPDIR)/tst-header.Plo ./$(DEPDIR)/tst-not.Plo \
+ ./$(DEPDIR)/tst-size.Plo ./$(DEPDIR)/tst-truefalse.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libdovecot_sieve_la_SOURCES)
+DIST_SOURCES = $(libdovecot_sieve_la_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(pkginc_lib_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = util storage plugins
+dovecot_pkglib_LTLIBRARIES = libdovecot-sieve.la
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_SERVICE_INCLUDE) \
+ -I$(top_srcdir)/src/lib-sieve/util \
+ -DMODULEDIR=\""$(dovecot_moduledir)"\"
+
+tests = \
+ tst-truefalse.c \
+ tst-not.c \
+ tst-anyof.c \
+ tst-allof.c \
+ tst-address.c \
+ tst-header.c \
+ tst-exists.c \
+ tst-size.c
+
+commands = \
+ cmd-require.c \
+ cmd-stop.c \
+ cmd-if.c \
+ cmd-keep.c \
+ cmd-redirect.c \
+ cmd-discard.c
+
+extensions = \
+ ext-fileinto.c \
+ ext-reject.c \
+ ext-envelope.c \
+ ext-encoded-character.c
+
+match_types = \
+ mcht-is.c \
+ mcht-contains.c \
+ mcht-matches.c
+
+comparators = \
+ cmp-i-octet.c \
+ cmp-i-ascii-casemap.c
+
+@BUILD_UNFINISHED_TRUE@unfinished_storages =
+@BUILD_UNFINISHED_TRUE@unfinished_plugins =
+strgdir = $(top_builddir)/src/lib-sieve/storage
+storages = \
+ $(strgdir)/data/libsieve_storage_data.la \
+ $(strgdir)/file/libsieve_storage_file.la \
+ $(strgdir)/dict/libsieve_storage_dict.la \
+ $(strgdir)/ldap/libsieve_storage_ldap.la \
+ $(unfinished_storages)
+
+extdir = $(top_builddir)/src/lib-sieve/plugins
+plugins = \
+ $(extdir)/vacation/libsieve_ext_vacation.la \
+ $(extdir)/subaddress/libsieve_ext_subaddress.la \
+ $(extdir)/comparator-i-ascii-numeric/libsieve_ext_comparator-i-ascii-numeric.la \
+ $(extdir)/relational/libsieve_ext_relational.la \
+ $(extdir)/regex/libsieve_ext_regex.la \
+ $(extdir)/copy/libsieve_ext_copy.la \
+ $(extdir)/imap4flags/libsieve_ext_imap4flags.la \
+ $(extdir)/include/libsieve_ext_include.la \
+ $(extdir)/body/libsieve_ext_body.la \
+ $(extdir)/variables/libsieve_ext_variables.la \
+ $(extdir)/enotify/libsieve_ext_enotify.la \
+ $(extdir)/notify/libsieve_ext_notify.la \
+ $(extdir)/environment/libsieve_ext_environment.la \
+ $(extdir)/mailbox/libsieve_ext_mailbox.la \
+ $(extdir)/date/libsieve_ext_date.la \
+ $(extdir)/spamvirustest/libsieve_ext_spamvirustest.la \
+ $(extdir)/ihave/libsieve_ext_ihave.la \
+ $(extdir)/editheader/libsieve_ext_editheader.la \
+ $(extdir)/duplicate/libsieve_ext_duplicate.la \
+ $(extdir)/index/libsieve_ext_index.la \
+ $(extdir)/metadata/libsieve_ext_metadata.la \
+ $(extdir)/mime/libsieve_ext_mime.la \
+ $(extdir)/special-use/libsieve_ext_special_use.la \
+ $(extdir)/vnd.dovecot/debug/libsieve_ext_debug.la \
+ $(extdir)/vnd.dovecot/environment/libsieve_ext_vnd_environment.la \
+ $(extdir)/vnd.dovecot/report/libsieve_ext_vnd_report.la \
+ $(unfinished_plugins)
+
+libdovecot_sieve_la_DEPENDENCIES = \
+ $(storages) \
+ $(plugins) \
+ $(top_builddir)/src/lib-sieve/util/libsieve_util.la \
+ $(LIBDOVECOT_STORAGE_DEPS) \
+ $(LIBDOVECOT_DEPS)
+
+libdovecot_sieve_la_LIBADD = \
+ $(storages) \
+ $(plugins) \
+ $(top_builddir)/src/lib-sieve/util/libsieve_util.la \
+ $(LIBDOVECOT_STORAGE) \
+ $(LIBDOVECOT)
+
+libdovecot_sieve_la_SOURCES = \
+ sieve-settings.c \
+ sieve-message.c \
+ sieve-smtp.c \
+ sieve-lexer.c \
+ sieve-script.c \
+ sieve-storage.c \
+ sieve-storage-sync.c \
+ sieve-ast.c \
+ sieve-binary.c \
+ sieve-binary-file.c \
+ sieve-binary-code.c \
+ sieve-binary-debug.c \
+ sieve-parser.c \
+ sieve-address.c \
+ sieve-validator.c \
+ sieve-generator.c \
+ sieve-execute.c \
+ sieve-interpreter.c \
+ sieve-runtime-trace.c \
+ sieve-code-dumper.c \
+ sieve-binary-dumper.c \
+ sieve-result.c \
+ sieve-error.c \
+ sieve-objects.c \
+ sieve-stringlist.c \
+ sieve-comparators.c \
+ sieve-match-types.c \
+ sieve-address-parts.c \
+ sieve-address-source.c \
+ sieve-match.c \
+ sieve-commands.c \
+ sieve-code.c \
+ sieve-actions.c \
+ sieve-extensions.c \
+ sieve-plugins.c \
+ $(comparators) \
+ $(match_types) \
+ $(tests) \
+ $(commands) \
+ $(extensions) \
+ sieve.c
+
+headers = \
+ sieve-config.h \
+ sieve-types.h \
+ sieve-common.h \
+ sieve-limits.h \
+ sieve-settings.h \
+ sieve-message.h \
+ sieve-smtp.h \
+ sieve-lexer.h \
+ sieve-script.h \
+ sieve-script-private.h \
+ sieve-storage.h \
+ sieve-storage-private.h \
+ sieve-ast.h \
+ sieve-binary.h \
+ sieve-binary-private.h \
+ sieve-parser.h \
+ sieve-address.h \
+ sieve-validator.h \
+ sieve-generator.h \
+ sieve-execute.h \
+ sieve-interpreter.h \
+ sieve-runtime-trace.h \
+ sieve-runtime.h \
+ sieve-code-dumper.h \
+ sieve-binary-dumper.h \
+ sieve-dump.h \
+ sieve-result.h \
+ sieve-error.h \
+ sieve-error-private.h \
+ sieve-objects.h \
+ sieve-stringlist.h \
+ sieve-match.h \
+ sieve-comparators.h \
+ sieve-match-types.h \
+ sieve-address-parts.h \
+ sieve-address-source.h \
+ sieve-commands.h \
+ sieve-code.h \
+ sieve-actions.h \
+ sieve-extensions.h \
+ sieve-plugins.h \
+ sieve.h
+
+pkginc_libdir = $(dovecot_pkgincludedir)/sieve
+pkginc_lib_HEADERS = $(headers)
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-dovecot_pkglibLTLIBRARIES: $(dovecot_pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(dovecot_pkglib_LTLIBRARIES)'; test -n "$(dovecot_pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(dovecot_pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(dovecot_pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(dovecot_pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(dovecot_pkglibdir)"; \
+ }
+
+uninstall-dovecot_pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dovecot_pkglib_LTLIBRARIES)'; test -n "$(dovecot_pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(dovecot_pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(dovecot_pkglibdir)/$$f"; \
+ done
+
+clean-dovecot_pkglibLTLIBRARIES:
+ -test -z "$(dovecot_pkglib_LTLIBRARIES)" || rm -f $(dovecot_pkglib_LTLIBRARIES)
+ @list='$(dovecot_pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libdovecot-sieve.la: $(libdovecot_sieve_la_OBJECTS) $(libdovecot_sieve_la_DEPENDENCIES) $(EXTRA_libdovecot_sieve_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) -rpath $(dovecot_pkglibdir) $(libdovecot_sieve_la_OBJECTS) $(libdovecot_sieve_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-discard.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-if.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-keep.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-redirect.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-require.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-stop.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmp-i-ascii-casemap.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmp-i-octet.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-encoded-character.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-envelope.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-fileinto.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-reject.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcht-contains.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcht-is.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcht-matches.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-actions.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-address-parts.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-address-source.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-address.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-ast.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-binary-code.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-binary-debug.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-binary-dumper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-binary-file.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-binary.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-code-dumper.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-code.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-commands.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-comparators.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-error.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-execute.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-extensions.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-generator.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-interpreter.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-lexer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-match-types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-match.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-message.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-objects.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-parser.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-plugins.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-result.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-runtime-trace.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-script.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-settings.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-smtp.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-storage-sync.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-storage.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-stringlist.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-validator.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-address.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-allof.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-anyof.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-exists.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-header.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-not.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-size.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-truefalse.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
+ done
+
+uninstall-pkginc_libHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(dovecot_pkglibdir)" "$(DESTDIR)$(pkginc_libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-dovecot_pkglibLTLIBRARIES clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f ./$(DEPDIR)/cmd-discard.Plo
+ -rm -f ./$(DEPDIR)/cmd-if.Plo
+ -rm -f ./$(DEPDIR)/cmd-keep.Plo
+ -rm -f ./$(DEPDIR)/cmd-redirect.Plo
+ -rm -f ./$(DEPDIR)/cmd-require.Plo
+ -rm -f ./$(DEPDIR)/cmd-stop.Plo
+ -rm -f ./$(DEPDIR)/cmp-i-ascii-casemap.Plo
+ -rm -f ./$(DEPDIR)/cmp-i-octet.Plo
+ -rm -f ./$(DEPDIR)/ext-encoded-character.Plo
+ -rm -f ./$(DEPDIR)/ext-envelope.Plo
+ -rm -f ./$(DEPDIR)/ext-fileinto.Plo
+ -rm -f ./$(DEPDIR)/ext-reject.Plo
+ -rm -f ./$(DEPDIR)/mcht-contains.Plo
+ -rm -f ./$(DEPDIR)/mcht-is.Plo
+ -rm -f ./$(DEPDIR)/mcht-matches.Plo
+ -rm -f ./$(DEPDIR)/sieve-actions.Plo
+ -rm -f ./$(DEPDIR)/sieve-address-parts.Plo
+ -rm -f ./$(DEPDIR)/sieve-address-source.Plo
+ -rm -f ./$(DEPDIR)/sieve-address.Plo
+ -rm -f ./$(DEPDIR)/sieve-ast.Plo
+ -rm -f ./$(DEPDIR)/sieve-binary-code.Plo
+ -rm -f ./$(DEPDIR)/sieve-binary-debug.Plo
+ -rm -f ./$(DEPDIR)/sieve-binary-dumper.Plo
+ -rm -f ./$(DEPDIR)/sieve-binary-file.Plo
+ -rm -f ./$(DEPDIR)/sieve-binary.Plo
+ -rm -f ./$(DEPDIR)/sieve-code-dumper.Plo
+ -rm -f ./$(DEPDIR)/sieve-code.Plo
+ -rm -f ./$(DEPDIR)/sieve-commands.Plo
+ -rm -f ./$(DEPDIR)/sieve-comparators.Plo
+ -rm -f ./$(DEPDIR)/sieve-error.Plo
+ -rm -f ./$(DEPDIR)/sieve-execute.Plo
+ -rm -f ./$(DEPDIR)/sieve-extensions.Plo
+ -rm -f ./$(DEPDIR)/sieve-generator.Plo
+ -rm -f ./$(DEPDIR)/sieve-interpreter.Plo
+ -rm -f ./$(DEPDIR)/sieve-lexer.Plo
+ -rm -f ./$(DEPDIR)/sieve-match-types.Plo
+ -rm -f ./$(DEPDIR)/sieve-match.Plo
+ -rm -f ./$(DEPDIR)/sieve-message.Plo
+ -rm -f ./$(DEPDIR)/sieve-objects.Plo
+ -rm -f ./$(DEPDIR)/sieve-parser.Plo
+ -rm -f ./$(DEPDIR)/sieve-plugins.Plo
+ -rm -f ./$(DEPDIR)/sieve-result.Plo
+ -rm -f ./$(DEPDIR)/sieve-runtime-trace.Plo
+ -rm -f ./$(DEPDIR)/sieve-script.Plo
+ -rm -f ./$(DEPDIR)/sieve-settings.Plo
+ -rm -f ./$(DEPDIR)/sieve-smtp.Plo
+ -rm -f ./$(DEPDIR)/sieve-storage-sync.Plo
+ -rm -f ./$(DEPDIR)/sieve-storage.Plo
+ -rm -f ./$(DEPDIR)/sieve-stringlist.Plo
+ -rm -f ./$(DEPDIR)/sieve-validator.Plo
+ -rm -f ./$(DEPDIR)/sieve.Plo
+ -rm -f ./$(DEPDIR)/tst-address.Plo
+ -rm -f ./$(DEPDIR)/tst-allof.Plo
+ -rm -f ./$(DEPDIR)/tst-anyof.Plo
+ -rm -f ./$(DEPDIR)/tst-exists.Plo
+ -rm -f ./$(DEPDIR)/tst-header.Plo
+ -rm -f ./$(DEPDIR)/tst-not.Plo
+ -rm -f ./$(DEPDIR)/tst-size.Plo
+ -rm -f ./$(DEPDIR)/tst-truefalse.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-dovecot_pkglibLTLIBRARIES \
+ install-pkginc_libHEADERS
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f ./$(DEPDIR)/cmd-discard.Plo
+ -rm -f ./$(DEPDIR)/cmd-if.Plo
+ -rm -f ./$(DEPDIR)/cmd-keep.Plo
+ -rm -f ./$(DEPDIR)/cmd-redirect.Plo
+ -rm -f ./$(DEPDIR)/cmd-require.Plo
+ -rm -f ./$(DEPDIR)/cmd-stop.Plo
+ -rm -f ./$(DEPDIR)/cmp-i-ascii-casemap.Plo
+ -rm -f ./$(DEPDIR)/cmp-i-octet.Plo
+ -rm -f ./$(DEPDIR)/ext-encoded-character.Plo
+ -rm -f ./$(DEPDIR)/ext-envelope.Plo
+ -rm -f ./$(DEPDIR)/ext-fileinto.Plo
+ -rm -f ./$(DEPDIR)/ext-reject.Plo
+ -rm -f ./$(DEPDIR)/mcht-contains.Plo
+ -rm -f ./$(DEPDIR)/mcht-is.Plo
+ -rm -f ./$(DEPDIR)/mcht-matches.Plo
+ -rm -f ./$(DEPDIR)/sieve-actions.Plo
+ -rm -f ./$(DEPDIR)/sieve-address-parts.Plo
+ -rm -f ./$(DEPDIR)/sieve-address-source.Plo
+ -rm -f ./$(DEPDIR)/sieve-address.Plo
+ -rm -f ./$(DEPDIR)/sieve-ast.Plo
+ -rm -f ./$(DEPDIR)/sieve-binary-code.Plo
+ -rm -f ./$(DEPDIR)/sieve-binary-debug.Plo
+ -rm -f ./$(DEPDIR)/sieve-binary-dumper.Plo
+ -rm -f ./$(DEPDIR)/sieve-binary-file.Plo
+ -rm -f ./$(DEPDIR)/sieve-binary.Plo
+ -rm -f ./$(DEPDIR)/sieve-code-dumper.Plo
+ -rm -f ./$(DEPDIR)/sieve-code.Plo
+ -rm -f ./$(DEPDIR)/sieve-commands.Plo
+ -rm -f ./$(DEPDIR)/sieve-comparators.Plo
+ -rm -f ./$(DEPDIR)/sieve-error.Plo
+ -rm -f ./$(DEPDIR)/sieve-execute.Plo
+ -rm -f ./$(DEPDIR)/sieve-extensions.Plo
+ -rm -f ./$(DEPDIR)/sieve-generator.Plo
+ -rm -f ./$(DEPDIR)/sieve-interpreter.Plo
+ -rm -f ./$(DEPDIR)/sieve-lexer.Plo
+ -rm -f ./$(DEPDIR)/sieve-match-types.Plo
+ -rm -f ./$(DEPDIR)/sieve-match.Plo
+ -rm -f ./$(DEPDIR)/sieve-message.Plo
+ -rm -f ./$(DEPDIR)/sieve-objects.Plo
+ -rm -f ./$(DEPDIR)/sieve-parser.Plo
+ -rm -f ./$(DEPDIR)/sieve-plugins.Plo
+ -rm -f ./$(DEPDIR)/sieve-result.Plo
+ -rm -f ./$(DEPDIR)/sieve-runtime-trace.Plo
+ -rm -f ./$(DEPDIR)/sieve-script.Plo
+ -rm -f ./$(DEPDIR)/sieve-settings.Plo
+ -rm -f ./$(DEPDIR)/sieve-smtp.Plo
+ -rm -f ./$(DEPDIR)/sieve-storage-sync.Plo
+ -rm -f ./$(DEPDIR)/sieve-storage.Plo
+ -rm -f ./$(DEPDIR)/sieve-stringlist.Plo
+ -rm -f ./$(DEPDIR)/sieve-validator.Plo
+ -rm -f ./$(DEPDIR)/sieve.Plo
+ -rm -f ./$(DEPDIR)/tst-address.Plo
+ -rm -f ./$(DEPDIR)/tst-allof.Plo
+ -rm -f ./$(DEPDIR)/tst-anyof.Plo
+ -rm -f ./$(DEPDIR)/tst-exists.Plo
+ -rm -f ./$(DEPDIR)/tst-header.Plo
+ -rm -f ./$(DEPDIR)/tst-not.Plo
+ -rm -f ./$(DEPDIR)/tst-size.Plo
+ -rm -f ./$(DEPDIR)/tst-truefalse.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-dovecot_pkglibLTLIBRARIES \
+ uninstall-pkginc_libHEADERS
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--depfiles check check-am clean \
+ clean-dovecot_pkglibLTLIBRARIES clean-generic clean-libtool \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dovecot_pkglibLTLIBRARIES \
+ install-dvi install-dvi-am install-exec install-exec-am \
+ install-html install-html-am install-info install-info-am \
+ install-man install-pdf install-pdf-am \
+ install-pkginc_libHEADERS install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-dovecot_pkglibLTLIBRARIES \
+ uninstall-pkginc_libHEADERS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/cmd-discard.c b/pigeonhole/src/lib-sieve/cmd-discard.c
new file mode 100644
index 0000000..de460ae
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/cmd-discard.c
@@ -0,0 +1,173 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-dump.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-result.h"
+
+/*
+ * Discard command
+ *
+ * Syntax
+ * discard
+ */
+
+static bool
+cmd_discard_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx ATTR_UNUSED);
+
+const struct sieve_command_def cmd_discard = {
+ .identifier = "discard",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .generate = cmd_discard_generate
+};
+
+/*
+ * Discard operation
+ */
+
+static bool
+cmd_discard_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_discard_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def cmd_discard_operation = {
+ .mnemonic = "DISCARD",
+ .code = SIEVE_OPERATION_DISCARD,
+ .dump = cmd_discard_operation_dump,
+ .execute = cmd_discard_operation_execute
+};
+
+/*
+ * Discard actions
+ */
+
+static bool
+act_discard_equals(const struct sieve_script_env *senv,
+ const struct sieve_action *act1,
+ const struct sieve_action *act2);
+static int
+act_discard_check_duplicate(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other);
+static void
+act_discard_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv, bool *keep);
+static int
+act_discard_execute(const struct sieve_action_exec_env *aenv, void *tr_context,
+ bool *keep);
+
+const struct sieve_action_def act_discard = {
+ .name = "discard",
+ .equals = act_discard_equals,
+ .check_duplicate = act_discard_check_duplicate,
+ .print = act_discard_print,
+ .execute = act_discard_execute,
+};
+
+/*
+ * Code generation
+ */
+
+static bool
+cmd_discard_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ sieve_operation_emit(cgenv->sblock, NULL, &cmd_discard_operation);
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+cmd_discard_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "DISCARD");
+ sieve_code_descend(denv);
+
+ return (sieve_action_opr_optional_dump(denv, address, NULL) == 0);
+}
+
+/*
+ * Interpretation
+ */
+
+static int
+cmd_discard_operation_execute(const struct sieve_runtime_env *renv ATTR_UNUSED,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS,
+ "discard action; cancel implicit keep");
+
+ if (sieve_result_add_action(renv, NULL, "discard", &act_discard,
+ NULL, NULL, 0, FALSE) < 0)
+ return SIEVE_EXEC_FAILURE;
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Action implementation
+ */
+
+static bool
+act_discard_equals(const struct sieve_script_env *senv ATTR_UNUSED,
+ const struct sieve_action *act1 ATTR_UNUSED,
+ const struct sieve_action *act2 ATTR_UNUSED)
+{
+ return TRUE;
+}
+
+static int
+act_discard_check_duplicate(const struct sieve_runtime_env *renv ATTR_UNUSED,
+ const struct sieve_action *act ATTR_UNUSED,
+ const struct sieve_action *act_other ATTR_UNUSED)
+{
+ return 1;
+}
+
+static void
+act_discard_print(const struct sieve_action *action ATTR_UNUSED,
+ const struct sieve_result_print_env *rpenv, bool *keep)
+{
+ sieve_result_action_printf(rpenv, "discard");
+
+ *keep = FALSE;
+}
+
+static int
+act_discard_execute(const struct sieve_action_exec_env *aenv,
+ void *tr_context ATTR_UNUSED, bool *keep)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+
+ eenv->exec_status->significant_action_executed = TRUE;
+
+ struct event_passthrough *e = sieve_action_create_finish_event(aenv);
+
+ sieve_result_event_log(aenv, e->event(),
+ "Marked message to be discarded if not explicitly delivered "
+ "(discard action)");
+ *keep = FALSE;
+
+ return SIEVE_EXEC_OK;
+}
+
diff --git a/pigeonhole/src/lib-sieve/cmd-if.c b/pigeonhole/src/lib-sieve/cmd-if.c
new file mode 100644
index 0000000..2ae186e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/cmd-if.c
@@ -0,0 +1,277 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+
+/*
+ * Commands
+ */
+
+static bool cmd_if_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool cmd_elsif_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool cmd_if_validate_const
+ (struct sieve_validator *valdtr, struct sieve_command *cmd,
+ int *const_current, int const_next);
+static bool cmd_if_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
+static bool cmd_else_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
+
+/* If command
+ *
+ * Syntax:
+ * if <test1: test> <block1: block>
+ */
+
+const struct sieve_command_def cmd_if = {
+ .identifier = "if",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 1,
+ .block_allowed = TRUE,
+ .block_required = TRUE,
+ .validate = cmd_if_validate,
+ .validate_const = cmd_if_validate_const,
+ .generate = cmd_if_generate
+};
+
+/* ElsIf command
+ *
+ * Santax:
+ * elsif <test2: test> <block2: block>
+ */
+
+const struct sieve_command_def cmd_elsif = {
+ .identifier = "elsif",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 1,
+ .block_allowed = TRUE,
+ .block_required = TRUE,
+ .validate = cmd_elsif_validate,
+ .validate_const = cmd_if_validate_const,
+ .generate = cmd_if_generate
+};
+
+/* Else command
+ *
+ * Syntax:
+ * else <block>
+ */
+
+const struct sieve_command_def cmd_else = {
+ .identifier = "else",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = TRUE,
+ .block_required = TRUE,
+ .validate = cmd_elsif_validate,
+ .validate_const = cmd_if_validate_const,
+ .generate = cmd_else_generate
+};
+
+/*
+ * Context management
+ */
+
+struct cmd_if_context_data {
+ struct cmd_if_context_data *previous;
+ struct cmd_if_context_data *next;
+
+ int const_condition;
+
+ bool jump_generated;
+ sieve_size_t exit_jump;
+};
+
+static void cmd_if_initialize_context_data
+(struct sieve_command *cmd, struct cmd_if_context_data *previous)
+{
+ struct cmd_if_context_data *cmd_data;
+
+ /* Assign context */
+ cmd_data = p_new(sieve_command_pool(cmd), struct cmd_if_context_data, 1);
+ cmd_data->exit_jump = 0;
+ cmd_data->jump_generated = FALSE;
+
+ /* Update linked list of contexts */
+ cmd_data->previous = previous;
+ cmd_data->next = NULL;
+ if ( previous != NULL )
+ previous->next = cmd_data;
+
+ /* Check const status */
+ cmd_data->const_condition = -1;
+ while ( previous != NULL ) {
+ if ( previous->const_condition > 0 ) {
+ cmd_data->const_condition = 0;
+ break;
+ }
+ previous = previous->previous;
+ }
+
+ /* Assign to command context */
+ cmd->data = cmd_data;
+}
+
+/*
+ * Validation
+ */
+
+static bool cmd_if_validate
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *cmd)
+{
+ /* Start if-command structure */
+ cmd_if_initialize_context_data(cmd, NULL);
+
+ return TRUE;
+}
+
+static bool cmd_elsif_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ struct sieve_command *prev;
+
+ i_assert(cmd != NULL);
+ prev = sieve_command_prev(cmd);
+
+ /* Check valid command placement */
+ if ( prev == NULL ||
+ ( !sieve_command_is(prev, cmd_if) && !sieve_command_is(prev, cmd_elsif) ) )
+ {
+ sieve_command_validate_error(valdtr, cmd,
+ "the %s command must follow an if or elseif command",
+ sieve_command_identifier(cmd));
+ return FALSE;
+ }
+
+ /* Previous command in this block is 'if' or 'elsif', so we can safely refer
+ * to its context data
+ */
+ cmd_if_initialize_context_data(cmd, prev->data);
+
+ return TRUE;
+}
+
+static bool cmd_if_validate_const
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *cmd,
+ int *const_current, int const_next)
+{
+ struct cmd_if_context_data *cmd_data =
+ (struct cmd_if_context_data *) cmd->data;
+
+ if ( cmd_data != NULL ) {
+ if ( cmd_data->const_condition == 0 ) {
+ *const_current = cmd_data->const_condition;
+ return FALSE;
+ }
+
+ cmd_data->const_condition = const_next;
+ }
+
+ *const_current = const_next;
+
+ return ( const_next < 0 );
+}
+
+/*
+ * Code generation
+ */
+
+/* The if command does not generate specific IF-ELSIF-ELSE opcodes, but only uses
+ * JMP instructions. This is why the implementation of the if command does not
+ * include an opcode implementation.
+ */
+
+static void cmd_if_resolve_exit_jumps
+(struct sieve_binary_block *sblock, struct cmd_if_context_data *cmd_data)
+{
+ struct cmd_if_context_data *if_ctx = cmd_data->previous;
+
+ /* Iterate backwards through all if-command contexts and resolve the
+ * exit jumps to the current code position.
+ */
+ while ( if_ctx != NULL ) {
+ if ( if_ctx->jump_generated )
+ sieve_binary_resolve_offset(sblock, if_ctx->exit_jump);
+ if_ctx = if_ctx->previous;
+ }
+}
+
+static bool cmd_if_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ struct sieve_binary_block *sblock = cgenv->sblock;
+ struct cmd_if_context_data *cmd_data =
+ (struct cmd_if_context_data *) cmd->data;
+ struct sieve_ast_node *test;
+ struct sieve_jumplist jmplist;
+
+ /* Generate test condition */
+ if ( cmd_data->const_condition < 0 ) {
+ /* Prepare jumplist */
+ sieve_jumplist_init_temp(&jmplist, sblock);
+
+ test = sieve_ast_test_first(cmd->ast_node);
+ if ( !sieve_generate_test(cgenv, test, &jmplist, FALSE) )
+ return FALSE;
+ }
+
+ /* Case true { */
+ if ( cmd_data->const_condition != 0 ) {
+ if ( !sieve_generate_block(cgenv, cmd->ast_node) )
+ return FALSE;
+ }
+
+ /* Are we the final command in this if-elsif-else structure? */
+ if ( cmd_data->next == NULL || cmd_data->const_condition == 1 ) {
+ /* Yes, Resolve previous exit jumps to this point */
+ cmd_if_resolve_exit_jumps(sblock, cmd_data);
+
+ } else if ( cmd_data->const_condition < 0 ) {
+ /* No, generate jump to end of if-elsif-else structure (resolved later)
+ * This of course is not necessary if the {} block contains a command
+ * like stop at top level that unconditionally exits the block already
+ * anyway.
+ */
+ if ( !sieve_command_block_exits_unconditionally(cmd) ) {
+ sieve_operation_emit(sblock, NULL, &sieve_jmp_operation);
+ cmd_data->exit_jump = sieve_binary_emit_offset(sblock, 0);
+ cmd_data->jump_generated = TRUE;
+ }
+ }
+
+ if ( cmd_data->const_condition < 0 ) {
+ /* Case false ... (subsequent elsif/else commands might generate more) */
+ sieve_jumplist_resolve(&jmplist);
+ }
+
+ return TRUE;
+}
+
+static bool cmd_else_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ struct cmd_if_context_data *cmd_data =
+ (struct cmd_if_context_data *) cmd->data;
+
+ /* Else { */
+ if ( cmd_data->const_condition != 0 ) {
+ if ( !sieve_generate_block(cgenv, cmd->ast_node) )
+ return FALSE;
+
+ /* } End: resolve all exit blocks */
+ cmd_if_resolve_exit_jumps(cgenv->sblock, cmd_data);
+ }
+
+ return TRUE;
+}
+
diff --git a/pigeonhole/src/lib-sieve/cmd-keep.c b/pigeonhole/src/lib-sieve/cmd-keep.c
new file mode 100644
index 0000000..b619a80
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/cmd-keep.c
@@ -0,0 +1,113 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-dump.h"
+#include "sieve-message.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-result.h"
+
+/*
+ * Keep command
+ *
+ * Syntax:
+ * keep
+ */
+
+static bool cmd_keep_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
+
+const struct sieve_command_def cmd_keep = {
+ .identifier = "keep",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .generate = cmd_keep_generate
+};
+
+/*
+ * Keep operation
+ */
+
+static bool cmd_keep_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int cmd_keep_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def cmd_keep_operation = {
+ .mnemonic = "KEEP",
+ .code = SIEVE_OPERATION_KEEP,
+ .dump = cmd_keep_operation_dump,
+ .execute = cmd_keep_operation_execute
+};
+
+/*
+ * Code generation
+ */
+
+static bool cmd_keep_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ /* Emit opcode */
+ sieve_operation_emit(cgenv->sblock, NULL, &cmd_keep_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, cmd, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool cmd_keep_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "KEEP");
+ sieve_code_descend(denv);
+
+ return ( sieve_action_opr_optional_dump(denv, address, NULL) == 0 );
+}
+
+/*
+ * Interpretation
+ */
+
+static int cmd_keep_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ struct sieve_side_effects_list *slist = NULL;
+ int ret = 0;
+
+ /*
+ * Read data
+ */
+
+ /* Optional operands (side effects only) */
+ if ( sieve_action_opr_optional_read(renv, address, NULL, &ret, &slist) != 0 )
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS,
+ "keep action; store message in default mailbox");
+
+ /* Add keep action to result.
+ */
+ if ( sieve_result_add_keep(renv, slist) < 0 )
+ return SIEVE_EXEC_FAILURE;
+
+ return SIEVE_EXEC_OK;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/cmd-redirect.c b/pigeonhole/src/lib-sieve/cmd-redirect.c
new file mode 100644
index 0000000..6a3b0a4
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/cmd-redirect.c
@@ -0,0 +1,677 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "str-sanitize.h"
+#include "strfuncs.h"
+#include "istream.h"
+#include "istream-header-filter.h"
+#include "ostream.h"
+#include "mail-storage.h"
+
+#include "rfc2822.h"
+
+#include "sieve-common.h"
+#include "sieve-limits.h"
+#include "sieve-address.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-message.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code-dumper.h"
+#include "sieve-result.h"
+#include "sieve-smtp.h"
+#include "sieve-message.h"
+
+#include <stdio.h>
+
+/*
+ * Redirect command
+ *
+ * Syntax
+ * redirect <address: string>
+ */
+
+static bool
+cmd_redirect_validate(struct sieve_validator *validator,
+ struct sieve_command *cmd);
+static bool
+cmd_redirect_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd);
+
+const struct sieve_command_def cmd_redirect = {
+ .identifier = "redirect",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_redirect_validate,
+ .generate = cmd_redirect_generate
+};
+
+/*
+ * Redirect operation
+ */
+
+static bool
+cmd_redirect_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_redirect_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def cmd_redirect_operation = {
+ .mnemonic = "REDIRECT",
+ .code = SIEVE_OPERATION_REDIRECT,
+ .dump = cmd_redirect_operation_dump,
+ .execute = cmd_redirect_operation_execute
+};
+
+/*
+ * Redirect action
+ */
+
+static bool
+act_redirect_equals(const struct sieve_script_env *senv,
+ const struct sieve_action *act1,
+ const struct sieve_action *act2);
+static int
+act_redirect_check_duplicate(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other);
+static void
+act_redirect_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv, bool *keep);
+
+static int
+act_redirect_start(const struct sieve_action_exec_env *aenv, void **tr_context);
+static int
+act_redirect_execute(const struct sieve_action_exec_env *aenv, void *tr_context,
+ bool *keep);
+static int
+act_redirect_commit(const struct sieve_action_exec_env *aenv, void *tr_context);
+
+const struct sieve_action_def act_redirect = {
+ .name = "redirect",
+ .flags = SIEVE_ACTFLAG_TRIES_DELIVER,
+ .equals = act_redirect_equals,
+ .check_duplicate = act_redirect_check_duplicate,
+ .print = act_redirect_print,
+ .start = act_redirect_start,
+ .execute = act_redirect_execute,
+ .commit = act_redirect_commit,
+};
+
+/*
+ * Validation
+ */
+
+static bool
+cmd_redirect_validate(struct sieve_validator *validator,
+ struct sieve_command *cmd)
+{
+ struct sieve_instance *svinst = sieve_validator_svinst(validator);
+ struct sieve_ast_argument *arg = cmd->first_positional;
+
+ /* Check and activate address argument */
+
+ if (!sieve_validate_positional_argument(validator, cmd, arg, "address",
+ 1, SAAT_STRING))
+ return FALSE;
+
+ if (!sieve_validator_argument_activate(validator, cmd, arg, FALSE))
+ return FALSE;
+
+ /* We can only assess the validity of the outgoing address when it is
+ * a string literal. For runtime-generated strings this needs to be
+ * done at runtime.
+ */
+ if (sieve_argument_is_string_literal(arg)) {
+ string_t *raw_address = sieve_ast_argument_str(arg);
+ const char *error;
+ bool result;
+
+ T_BEGIN {
+ /* Parse the address */
+ result = sieve_address_validate_str(raw_address, &error);
+ if (!result) {
+ sieve_argument_validate_error(
+ validator, arg,
+ "specified redirect address '%s' is invalid: %s",
+ str_sanitize(str_c(raw_address),128),
+ error);
+ }
+ } T_END;
+
+ return result;
+ }
+
+ if (svinst->max_redirects == 0) {
+ sieve_command_validate_error(validator, cmd,
+ "local policy prohibits the use of a redirect action");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+cmd_redirect_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, NULL, &cmd_redirect_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, cmd, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+cmd_redirect_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "REDIRECT");
+ sieve_code_descend(denv);
+
+ if (sieve_action_opr_optional_dump(denv, address, NULL) != 0)
+ return FALSE;
+
+ return sieve_opr_string_dump(denv, address, "address");
+}
+
+/*
+ * Code execution
+ */
+
+static int
+cmd_redirect_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ struct sieve_instance *svinst = eenv->svinst;
+ struct sieve_side_effects_list *slist = NULL;
+ string_t *redirect;
+ const struct smtp_address *to_address;
+ const char *error;
+ int ret;
+
+ /*
+ * Read data
+ */
+
+ /* Optional operands (side effects only) */
+ if (sieve_action_opr_optional_read(renv, address, NULL,
+ &ret, &slist) != 0)
+ return ret;
+
+ /* Read the address */
+ if ((ret = sieve_opr_string_read(renv, address, "address",
+ &redirect)) <= 0)
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ /* Parse the address */
+ to_address = sieve_address_parse_str(redirect, &error);
+ if (to_address == NULL) {
+ sieve_runtime_error(renv, NULL,
+ "specified redirect address '%s' is invalid: %s",
+ str_sanitize(str_c(redirect),128), error);
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ if (svinst->max_redirects == 0) {
+ sieve_runtime_error(renv, NULL,
+ "local policy prohibits the use of a redirect action");
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_ACTIONS)) {
+ sieve_runtime_trace(renv, 0, "redirect action");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(renv, 0, "forward message to address %s",
+ smtp_address_encode_path(to_address));
+ }
+
+ /* Add redirect action to the result */
+
+ return sieve_act_redirect_add_to_result(renv, "redirect", slist,
+ to_address);
+}
+
+/*
+ * Action implementation
+ */
+
+struct act_redirect_transaction {
+ const char *msg_id, *new_msg_id;
+ const char *dupeid;
+
+ bool skip_redirect:1;
+};
+
+static bool
+act_redirect_equals(const struct sieve_script_env *senv ATTR_UNUSED,
+ const struct sieve_action *act1,
+ const struct sieve_action *act2)
+{
+ struct act_redirect_context *rd_ctx1 =
+ (struct act_redirect_context *)act1->context;
+ struct act_redirect_context *rd_ctx2 =
+ (struct act_redirect_context *)act2->context;
+
+ /* Address is already normalized */
+ return (smtp_address_equals(rd_ctx1->to_address, rd_ctx2->to_address));
+}
+
+static int
+act_redirect_check_duplicate(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+
+ return (act_redirect_equals(eenv->scriptenv, act, act_other) ? 1 : 0);
+}
+
+static void
+act_redirect_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv, bool *keep)
+{
+ struct act_redirect_context *ctx =
+ (struct act_redirect_context *)action->context;
+
+ sieve_result_action_printf(rpenv, "redirect message to: %s",
+ smtp_address_encode_path(ctx->to_address));
+ *keep = FALSE;
+}
+
+static int
+act_redirect_send(const struct sieve_action_exec_env *aenv, struct mail *mail,
+ struct act_redirect_context *ctx, const char *new_msg_id)
+ ATTR_NULL(4)
+{
+ static const char *hide_headers[] = { "Return-Path" };
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_instance *svinst = eenv->svinst;
+ struct sieve_message_context *msgctx = aenv->msgctx;
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ struct sieve_address_source env_from = svinst->redirect_from;
+ struct istream *input;
+ struct ostream *output;
+ const struct smtp_address *sender;
+ const char *error;
+ struct sieve_smtp_context *sctx;
+ int ret;
+
+ /* Just to be sure */
+ if (!sieve_smtp_available(senv)) {
+ sieve_result_global_warning(aenv, "no means to send mail");
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ if (mail_get_stream(mail, NULL, NULL, &input) < 0) {
+ return sieve_result_mail_error(aenv, mail,
+ "failed to read input message");
+ }
+
+ /* Determine which sender to use
+
+ From RFC 5228, Section 4.2:
+
+ The envelope sender address on the outgoing message is chosen by the
+ sieve implementation. It MAY be copied from the message being
+ processed. However, if the message being processed has an empty
+ envelope sender address the outgoing message MUST also have an empty
+ envelope sender address. This last requirement is imposed to prevent
+ loops in the case where a message is redirected to an invalid address
+ when then returns a delivery status notification that also ends up
+ being redirected to the same invalid address.
+ */
+ if ((eenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0) {
+ /* Envelope available */
+ sender = sieve_message_get_sender(msgctx);
+ if (sender != NULL &&
+ sieve_address_source_get_address(&env_from, svinst, senv,
+ msgctx, eenv->flags,
+ &sender) < 0)
+ sender = NULL;
+ } else {
+ /* No envelope available */
+ ret = sieve_address_source_get_address(&env_from, svinst, senv,
+ msgctx, eenv->flags,
+ &sender);
+ if (ret < 0)
+ sender = NULL;
+ else if (ret == 0)
+ sender = svinst->user_email;
+ }
+
+ /* Open SMTP transport */
+ sctx = sieve_smtp_start_single(senv, ctx->to_address, sender, &output);
+
+ /* Remove unwanted headers */
+ input = i_stream_create_header_filter(
+ input, HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR,
+ hide_headers, N_ELEMENTS(hide_headers),
+ *null_header_filter_callback, (void *)NULL);
+
+ T_BEGIN {
+ string_t *hdr = t_str_new(256);
+ const struct smtp_address *user_email;
+
+ /* Prepend sieve headers (should not affect signatures) */
+ rfc2822_header_append(hdr, "X-Sieve", SIEVE_IMPLEMENTATION,
+ FALSE, NULL);
+ if (svinst->user_email == NULL &&
+ (eenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0)
+ user_email = sieve_message_get_final_recipient(msgctx);
+ else
+ user_email = sieve_get_user_email(svinst);
+ if (user_email != NULL) {
+ rfc2822_header_append(hdr, "X-Sieve-Redirected-From",
+ smtp_address_encode(user_email),
+ FALSE, NULL);
+ }
+
+ /* Add new Message-ID if message doesn't have one */
+ if (new_msg_id != NULL)
+ rfc2822_header_write(hdr, "Message-ID", new_msg_id);
+
+ o_stream_nsend(output, str_data(hdr), str_len(hdr));
+ } T_END;
+
+ o_stream_nsend_istream(output, input);
+
+ if (input->stream_errno != 0) {
+ sieve_result_critical(aenv, "failed to read input message",
+ "read(%s) failed: %s",
+ i_stream_get_name(input),
+ i_stream_get_error(input));
+ i_stream_unref(&input);
+ sieve_smtp_abort(sctx);
+ return SIEVE_EXEC_TEMP_FAILURE;
+ }
+ i_stream_unref(&input);
+
+ /* Close SMTP transport */
+ if ((ret = sieve_smtp_finish(sctx, &error)) <= 0) {
+ if (ret < 0) {
+ sieve_result_global_error(
+ aenv, "failed to redirect message to <%s>: %s "
+ "(temporary failure)",
+ smtp_address_encode(ctx->to_address),
+ str_sanitize(error, 512));
+ return SIEVE_EXEC_TEMP_FAILURE;
+ }
+
+ sieve_result_global_log_error(
+ aenv, "failed to redirect message to <%s>: %s "
+ "(permanent failure)",
+ smtp_address_encode(ctx->to_address),
+ str_sanitize(error, 512));
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+static int
+act_redirect_get_duplicate_id(struct act_redirect_context *ctx,
+ const struct sieve_action_exec_env *aenv,
+ const char *msg_id, const char **dupeid_r)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_message_context *msgctx = aenv->msgctx;
+ const struct sieve_message_data *msgdata = eenv->msgdata;
+ struct mail *mail = msgdata->mail;
+ const struct smtp_address *recipient;
+ const char *resent_id = NULL, *list_id = NULL;
+
+ /* Read identifying headers */
+ if (mail_get_first_header(mail, "resent-message-id", &resent_id) < 0) {
+ return sieve_result_mail_error(
+ aenv, mail,
+ "failed to read header field `resent-message-id'");
+ }
+ if (resent_id == NULL &&
+ mail_get_first_header(mail, "resent-from", &resent_id) < 0) {
+ return sieve_result_mail_error(
+ aenv, mail,
+ "failed to read header field `resent-from'");
+ }
+ if (mail_get_first_header(mail, "list-id", &list_id) < 0) {
+ return sieve_result_mail_error(
+ aenv, mail,
+ "failed to read header field `list-id'");
+ }
+
+ if ((eenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0)
+ recipient = sieve_message_get_orig_recipient(msgctx);
+ else
+ recipient = sieve_get_user_email(eenv->svinst);
+
+ pool_t pool = sieve_result_pool(aenv->result);
+
+ /* Base the duplicate ID on:
+ - the message id
+ - the recipient running this Sieve script
+ - redirect target address
+ - if this message is resent: the message-id or from-address of
+ the original message
+ - if the message came through a mailing list: the mailinglist ID
+ */
+ *dupeid_r = p_strdup_printf(
+ pool, "%s-%s-%s-%s-%s", msg_id,
+ (recipient != NULL ? smtp_address_encode(recipient) : ""),
+ smtp_address_encode(ctx->to_address),
+ (resent_id != NULL ? resent_id : ""),
+ (list_id != NULL ? list_id : ""));
+ return SIEVE_EXEC_OK;
+}
+
+static int
+act_redirect_check_loop_header(const struct sieve_action_exec_env *aenv,
+ struct mail *mail, bool *loop_detected_r)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_message_context *msgctx = aenv->msgctx;
+ const char *const *headers;
+ const char *recipient, *user_email;
+ const struct smtp_address *addr;
+ int ret;
+
+ *loop_detected_r = FALSE;
+
+ ret = mail_get_headers(mail, "x-sieve-redirected-from", &headers);
+ if (ret < 0) {
+ return sieve_result_mail_error(
+ aenv, mail, "failed to read header field "
+ "`x-sieve-redirected-from'");
+ }
+
+ if (ret == 0)
+ return SIEVE_EXEC_OK;
+
+ recipient = user_email = NULL;
+ if ((eenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0) {
+ addr = sieve_message_get_final_recipient(msgctx);
+ if (addr != NULL)
+ recipient = smtp_address_encode(addr);
+ }
+ addr = sieve_get_user_email(eenv->svinst);
+ if (addr != NULL)
+ user_email = smtp_address_encode(addr);
+
+ while (*headers != NULL) {
+ const char *header = t_str_trim(*headers, " \t\r\n");
+ if (recipient != NULL && strcmp(header, recipient) == 0) {
+ *loop_detected_r = TRUE;
+ break;
+ }
+ if (user_email != NULL && strcmp(header, user_email) == 0) {
+ *loop_detected_r = TRUE;
+ break;
+ }
+ headers++;
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+static int
+act_redirect_start(const struct sieve_action_exec_env *aenv, void **tr_context)
+{
+ struct act_redirect_transaction *trans;
+ pool_t pool = sieve_result_pool(aenv->result);
+
+ /* Create transaction context */
+ trans = p_new(pool, struct act_redirect_transaction, 1);
+ *tr_context = trans;
+
+ return SIEVE_EXEC_OK;
+}
+
+static int
+act_redirect_execute(const struct sieve_action_exec_env *aenv,
+ void *tr_context, bool *keep)
+{
+ const struct sieve_action *action = aenv->action;
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_instance *svinst = eenv->svinst;
+ struct act_redirect_context *ctx =
+ (struct act_redirect_context *)action->context;
+ struct act_redirect_transaction *trans = tr_context;
+ struct sieve_message_context *msgctx = aenv->msgctx;
+ struct mail *mail = (action->mail != NULL ?
+ action->mail : sieve_message_get_mail(msgctx));
+ const struct sieve_message_data *msgdata = eenv->msgdata;
+ bool duplicate, loop_detected = FALSE;
+ int ret;
+
+ /*
+ * Prevent mail loops
+ */
+
+ /* Create Message-ID for the message if it has none */
+ trans->msg_id = msgdata->id;
+ if (trans->msg_id == NULL) {
+ pool_t pool = sieve_result_pool(aenv->result);
+ const char *msg_id;
+ if (mail_get_message_id_no_validation(msgdata->mail, &msg_id) > 0)
+ trans->msg_id = p_strdup(pool, msg_id);
+ else {
+ msg_id = sieve_message_get_new_id(svinst);
+ trans->msg_id = trans->new_msg_id = p_strdup(pool, msg_id);
+ }
+ }
+
+ /* Create ID for duplicate database lookup */
+ ret = act_redirect_get_duplicate_id(ctx, aenv, trans->msg_id,
+ &trans->dupeid);
+ if (ret != SIEVE_EXEC_OK)
+ return ret;
+ i_assert(trans->dupeid != NULL);
+
+ /* Check whether we've seen this message before */
+ ret = sieve_action_duplicate_check(aenv, trans->dupeid,
+ strlen(trans->dupeid),
+ &duplicate);
+ if (ret < SIEVE_EXEC_OK) {
+ sieve_result_critical(
+ aenv, "failed to check for duplicate forward",
+ "failed to check for duplicate forward to <%s>%s",
+ smtp_address_encode(ctx->to_address),
+ (ret == SIEVE_EXEC_TEMP_FAILURE ?
+ " (temporaty failure)" : ""));
+ return ret;
+ }
+ if (duplicate) {
+ sieve_result_global_log(
+ aenv, "discarded duplicate forward to <%s>",
+ smtp_address_encode(ctx->to_address));
+ trans->skip_redirect = TRUE;
+ return SIEVE_EXEC_OK;
+ }
+
+ /* Check whether we've seen this message before based on added headers
+ */
+ ret = act_redirect_check_loop_header(aenv, mail, &loop_detected);
+ if (ret != SIEVE_EXEC_OK)
+ return ret;
+ if (loop_detected) {
+ sieve_result_global_log(
+ aenv, "not forwarding message to <%s>: "
+ "the `x-sieve-redirected-from' header indicates a mail loop",
+ smtp_address_encode(ctx->to_address));
+ trans->skip_redirect = TRUE;
+ return SIEVE_EXEC_OK;
+ }
+
+ /* Cancel implicit keep */
+ *keep = FALSE;
+
+ return SIEVE_EXEC_OK;
+}
+
+static int
+act_redirect_commit(const struct sieve_action_exec_env *aenv, void *tr_context)
+{
+ const struct sieve_action *action = aenv->action;
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_instance *svinst = eenv->svinst;
+ struct act_redirect_context *ctx =
+ (struct act_redirect_context *)action->context;
+ struct sieve_message_context *msgctx = aenv->msgctx;
+ struct mail *mail = (action->mail != NULL ?
+ action->mail : sieve_message_get_mail(msgctx));
+ struct act_redirect_transaction *trans = tr_context;
+ int ret;
+
+ if (trans->skip_redirect)
+ return SIEVE_EXEC_OK;
+
+ /*
+ * Try to forward the message
+ */
+
+ ret = act_redirect_send(aenv, mail, ctx, trans->new_msg_id);
+ if (ret == SIEVE_EXEC_OK) {
+ /* Mark this message id as forwarded to the specified
+ destination */
+ sieve_action_duplicate_mark(
+ aenv, trans->dupeid, strlen(trans->dupeid),
+ ioloop_time + svinst->redirect_duplicate_period);
+
+ eenv->exec_status->significant_action_executed = TRUE;
+
+ struct event_passthrough *e =
+ sieve_action_create_finish_event(aenv)->
+ add_str("redirect_target",
+ smtp_address_encode(ctx->to_address));
+
+ sieve_result_event_log(aenv, e->event(),
+ "forwarded to <%s>",
+ smtp_address_encode(ctx->to_address));
+
+ /* Indicate that message was successfully forwarded */
+ eenv->exec_status->message_forwarded = TRUE;
+
+ return SIEVE_EXEC_OK;
+ }
+
+ return ret;
+}
diff --git a/pigeonhole/src/lib-sieve/cmd-require.c b/pigeonhole/src/lib-sieve/cmd-require.c
new file mode 100644
index 0000000..93a2a26
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/cmd-require.c
@@ -0,0 +1,86 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-extensions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+
+/*
+ * Require command
+ *
+ * Syntax
+ * Syntax: require <capabilities: string-list>
+ */
+
+static bool cmd_require_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+
+const struct sieve_command_def cmd_require = {
+ .identifier = "require",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_require_validate
+};
+
+/*
+ * Validation
+ */
+
+static bool cmd_require_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ bool result = TRUE;
+ struct sieve_ast_argument *arg;
+ struct sieve_command *prev = sieve_command_prev(cmd);
+
+ /* Check valid command placement */
+ if ( !sieve_command_is_toplevel(cmd) ||
+ ( !sieve_command_is_first(cmd) && prev != NULL &&
+ !sieve_command_is(prev, cmd_require) ) )
+ {
+ sieve_command_validate_error(valdtr, cmd,
+ "require commands can only be placed at top level "
+ "at the beginning of the file");
+ return FALSE;
+ }
+
+ /* Check argument and load specified extension(s) */
+
+ arg = cmd->first_positional;
+ if ( sieve_ast_argument_type(arg) == SAAT_STRING ) {
+ /* Single string */
+ const struct sieve_extension *ext = sieve_validator_extension_load_by_name
+ (valdtr, cmd, arg, sieve_ast_argument_strc(arg));
+
+ if ( ext == NULL ) result = FALSE;
+
+ } else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) {
+ /* String list */
+ struct sieve_ast_argument *stritem = sieve_ast_strlist_first(arg);
+
+ while ( stritem != NULL ) {
+ const struct sieve_extension *ext = sieve_validator_extension_load_by_name
+ (valdtr, cmd, stritem, sieve_ast_strlist_strc(stritem));
+
+ if ( ext == NULL ) result = FALSE;
+
+ stritem = sieve_ast_strlist_next(stritem);
+ }
+ } else {
+ /* Something else */
+ sieve_argument_validate_error(valdtr, arg,
+ "the require command accepts a single string or string list argument, "
+ "but %s was found",
+ sieve_ast_argument_name(arg));
+ return FALSE;
+ }
+
+ return result;
+}
diff --git a/pigeonhole/src/lib-sieve/cmd-stop.c b/pigeonhole/src/lib-sieve/cmd-stop.c
new file mode 100644
index 0000000..23acadb
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/cmd-stop.c
@@ -0,0 +1,86 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+/*
+ * Stop command
+ *
+ * Syntax
+ * stop
+ */
+
+static bool cmd_stop_generate
+ (const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx ATTR_UNUSED);
+static bool cmd_stop_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+
+const struct sieve_command_def cmd_stop = {
+ .identifier = "stop",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_stop_validate,
+ .generate = cmd_stop_generate
+};
+
+/*
+ * Stop operation
+ */
+
+static int opc_stop_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def cmd_stop_operation = {
+ .mnemonic = "STOP",
+ .code = SIEVE_OPERATION_STOP,
+ .execute = opc_stop_execute
+};
+
+/*
+ * Command validation
+ */
+
+static bool cmd_stop_validate
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *cmd)
+{
+ sieve_command_exit_block_unconditionally(cmd);
+
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool cmd_stop_generate
+(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ sieve_operation_emit(cgenv->sblock, NULL, &cmd_stop_operation);
+
+ return TRUE;
+}
+
+/*
+ * Code execution
+ */
+
+static int opc_stop_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address ATTR_UNUSED)
+{
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
+ "stop command; end all script execution");
+
+ sieve_interpreter_interrupt(renv->interp);
+
+ return SIEVE_EXEC_OK;
+}
+
diff --git a/pigeonhole/src/lib-sieve/cmp-i-ascii-casemap.c b/pigeonhole/src/lib-sieve/cmp-i-ascii-casemap.c
new file mode 100644
index 0000000..4f0dab4
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/cmp-i-ascii-casemap.c
@@ -0,0 +1,99 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Comparator 'i;ascii-casemap':
+ *
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-comparators.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+/*
+ * Forward declarations
+ */
+
+static int cmp_i_ascii_casemap_compare
+ (const struct sieve_comparator *cmp,
+ const char *val1, size_t val1_size, const char *val2, size_t val2_size);
+static bool cmp_i_ascii_casemap_char_match
+ (const struct sieve_comparator *cmp, const char **val1, const char *val1_end,
+ const char **val2, const char *val2_end);
+
+/*
+ * Comparator object
+ */
+
+const struct sieve_comparator_def i_ascii_casemap_comparator = {
+ SIEVE_OBJECT("i;ascii-casemap",
+ &comparator_operand, SIEVE_COMPARATOR_I_ASCII_CASEMAP),
+ .flags =
+ SIEVE_COMPARATOR_FLAG_ORDERING |
+ SIEVE_COMPARATOR_FLAG_EQUALITY |
+ SIEVE_COMPARATOR_FLAG_SUBSTRING_MATCH |
+ SIEVE_COMPARATOR_FLAG_PREFIX_MATCH,
+ .compare = cmp_i_ascii_casemap_compare,
+ .char_match = cmp_i_ascii_casemap_char_match,
+ .char_skip = sieve_comparator_octet_skip
+};
+
+/*
+ * Comparator implementation
+ */
+
+static int cmp_i_ascii_casemap_compare(
+ const struct sieve_comparator *cmp ATTR_UNUSED,
+ const char *val1, size_t val1_size, const char *val2, size_t val2_size)
+{
+ int result;
+
+ if ( val1_size == val2_size ) {
+ return strncasecmp(val1, val2, val1_size);
+ }
+
+ if ( val1_size > val2_size ) {
+ result = strncasecmp(val1, val2, val2_size);
+
+ if ( result == 0 ) return 1;
+
+ return result;
+ }
+
+ result = strncasecmp(val1, val2, val1_size);
+
+ if ( result == 0 ) return -1;
+
+ return result;
+}
+
+static bool cmp_i_ascii_casemap_char_match
+ (const struct sieve_comparator *cmp ATTR_UNUSED,
+ const char **val, const char *val_end,
+ const char **key, const char *key_end)
+{
+ const char *val_begin = *val;
+ const char *key_begin = *key;
+
+ while ( i_tolower(**val) == i_tolower(**key) &&
+ *val < val_end && *key < key_end ) {
+ (*val)++;
+ (*key)++;
+ }
+
+ if ( *key < key_end ) {
+ /* Reset */
+ *val = val_begin;
+ *key = key_begin;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/cmp-i-octet.c b/pigeonhole/src/lib-sieve/cmp-i-octet.c
new file mode 100644
index 0000000..caa46fa
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/cmp-i-octet.c
@@ -0,0 +1,97 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Comparator 'i;octet':
+ *
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-comparators.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * Forward declarations
+ */
+
+static int cmp_i_octet_compare
+ (const struct sieve_comparator *cmp,
+ const char *val1, size_t val1_size, const char *val2, size_t val2_size);
+static bool cmp_i_octet_char_match
+ (const struct sieve_comparator *cmp, const char **val1, const char *val1_end,
+ const char **val2, const char *val2_end);
+
+/*
+ * Comparator object
+ */
+
+const struct sieve_comparator_def i_octet_comparator = {
+ SIEVE_OBJECT("i;octet",
+ &comparator_operand, SIEVE_COMPARATOR_I_OCTET),
+ .flags =
+ SIEVE_COMPARATOR_FLAG_ORDERING |
+ SIEVE_COMPARATOR_FLAG_EQUALITY |
+ SIEVE_COMPARATOR_FLAG_SUBSTRING_MATCH |
+ SIEVE_COMPARATOR_FLAG_PREFIX_MATCH,
+ .compare = cmp_i_octet_compare,
+ .char_match = cmp_i_octet_char_match,
+ .char_skip = sieve_comparator_octet_skip
+};
+
+/*
+ * Comparator implementation
+ */
+
+static int cmp_i_octet_compare(
+ const struct sieve_comparator *cmp ATTR_UNUSED,
+ const char *val1, size_t val1_size, const char *val2, size_t val2_size)
+{
+ int result;
+
+ if ( val1_size == val2_size ) {
+ return memcmp((void *) val1, (void *) val2, val1_size);
+ }
+
+ if ( val1_size > val2_size ) {
+ result = memcmp((void *) val1, (void *) val2, val2_size);
+
+ if ( result == 0 ) return 1;
+
+ return result;
+ }
+
+ result = memcmp((void *) val1, (void *) val2, val1_size);
+
+ if ( result == 0 ) return -1;
+
+ return result;
+}
+
+static bool cmp_i_octet_char_match
+ (const struct sieve_comparator *cmp ATTR_UNUSED,
+ const char **val, const char *val_end,
+ const char **key, const char *key_end)
+{
+ const char *val_begin = *val;
+ const char *key_begin = *key;
+
+ while ( **val == **key && *val < val_end && *key < key_end ) {
+ (*val)++;
+ (*key)++;
+ }
+
+ if ( *key < key_end ) {
+ /* Reset */
+ *val = val_begin;
+ *key = key_begin;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/ext-encoded-character.c b/pigeonhole/src/lib-sieve/ext-encoded-character.c
new file mode 100644
index 0000000..d9e2b18
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/ext-encoded-character.c
@@ -0,0 +1,271 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension encoded-character
+ * ---------------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5228
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "lib.h"
+#include "unichar.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+
+#include <ctype.h>
+
+/*
+ * Extension
+ */
+
+static bool ext_encoded_character_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def encoded_character_extension = {
+ .name = "encoded-character",
+ .validator_load = ext_encoded_character_validator_load,
+};
+
+/*
+ * Encoded string argument
+ */
+
+bool arg_encoded_string_validate
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *context);
+
+const struct sieve_argument_def encoded_string_argument = {
+ .identifier = "@encoded-string",
+ .validate = arg_encoded_string_validate
+};
+
+/* Parsing */
+
+static bool _skip_whitespace
+ (const char **in, const char *inend)
+{
+ while ( *in < inend ) {
+ if ( **in == '\r' ) {
+ (*in)++;
+ if ( **in != '\n' )
+ return FALSE;
+ continue;
+ }
+
+ /* (Loose LF is non-standard) */
+ if ( **in != ' ' && **in != '\n' && **in != '\t' )
+ break;
+
+ (*in)++;
+ }
+
+ return TRUE;
+}
+
+static bool _parse_hexint
+(const char **in, const char *inend, int max_digits, unsigned int *result)
+{
+ int digit = 0;
+ *result = 0;
+
+ while ( *in < inend && (max_digits == 0 || digit < max_digits) ) {
+
+ if ( (**in) >= '0' && (**in) <= '9' )
+ *result = ((*result) << 4) + (**in) - ((unsigned int) '0');
+ else if ( (**in) >= 'a' && (**in) <= 'f' )
+ *result = ((*result) << 4) + (**in) - ((unsigned int) 'a') + 0x0a;
+ else if ( (**in) >= 'A' && (**in) <= 'F' )
+ *result = ((*result) << 4) + (**in) - ((unsigned int) 'A') + 0x0a;
+ else
+ return ( digit > 0 );
+
+ (*in)++;
+ digit++;
+ }
+
+ if ( digit == max_digits ) {
+ /* Hex digit _MUST_ end here */
+ if ( (**in >= '0' && **in <= '9') || (**in >= 'a' && **in <= 'f') ||
+ (**in >= 'A' && **in <= 'F') )
+ return FALSE;
+
+ return TRUE;
+ }
+
+ return ( digit > 0 );
+}
+
+static bool _decode_hex
+(const char **in, const char *inend, string_t *result)
+{
+ int values = 0;
+
+ while ( *in < inend ) {
+ unsigned int hexpair;
+
+ if ( !_skip_whitespace(in, inend) ) return FALSE;
+
+ if ( !_parse_hexint(in, inend, 2, &hexpair) ) break;
+
+ str_append_c(result, (unsigned char) hexpair);
+ values++;
+ }
+
+ return ( values > 0 );
+}
+
+static bool _decode_unicode
+(const char **in, const char *inend, string_t *result,
+ unsigned int *error_hex)
+{
+ int values = 0;
+ bool valid = TRUE;
+
+ while ( *in < inend ) {
+ unsigned int unicode_hex;
+
+ if ( !_skip_whitespace(in, inend) ) return FALSE;
+
+ if ( !_parse_hexint(in, inend, 0, &unicode_hex) ) break;
+
+ if ( uni_is_valid_ucs4((unichar_t) unicode_hex) )
+ uni_ucs4_to_utf8_c((unichar_t) unicode_hex, result);
+ else {
+ if ( valid ) *error_hex = unicode_hex;
+ valid = FALSE;
+ }
+ values++;
+ }
+
+ return ( values > 0 );
+}
+
+bool arg_encoded_string_validate
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ bool result = TRUE;
+ enum { ST_NONE, ST_OPEN, ST_TYPE, ST_CLOSE }
+ state = ST_NONE;
+ string_t *str = sieve_ast_argument_str(*arg);
+ string_t *tmpstr, *newstr = NULL;
+ const char *p, *mark, *strstart, *substart = NULL;
+ const char *strval = (const char *) str_data(str);
+ const char *strend = strval + str_len(str);
+ unsigned int error_hex = 0;
+
+ T_BEGIN {
+ tmpstr = t_str_new(32);
+
+ p = strval;
+ strstart = p;
+ while ( result && p < strend ) {
+ switch ( state ) {
+ /* Normal string */
+ case ST_NONE:
+ if ( *p == '$' ) {
+ substart = p;
+ state = ST_OPEN;
+ }
+ p++;
+ break;
+ /* Parsed '$' */
+ case ST_OPEN:
+ if ( *p == '{' ) {
+ state = ST_TYPE;
+ p++;
+ } else
+ state = ST_NONE;
+ break;
+ /* Parsed '${' */
+ case ST_TYPE:
+ mark = p;
+ /* Scan for 'hex' or 'unicode' */
+ while ( p < strend && i_isalpha(*p) ) p++;
+
+ if ( *p != ':' ) {
+ state = ST_NONE;
+ break;
+ }
+
+ state = ST_CLOSE;
+
+ str_truncate(tmpstr, 0);
+ if ( strncasecmp(mark, "hex", p - mark) == 0 ) {
+ /* Hexadecimal */
+ p++;
+ if ( !_decode_hex(&p, strend, tmpstr) )
+ state = ST_NONE;
+ } else if ( strncasecmp(mark, "unicode", p - mark) == 0 ) {
+ /* Unicode */
+ p++;
+ if ( !_decode_unicode(&p, strend, tmpstr, &error_hex) )
+ state = ST_NONE;
+ } else {
+ /* Invalid encoding */
+ p++;
+ state = ST_NONE;
+ }
+ break;
+ case ST_CLOSE:
+ if ( *p == '}' ) {
+ /* We now know that the substitution is valid */
+
+ if ( error_hex != 0 ) {
+ sieve_argument_validate_error(valdtr, *arg,
+ "invalid unicode character 0x%08x in encoded character substitution",
+ error_hex);
+ result = FALSE;
+ break;
+ }
+
+ if ( newstr == NULL ) {
+ newstr = str_new(sieve_ast_pool((*arg)->ast), str_len(str)*2);
+ }
+
+ str_append_data(newstr, strstart, substart-strstart);
+ str_append_str(newstr, tmpstr);
+
+ strstart = p + 1;
+ substart = strstart;
+
+ p++;
+ }
+ state = ST_NONE;
+ }
+ }
+ } T_END;
+
+ if ( !result ) return FALSE;
+
+ if ( newstr != NULL ) {
+ if ( strstart != strend )
+ str_append_data(newstr, strstart, strend-strstart);
+
+ sieve_ast_argument_string_set(*arg, newstr);
+ }
+
+ /* Pass the processed string to a (possible) next layer of processing */
+ return sieve_validator_argument_activate_super
+ (valdtr, cmd, *arg, TRUE);
+}
+
+/*
+ * Extension implementation
+ */
+
+static bool ext_encoded_character_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Override the constant string argument with our own */
+ sieve_validator_argument_override
+ (valdtr, SAT_CONST_STRING, ext, &encoded_string_argument);
+
+ return TRUE;
+}
diff --git a/pigeonhole/src/lib-sieve/ext-envelope.c b/pigeonhole/src/lib-sieve/ext-envelope.c
new file mode 100644
index 0000000..e889cff
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/ext-envelope.c
@@ -0,0 +1,732 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension envelope
+ * ------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5228
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-address.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-address-parts.h"
+#include "sieve-message.h"
+
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-match.h"
+
+/*
+ * Forward declarations
+ */
+
+static const struct sieve_command_def envelope_test;
+const struct sieve_operation_def envelope_operation;
+const struct sieve_extension_def envelope_extension;
+
+/*
+ * Extension
+ */
+
+static bool
+ext_envelope_validator_load(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr);
+static bool
+ext_envelope_interpreter_load(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+static bool
+ext_envelope_validator_validate(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context,
+ struct sieve_ast_argument *require_arg,
+ bool required);
+static int
+ext_envelope_interpreter_run(const struct sieve_extension *this_ext,
+ const struct sieve_runtime_env *renv,
+ void *context, bool deferred);
+
+const struct sieve_extension_def envelope_extension = {
+ .name = "envelope",
+ .interpreter_load = ext_envelope_interpreter_load,
+ .validator_load = ext_envelope_validator_load,
+ SIEVE_EXT_DEFINE_OPERATION(envelope_operation)
+};
+const struct sieve_validator_extension
+envelope_validator_extension = {
+ .ext = &envelope_extension,
+ .validate = ext_envelope_validator_validate
+};
+const struct sieve_interpreter_extension
+envelope_interpreter_extension = {
+ .ext_def = &envelope_extension,
+ .run = ext_envelope_interpreter_run
+};
+
+static bool
+ext_envelope_validator_load(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr)
+{
+ /* Register new test */
+ sieve_validator_register_command(valdtr, ext, &envelope_test);
+
+ sieve_validator_extension_register(valdtr, ext,
+ &envelope_validator_extension, NULL);
+ return TRUE;
+}
+
+static bool
+ext_envelope_interpreter_load(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ sieve_interpreter_extension_register(renv->interp, ext,
+ &envelope_interpreter_extension,
+ NULL);
+ return TRUE;
+}
+
+static bool
+ext_envelope_validator_validate(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr,
+ void *context ATTR_UNUSED,
+ struct sieve_ast_argument *require_arg,
+ bool required)
+{
+ if (required) {
+ enum sieve_compile_flags flags =
+ sieve_validator_compile_flags(valdtr);
+
+ if ((flags & SIEVE_COMPILE_FLAG_NO_ENVELOPE) != 0) {
+ sieve_argument_validate_error(
+ valdtr, require_arg,
+ "the %s extension cannot be used in this context "
+ "(needs access to message envelope)",
+ sieve_extension_name(ext));
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static int
+ext_envelope_interpreter_run(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ void *context ATTR_UNUSED, bool deferred)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+
+ if ((eenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) != 0) {
+ if (!deferred) {
+ sieve_runtime_error(
+ renv, NULL,
+ "the %s extension cannot be used in this context "
+ "(needs access to message envelope)",
+ sieve_extension_name(ext));
+ }
+ return SIEVE_EXEC_FAILURE;
+ }
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Envelope test
+ *
+ * Syntax
+ * envelope [COMPARATOR] [ADDRESS-PART] [MATCH-TYPE]
+ * <envelope-part: string-list> <key-list: string-list>
+ */
+
+static bool
+tst_envelope_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool
+tst_envelope_validate(struct sieve_validator *valdtr,
+ struct sieve_command *tst);
+static bool
+tst_envelope_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+static const struct sieve_command_def envelope_test = {
+ .identifier = "envelope",
+ .type = SCT_TEST,
+ .positional_args= 2,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_envelope_registered,
+ .validate = tst_envelope_validate,
+ .generate = tst_envelope_generate
+};
+
+/*
+ * Envelope operation
+ */
+
+static bool
+ext_envelope_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+ext_envelope_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def envelope_operation = {
+ .mnemonic = "ENVELOPE",
+ .ext_def = &envelope_extension,
+ .dump = ext_envelope_operation_dump,
+ .execute = ext_envelope_operation_execute
+};
+
+/*
+ * Envelope parts
+ *
+ * FIXME: not available to extensions
+ */
+
+struct sieve_envelope_part {
+ const char *identifier;
+
+ const struct smtp_address *const *(*get_addresses)
+ (const struct sieve_runtime_env *renv);
+ const char * const *(*get_values)
+ (const struct sieve_runtime_env *renv);
+};
+
+static const struct smtp_address *const *
+_from_part_get_addresses(const struct sieve_runtime_env *renv);
+static const char *const *
+_from_part_get_values(const struct sieve_runtime_env *renv);
+static const struct smtp_address *const *
+_to_part_get_addresses(const struct sieve_runtime_env *renv);
+static const char *const *
+_to_part_get_values(const struct sieve_runtime_env *renv);
+static const char *const *
+_auth_part_get_values(const struct sieve_runtime_env *renv);
+
+static const struct sieve_envelope_part _from_part = {
+ "from",
+ _from_part_get_addresses,
+ _from_part_get_values,
+};
+
+static const struct sieve_envelope_part _to_part = {
+ "to",
+ _to_part_get_addresses,
+ _to_part_get_values,
+};
+
+static const struct sieve_envelope_part _auth_part = {
+ "auth",
+ NULL,
+ _auth_part_get_values,
+};
+
+static const struct sieve_envelope_part *_envelope_parts[] = {
+ /* Required */
+ &_from_part, &_to_part,
+
+ /* Non-standard */
+ &_auth_part
+};
+
+static unsigned int _envelope_part_count = N_ELEMENTS(_envelope_parts);
+
+static const struct sieve_envelope_part *
+_envelope_part_find(const char *identifier)
+{
+ unsigned int i;
+
+ for (i = 0; i < _envelope_part_count; i++) {
+ if (strcasecmp(_envelope_parts[i]->identifier,
+ identifier) == 0)
+ return _envelope_parts[i];
+ }
+
+ return NULL;
+}
+
+/* Envelope parts implementation */
+
+static const struct smtp_address *const *
+_from_part_get_addresses(const struct sieve_runtime_env *renv)
+{
+ ARRAY(const struct smtp_address *) envelope_values;
+ const struct smtp_address *address =
+ sieve_message_get_sender(renv->msgctx);
+
+ t_array_init(&envelope_values, 2);
+
+ if (address == NULL)
+ address = smtp_address_create_temp(NULL, NULL);
+ array_append(&envelope_values, &address, 1);
+
+ (void)array_append_space(&envelope_values);
+ return array_idx(&envelope_values, 0);
+}
+
+static const char *const *
+_from_part_get_values(const struct sieve_runtime_env *renv)
+{
+ ARRAY(const char *)envelope_values;
+ const struct smtp_address *address =
+ sieve_message_get_sender(renv->msgctx);
+ const char *value;
+
+ t_array_init(&envelope_values, 2);
+
+ value = "";
+ if (!smtp_address_isnull(address))
+ value = smtp_address_encode(address);
+ array_append(&envelope_values, &value, 1);
+
+ (void)array_append_space(&envelope_values);
+
+ return array_idx(&envelope_values, 0);
+}
+
+static const struct smtp_address *const *
+_to_part_get_addresses(const struct sieve_runtime_env *renv)
+{
+ ARRAY(const struct smtp_address *) envelope_values;
+ const struct smtp_address *address =
+ sieve_message_get_orig_recipient(renv->msgctx);
+
+ if (address != NULL && address->localpart != NULL) {
+ t_array_init(&envelope_values, 2);
+
+ array_append(&envelope_values, &address, 1);
+
+ (void)array_append_space(&envelope_values);
+ return array_idx(&envelope_values, 0);
+ }
+ return NULL;
+}
+
+static const char *const *
+_to_part_get_values(const struct sieve_runtime_env *renv)
+{
+ ARRAY(const char *) envelope_values;
+ const struct smtp_address *address =
+ sieve_message_get_orig_recipient(renv->msgctx);
+
+ t_array_init(&envelope_values, 2);
+
+ if (address != NULL && address->localpart != NULL) {
+ const char *value = smtp_address_encode(address);
+ array_append(&envelope_values, &value, 1);
+ }
+
+ (void)array_append_space(&envelope_values);
+
+ return array_idx(&envelope_values, 0);
+}
+
+static const char *const *
+_auth_part_get_values(const struct sieve_runtime_env *renv)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ ARRAY(const char *) envelope_values;
+
+ t_array_init(&envelope_values, 2);
+
+ if (eenv->msgdata->auth_user != NULL)
+ array_append(&envelope_values, &eenv->msgdata->auth_user, 1);
+
+ (void)array_append_space(&envelope_values);
+
+ return array_idx(&envelope_values, 0);
+}
+
+/*
+ * Envelope address list
+ */
+
+/* Forward declarations */
+
+static int
+sieve_envelope_address_list_next_string_item(struct sieve_stringlist *_strlist,
+ string_t **str_r);
+static int
+sieve_envelope_address_list_next_item(struct sieve_address_list *_addrlist,
+ struct smtp_address *addr_r,
+ string_t **unparsed_r);
+static void
+sieve_envelope_address_list_reset(struct sieve_stringlist *_strlist);
+
+/* Stringlist object */
+
+struct sieve_envelope_address_list {
+ struct sieve_address_list addrlist;
+
+ struct sieve_stringlist *env_parts;
+
+ const struct smtp_address *const *cur_addresses;
+ const char * const *cur_values;
+
+ int value_index;
+};
+
+static struct sieve_address_list *
+sieve_envelope_address_list_create(const struct sieve_runtime_env *renv,
+ struct sieve_stringlist *env_parts)
+{
+ struct sieve_envelope_address_list *addrlist;
+
+ addrlist = t_new(struct sieve_envelope_address_list, 1);
+ addrlist->addrlist.strlist.runenv = renv;
+ addrlist->addrlist.strlist.exec_status = SIEVE_EXEC_OK;
+ addrlist->addrlist.strlist.next_item =
+ sieve_envelope_address_list_next_string_item;
+ addrlist->addrlist.strlist.reset = sieve_envelope_address_list_reset;
+ addrlist->addrlist.next_item = sieve_envelope_address_list_next_item;
+ addrlist->env_parts = env_parts;
+
+ return &addrlist->addrlist;
+}
+
+static int
+sieve_envelope_address_list_next_item(struct sieve_address_list *_addrlist,
+ struct smtp_address *addr_r,
+ string_t **unparsed_r)
+{
+ struct sieve_envelope_address_list *addrlist =
+ (struct sieve_envelope_address_list *)_addrlist;
+ const struct sieve_runtime_env *renv = _addrlist->strlist.runenv;
+
+ if (addr_r != NULL)
+ smtp_address_init(addr_r, NULL, NULL);
+ if (unparsed_r != NULL) *unparsed_r = NULL;
+
+ while (addrlist->cur_addresses == NULL &&
+ addrlist->cur_values == NULL) {
+ const struct sieve_envelope_part *epart;
+ string_t *envp_item = NULL;
+ int ret;
+
+ /* Read next header value from source list */
+ if ((ret = sieve_stringlist_next_item(addrlist->env_parts,
+ &envp_item)) <= 0)
+ return ret;
+
+ if (_addrlist->strlist.trace) {
+ sieve_runtime_trace(
+ _addrlist->strlist.runenv, 0,
+ "getting `%s' part from message envelope",
+ str_sanitize(str_c(envp_item), 80));
+ }
+
+ if ((epart=_envelope_part_find(str_c(envp_item))) != NULL) {
+ addrlist->value_index = 0;
+
+ if (epart->get_addresses != NULL) {
+ /* Field contains addresses */
+ addrlist->cur_addresses =
+ epart->get_addresses(renv);
+
+ /* Drop empty list */
+ if (addrlist->cur_addresses != NULL &&
+ addrlist->cur_addresses[0] == NULL)
+ addrlist->cur_addresses = NULL;
+ }
+
+ if (addrlist->cur_addresses == NULL &&
+ epart->get_values != NULL) {
+ /* Field contains something else */
+ addrlist->cur_values = epart->get_values(renv);
+
+ /* Drop empty list */
+ if (addrlist->cur_values != NULL &&
+ addrlist->cur_values[0] == NULL)
+ addrlist->cur_values = NULL;
+ }
+ }
+ }
+
+ /* Return next item */
+ if (addrlist->cur_addresses != NULL) {
+ const struct smtp_address *addr =
+ addrlist->cur_addresses[addrlist->value_index];
+
+ if (addr->localpart == NULL) {
+ /* Null path <> */
+ if (unparsed_r != NULL)
+ *unparsed_r = t_str_new_const("", 0);
+ } else {
+ if (addr_r != NULL)
+ *addr_r = *addr;
+ }
+
+ /* Advance to next value */
+ addrlist->value_index++;
+ if (addrlist->cur_addresses[addrlist->value_index] == NULL) {
+ addrlist->cur_addresses = NULL;
+ addrlist->value_index = 0;
+ }
+ } else {
+ if (unparsed_r != NULL) {
+ const char *value =
+ addrlist->cur_values[addrlist->value_index];
+
+ *unparsed_r = t_str_new_const(value, strlen(value));
+ }
+
+ /* Advance to next value */
+ addrlist->value_index++;
+ if (addrlist->cur_values[addrlist->value_index] == NULL) {
+ addrlist->cur_values = NULL;
+ addrlist->value_index = 0;
+ }
+ }
+
+ return 1;
+}
+
+static int
+sieve_envelope_address_list_next_string_item(struct sieve_stringlist *_strlist,
+ string_t **str_r)
+{
+ struct sieve_address_list *addrlist =
+ (struct sieve_address_list *)_strlist;
+ struct smtp_address addr;
+ int ret;
+
+ if ((ret=sieve_envelope_address_list_next_item(addrlist, &addr,
+ str_r)) <= 0)
+ return ret;
+
+ if (addr.localpart != NULL) {
+ const char *addr_str = smtp_address_encode(&addr);
+ if (str_r != NULL)
+ *str_r = t_str_new_const(addr_str, strlen(addr_str));
+ }
+ return 1;
+}
+
+static void
+sieve_envelope_address_list_reset(struct sieve_stringlist *_strlist)
+{
+ struct sieve_envelope_address_list *addrlist =
+ (struct sieve_envelope_address_list *)_strlist;
+
+ sieve_stringlist_reset(addrlist->env_parts);
+ addrlist->cur_addresses = NULL;
+ addrlist->cur_values = NULL;
+ addrlist->value_index = 0;
+}
+
+/*
+ * Command Registration
+ */
+
+static bool
+tst_envelope_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_command_registration *cmd_reg)
+{
+ /* The order of these is not significant */
+ sieve_comparators_link_tag(valdtr, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
+ sieve_match_types_link_tags(valdtr, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
+ sieve_address_parts_link_tags(valdtr, cmd_reg, SIEVE_AM_OPT_ADDRESS_PART);
+ return TRUE;
+}
+
+/*
+ * Validation
+ */
+
+static int
+_envelope_part_is_supported(void *context, struct sieve_ast_argument *arg)
+{
+ const struct sieve_envelope_part **not_address =
+ (const struct sieve_envelope_part **) context;
+
+ if (sieve_argument_is_string_literal(arg)) {
+ const struct sieve_envelope_part *epart;
+
+ if ((epart=_envelope_part_find(
+ sieve_ast_strlist_strc(arg))) != NULL) {
+ if (epart->get_addresses == NULL) {
+ if (*not_address == NULL)
+ *not_address = epart;
+ }
+ return 1;
+ }
+ return 0;
+ }
+ return 1; /* Can't check at compile time */
+}
+
+static bool
+tst_envelope_validate(struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+ struct sieve_ast_argument *epart;
+ struct sieve_comparator cmp_default =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+ struct sieve_match_type mcht_default =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ const struct sieve_envelope_part *not_address = NULL;
+
+ if (!sieve_validate_positional_argument(valdtr, tst, arg,
+ "envelope part", 1,
+ SAAT_STRING_LIST)) {
+ return FALSE;
+ }
+
+ if (!sieve_validator_argument_activate(valdtr, tst, arg, FALSE))
+ return FALSE;
+
+ /* Check whether supplied envelope parts are supported
+ * FIXME: verify dynamic envelope parts at runtime
+ */
+ epart = arg;
+ if (sieve_ast_stringlist_map(&epart, (void *) &not_address,
+ _envelope_part_is_supported) <= 0) {
+ i_assert(epart != NULL);
+ sieve_argument_validate_error(
+ valdtr, epart,
+ "specified envelope part '%s' is not supported by the envelope test",
+ str_sanitize(sieve_ast_strlist_strc(epart), 64));
+ return FALSE;
+ }
+
+ if (not_address != NULL) {
+ struct sieve_ast_argument *addrp_arg =
+ sieve_command_find_argument(tst, &address_part_tag);
+
+ if (addrp_arg != NULL) {
+ sieve_argument_validate_error(
+ valdtr, addrp_arg,
+ "address part ':%s' specified while non-address envelope part '%s' "
+ "is tested with the envelope test",
+ sieve_ast_argument_tag(addrp_arg),
+ not_address->identifier);
+ return FALSE;
+ }
+ }
+
+ arg = sieve_ast_argument_next(arg);
+
+ if (!sieve_validate_positional_argument(valdtr, tst, arg, "key list", 2,
+ SAAT_STRING_LIST))
+ return FALSE;
+
+ if (!sieve_validator_argument_activate(valdtr, tst, arg, FALSE))
+ return FALSE;
+
+ /* Validate the key argument to a specified match type */
+ return sieve_match_type_validate(valdtr, tst, arg,
+ &mcht_default, &cmp_default);
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+tst_envelope_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ (void)sieve_operation_emit(cgenv->sblock, cmd->ext,
+ &envelope_operation);
+
+ /* Generate arguments */
+ if (!sieve_generate_arguments(cgenv, cmd, NULL))
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+ext_envelope_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "ENVELOPE");
+ sieve_code_descend(denv);
+
+ /* Handle any optional arguments */
+ if (sieve_addrmatch_opr_optional_dump(denv, address, NULL) != 0)
+ return FALSE;
+
+ return (sieve_opr_stringlist_dump(denv, address, "envelope part") &&
+ sieve_opr_stringlist_dump(denv, address, "key list"));
+}
+
+/*
+ * Interpretation
+ */
+
+static int
+ext_envelope_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ struct sieve_comparator cmp =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+ struct sieve_match_type mcht =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ struct sieve_address_part addrp =
+ SIEVE_ADDRESS_PART_DEFAULT(all_address_part);
+ struct sieve_stringlist *env_part_list, *value_list, *key_list;
+ struct sieve_address_list *addr_list;
+ int match, ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Read optional operands */
+ if (sieve_addrmatch_opr_optional_read(renv, address, NULL, &ret,
+ &addrp, &mcht, &cmp) < 0)
+ return ret;
+
+ /* Read envelope-part */
+ if ((ret = sieve_opr_stringlist_read(renv, address, "envelope-part",
+ &env_part_list)) <= 0)
+ return ret;
+
+ /* Read key-list */
+ if ((ret = sieve_opr_stringlist_read(renv, address, "key-list",
+ &key_list)) <= 0)
+ return ret;
+
+ /*
+ * Perform test
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "envelope test");
+
+ /* Create value stringlist */
+ addr_list = sieve_envelope_address_list_create(renv, env_part_list);
+ value_list = sieve_address_part_stringlist_create(renv, &addrp,
+ addr_list);
+
+ /* Perform match */
+ if ((match = sieve_match(renv, &mcht, &cmp,
+ value_list, key_list, &ret)) < 0)
+ return ret;
+
+ /* Set test result for subsequent conditional jump */
+ sieve_interpreter_set_test_result(renv->interp, match > 0);
+ return SIEVE_EXEC_OK;
+}
+
diff --git a/pigeonhole/src/lib-sieve/ext-fileinto.c b/pigeonhole/src/lib-sieve/ext-fileinto.c
new file mode 100644
index 0000000..fb65758
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/ext-fileinto.c
@@ -0,0 +1,225 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension fileinto
+ * ------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5228
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+#include "unichar.h"
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+#include "sieve-binary.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-message.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-result.h"
+
+/*
+ * Forward declarations
+ */
+
+static const struct sieve_command_def fileinto_command;
+const struct sieve_operation_def fileinto_operation;
+const struct sieve_extension_def fileinto_extension;
+
+/*
+ * Extension
+ */
+
+static bool
+ext_fileinto_validator_load(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr);
+
+const struct sieve_extension_def fileinto_extension = {
+ .name = "fileinto",
+ .validator_load = ext_fileinto_validator_load,
+ SIEVE_EXT_DEFINE_OPERATION(fileinto_operation),
+};
+
+static bool
+ext_fileinto_validator_load(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr)
+{
+ /* Register new command */
+ sieve_validator_register_command(valdtr, ext, &fileinto_command);
+
+ return TRUE;
+}
+
+/*
+ * Fileinto command
+ *
+ * Syntax:
+ * fileinto <folder: string>
+ */
+
+static bool
+cmd_fileinto_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd);
+static bool
+cmd_fileinto_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+static const struct sieve_command_def fileinto_command = {
+ .identifier = "fileinto",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_fileinto_validate,
+ .generate = cmd_fileinto_generate,
+};
+
+/*
+ * Fileinto operation
+ */
+
+static bool
+ext_fileinto_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+ext_fileinto_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def fileinto_operation = {
+ .mnemonic = "FILEINTO",
+ .ext_def = &fileinto_extension,
+ .dump = ext_fileinto_operation_dump,
+ .execute = ext_fileinto_operation_execute,
+};
+
+/*
+ * Validation
+ */
+
+static bool
+cmd_fileinto_validate(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+
+ if (!sieve_validate_positional_argument(valdtr, cmd, arg, "folder",
+ 1, SAAT_STRING))
+ return FALSE;
+
+ if (!sieve_validator_argument_activate(valdtr, cmd, arg, FALSE))
+ return FALSE;
+
+ /* Check name validity when folder argument is not a variable */
+ if (sieve_argument_is_string_literal(arg)) {
+ const char *folder = sieve_ast_argument_strc(arg), *error;
+
+ if (!sieve_mailbox_check_name(folder, &error)) {
+ sieve_command_validate_error(
+ valdtr, cmd, "fileinto command: "
+ "invalid folder name `%s' specified: %s",
+ str_sanitize(folder, 256), error);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+cmd_fileinto_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &fileinto_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, cmd, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+ext_fileinto_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "FILEINTO");
+ sieve_code_descend(denv);
+
+ if (sieve_action_opr_optional_dump(denv, address, NULL) != 0)
+ return FALSE;
+
+ return sieve_opr_string_dump(denv, address, "folder");
+}
+
+/*
+ * Execution
+ */
+
+static int
+ext_fileinto_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ struct sieve_side_effects_list *slist = NULL;
+ string_t *folder;
+ const char *error;
+ bool trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_ACTIONS);
+ int ret = 0;
+
+ /*
+ * Read operands
+ */
+
+ /* Optional operands (side effects only) */
+ if (sieve_action_opr_optional_read(renv, address, NULL,
+ &ret, &slist) != 0)
+ return ret;
+
+ /* Folder operand */
+ ret = sieve_opr_string_read(renv, address, "folder", &folder);
+ if (ret <= 0)
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ if (trace) {
+ sieve_runtime_trace(renv, 0, "fileinto action");
+ sieve_runtime_trace_descend(renv);
+ }
+
+ if (!sieve_mailbox_check_name(str_c(folder), &error)) {
+ sieve_runtime_error(
+ renv, NULL, "fileinto command: "
+ "invalid folder name `%s' specified: %s",
+ str_c(folder), error);
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ if (trace) {
+ sieve_runtime_trace(renv, 0, "store message in mailbox `%s'",
+ str_sanitize(str_c(folder), 80));
+ }
+
+ /* Add action to result */
+ if (sieve_act_store_add_to_result(renv, "fileinto", slist,
+ str_c(folder)) < 0)
+ return SIEVE_EXEC_FAILURE;
+
+ sieve_message_snapshot(renv->msgctx);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/ext-reject.c b/pigeonhole/src/lib-sieve/ext-reject.c
new file mode 100644
index 0000000..649c1f2
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/ext-reject.c
@@ -0,0 +1,606 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension reject
+ * ----------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5429
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "hostpid.h"
+#include "str-sanitize.h"
+#include "message-date.h"
+#include "message-size.h"
+#include "istream.h"
+#include "istream-header-filter.h"
+
+#include "rfc2822.h"
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-result.h"
+#include "sieve-message.h"
+#include "sieve-smtp.h"
+
+/*
+ * Forward declarations
+ */
+
+static const struct sieve_command_def reject_command;
+static const struct sieve_operation_def reject_operation;
+
+static const struct sieve_command_def ereject_command;
+static const struct sieve_operation_def ereject_operation;
+
+/*
+ * Extensions
+ */
+
+static bool
+ext_reject_validator_validate(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context,
+ struct sieve_ast_argument *require_arg,
+ bool required);
+static int
+ext_reject_interpreter_run(const struct sieve_extension *this_ext,
+ const struct sieve_runtime_env *renv,
+ void *context, bool deferred);
+
+/* Reject */
+
+static bool
+ext_reject_validator_load(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr);
+static bool
+ext_reject_interpreter_load(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_extension_def reject_extension = {
+ .name = "reject",
+ .validator_load = ext_reject_validator_load,
+ .interpreter_load = ext_reject_interpreter_load,
+ SIEVE_EXT_DEFINE_OPERATION(reject_operation)
+};
+const struct sieve_validator_extension
+reject_validator_extension = {
+ .ext = &reject_extension,
+ .validate = ext_reject_validator_validate
+};
+const struct sieve_interpreter_extension
+reject_interpreter_extension = {
+ .ext_def = &reject_extension,
+ .run = ext_reject_interpreter_run
+};
+
+static bool
+ext_reject_validator_load(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr)
+{
+ /* Register new command */
+ sieve_validator_register_command(valdtr, ext, &reject_command);
+
+ sieve_validator_extension_register(valdtr, ext,
+ &reject_validator_extension, NULL);
+ return TRUE;
+}
+
+static bool
+ext_reject_interpreter_load(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ sieve_interpreter_extension_register(renv->interp, ext,
+ &reject_interpreter_extension,
+ NULL);
+ return TRUE;
+}
+
+/* EReject */
+
+static bool
+ext_ereject_validator_load(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr);
+static bool
+ext_ereject_interpreter_load(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_extension_def ereject_extension = {
+ .name = "ereject",
+ .validator_load = ext_ereject_validator_load,
+ .interpreter_load = ext_ereject_interpreter_load,
+ SIEVE_EXT_DEFINE_OPERATION(ereject_operation)
+};
+const struct sieve_validator_extension
+ereject_validator_extension = {
+ .ext = &ereject_extension,
+ .validate = ext_reject_validator_validate
+};
+const struct sieve_interpreter_extension
+ereject_interpreter_extension = {
+ .ext_def = &ereject_extension,
+ .run = ext_reject_interpreter_run
+};
+
+static bool
+ext_ereject_validator_load(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr)
+{
+ /* Register new command */
+ sieve_validator_register_command(valdtr, ext, &ereject_command);
+
+ sieve_validator_extension_register(valdtr, ext,
+ &ereject_validator_extension, NULL);
+ return TRUE;
+}
+
+static bool
+ext_ereject_interpreter_load(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ sieve_interpreter_extension_register(renv->interp, ext,
+ &ereject_interpreter_extension,
+ NULL);
+ return TRUE;
+}
+
+/* Environment checking */
+
+static bool
+ext_reject_validator_validate(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr,
+ void *context ATTR_UNUSED,
+ struct sieve_ast_argument *require_arg,
+ bool required)
+{
+ if (required) {
+ enum sieve_compile_flags flags =
+ sieve_validator_compile_flags(valdtr);
+
+ if ((flags & SIEVE_COMPILE_FLAG_NO_ENVELOPE) != 0) {
+ sieve_argument_validate_error(
+ valdtr, require_arg,
+ "the %s extension cannot be used in this context "
+ "(needs access to message envelope)",
+ sieve_extension_name(ext));
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static int
+ext_reject_interpreter_run(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ void *context ATTR_UNUSED, bool deferred)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+
+ if ((eenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) != 0) {
+ if (!deferred) {
+ sieve_runtime_error(
+ renv, NULL,
+ "the %s extension cannot be used in this context "
+ "(needs access to message envelope)",
+ sieve_extension_name(ext));
+ }
+ return SIEVE_EXEC_FAILURE;
+ }
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Commands
+ */
+
+/* Forward declarations */
+
+static bool
+cmd_reject_validate(struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool
+cmd_reject_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd);
+
+/* Reject command
+ *
+ * Syntax:
+ * reject <reason: string>
+ */
+
+static const struct sieve_command_def reject_command = {
+ .identifier = "reject",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_reject_validate,
+ .generate = cmd_reject_generate
+};
+
+/* EReject command
+ *
+ * Syntax:
+ * ereject <reason: string>
+ */
+
+static const struct sieve_command_def ereject_command = {
+ .identifier = "ereject",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_reject_validate,
+ .generate = cmd_reject_generate,
+};
+
+/*
+ * Operations
+ */
+
+/* Forward declarations */
+
+static bool
+ext_reject_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+ext_reject_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+/* Reject operation */
+
+static const struct sieve_operation_def reject_operation = {
+ .mnemonic = "REJECT",
+ .ext_def = &reject_extension,
+ .dump = ext_reject_operation_dump,
+ .execute = ext_reject_operation_execute
+};
+
+/* EReject operation */
+
+static const struct sieve_operation_def ereject_operation = {
+ .mnemonic = "EREJECT",
+ .ext_def = &ereject_extension,
+ .dump = ext_reject_operation_dump,
+ .execute = ext_reject_operation_execute
+};
+
+/*
+ * Reject action
+ */
+
+static int
+act_reject_check_duplicate(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other);
+int act_reject_check_conflict(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other);
+static void
+act_reject_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv, bool *keep);
+static int
+act_reject_start(const struct sieve_action_exec_env *aenv, void **tr_context);
+static int
+act_reject_execute(const struct sieve_action_exec_env *aenv, void *tr_context,
+ bool *keep);
+static int
+act_reject_commit(const struct sieve_action_exec_env *aenv, void *tr_context);
+
+const struct sieve_action_def act_reject = {
+ .name = "reject",
+ .flags = SIEVE_ACTFLAG_SENDS_RESPONSE,
+ .check_duplicate = act_reject_check_duplicate,
+ .check_conflict = act_reject_check_conflict,
+ .print = act_reject_print,
+ .start = act_reject_start,
+ .execute = act_reject_execute,
+ .commit = act_reject_commit,
+};
+
+struct act_reject_context {
+ const char *reason;
+ bool ereject;
+};
+
+/*
+ * Validation
+ */
+
+static bool
+cmd_reject_validate(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+
+ if (!sieve_validate_positional_argument(valdtr, cmd, arg, "reason",
+ 1, SAAT_STRING))
+ return FALSE;
+
+ return sieve_validator_argument_activate(valdtr, cmd, arg, FALSE);
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+cmd_reject_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ if (sieve_command_is(cmd, reject_command)) {
+ sieve_operation_emit(cgenv->sblock, cmd->ext,
+ &reject_operation);
+ } else {
+ sieve_operation_emit(cgenv->sblock, cmd->ext,
+ &ereject_operation);
+ }
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, cmd, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+ext_reject_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "%s", sieve_operation_mnemonic(denv->oprtn));
+ sieve_code_descend(denv);
+
+ if (sieve_action_opr_optional_dump(denv, address, NULL) != 0)
+ return FALSE;
+
+ return sieve_opr_string_dump(denv, address, "reason");
+}
+
+/*
+ * Interpretation
+ */
+
+static int
+ext_reject_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ const struct sieve_operation *oprtn = renv->oprtn;
+ const struct sieve_extension *this_ext = oprtn->ext;
+ struct sieve_side_effects_list *slist = NULL;
+ struct act_reject_context *act;
+ string_t *reason;
+ pool_t pool;
+ int ret;
+
+ /*
+ * Read data
+ */
+
+ /* Optional operands (side effects only) */
+ if (sieve_action_opr_optional_read(renv, address, NULL,
+ &ret, &slist) != 0)
+ return ret;
+
+ /* Read rejection reason */
+ if ((ret = sieve_opr_string_read(renv, address, "reason",
+ &reason)) <= 0)
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_ACTIONS)) {
+ if (sieve_operation_is(oprtn, ereject_operation))
+ sieve_runtime_trace(renv, 0, "ereject action");
+ else
+ sieve_runtime_trace(renv, 0, "reject action");
+
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(renv, 0, "reject message with reason `%s'",
+ str_sanitize(str_c(reason), 64));
+ }
+
+ /* Add reject action to the result */
+ pool = sieve_result_pool(renv->result);
+ act = p_new(pool, struct act_reject_context, 1);
+ act->reason = p_strdup(pool, str_c(reason));
+ act->ereject = sieve_operation_is(oprtn, ereject_operation);
+
+ if (sieve_result_add_action(renv, this_ext,
+ (act->ereject ? "ereject" : "reject"),
+ &act_reject, slist, (void *)act,
+ 0, FALSE) < 0)
+ return SIEVE_EXEC_FAILURE;
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Action implementation
+ */
+
+struct act_reject_transaction {
+ bool ignore_reject:1;
+};
+
+static int
+act_reject_check_duplicate(const struct sieve_runtime_env *renv ATTR_UNUSED,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other)
+{
+ if (!sieve_action_is_executed(act_other, renv->result)) {
+ sieve_runtime_error(
+ renv, act->location,
+ "duplicate reject/ereject action not allowed "
+ "(previously triggered one was here: %s)",
+ act_other->location);
+ return -1;
+ }
+
+ return 1;
+}
+
+int act_reject_check_conflict(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other)
+{
+ if ((act_other->def->flags & SIEVE_ACTFLAG_TRIES_DELIVER) > 0) {
+ if (!sieve_action_is_executed(act_other, renv->result)) {
+ sieve_runtime_error(
+ renv, act->location,
+ "reject/ereject action conflicts with other action: "
+ "the %s action (%s) tries to deliver the message",
+ act_other->def->name, act_other->location);
+ return -1;
+ }
+ }
+
+ if ((act_other->def->flags & SIEVE_ACTFLAG_SENDS_RESPONSE) > 0) {
+ struct act_reject_context *rj_ctx;
+
+ if (!sieve_action_is_executed(act_other, renv->result)) {
+ sieve_runtime_error(
+ renv, act->location,
+ "reject/ereject action conflicts with other action: "
+ "the %s action (%s) also sends a response to the sender",
+ act_other->def->name, act_other->location);
+ return -1;
+ }
+
+ /* Conflicting action was already executed, transform reject
+ * into discard equivalent.
+ */
+ rj_ctx = (struct act_reject_context *)act->context;
+ rj_ctx->reason = NULL;
+ }
+
+ return 0;
+}
+
+static void
+act_reject_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv, bool *keep)
+{
+ struct act_reject_context *rj_ctx =
+ (struct act_reject_context *)action->context;
+
+ if (rj_ctx->reason != NULL) {
+ sieve_result_action_printf(
+ rpenv, "reject message with reason: %s",
+ str_sanitize(rj_ctx->reason, 128));
+ } else {
+ sieve_result_action_printf(
+ rpenv,
+ "reject message without sending a response (discard)");
+ }
+
+ *keep = FALSE;
+}
+
+static int
+act_reject_start(const struct sieve_action_exec_env *aenv, void **tr_context)
+{
+ struct act_reject_transaction *trans;
+ pool_t pool = sieve_result_pool(aenv->result);
+
+ /* Create transaction context */
+ trans = p_new(pool, struct act_reject_transaction, 1);
+ *tr_context = trans;
+
+ return SIEVE_EXEC_OK;
+}
+
+static int
+act_reject_execute(const struct sieve_action_exec_env *aenv,
+ void *tr_context, bool *keep)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct act_reject_context *rj_ctx =
+ (struct act_reject_context *)aenv->action->context;
+ struct act_reject_transaction *trans = tr_context;
+ const struct smtp_address *sender, *recipient;
+
+ sender = sieve_message_get_sender(aenv->msgctx);
+ recipient = sieve_message_get_orig_recipient(aenv->msgctx);
+
+ if ((eenv->flags & SIEVE_EXECUTE_FLAG_SKIP_RESPONSES) != 0) {
+ sieve_result_global_log(
+ aenv, "not sending reject message (skipped)");
+ trans->ignore_reject = TRUE;
+ return SIEVE_EXEC_OK;
+ }
+ if (smtp_address_isnull(recipient)) {
+ sieve_result_global_warning(
+ aenv, "reject action aborted: envelope recipient is <>");
+ trans->ignore_reject = TRUE;
+ return SIEVE_EXEC_OK;
+ }
+ if (rj_ctx->reason == NULL) {
+ sieve_result_global_log(
+ aenv, "not sending reject message "
+ "(would cause second response to sender)");
+ trans->ignore_reject = TRUE;
+ *keep = FALSE;
+ return SIEVE_EXEC_OK;
+ }
+ if (smtp_address_isnull(sender)) {
+ sieve_result_global_log(
+ aenv, "not sending reject message to <>");
+ trans->ignore_reject = TRUE;
+ *keep = FALSE;
+ return SIEVE_EXEC_OK;
+ }
+
+ *keep = FALSE;
+ return SIEVE_EXEC_OK;
+}
+
+static int
+act_reject_commit(const struct sieve_action_exec_env *aenv,
+ void *tr_context ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct act_reject_context *rj_ctx =
+ (struct act_reject_context *)aenv->action->context;
+ struct act_reject_transaction *trans = tr_context;
+ const struct smtp_address *sender, *recipient;
+ int ret;
+
+ sender = sieve_message_get_sender(aenv->msgctx);
+ recipient = sieve_message_get_orig_recipient(aenv->msgctx);
+
+ if (trans->ignore_reject)
+ return SIEVE_EXEC_OK;
+
+ if ((ret = sieve_action_reject_mail(aenv, recipient,
+ rj_ctx->reason)) <= 0)
+ return ret;
+
+ eenv->exec_status->significant_action_executed = TRUE;
+
+ struct event_passthrough *e = sieve_action_create_finish_event(aenv);
+
+ sieve_result_event_log(aenv, e->event(),
+ "rejected message from <%s> (%s)",
+ smtp_address_encode(sender),
+ (rj_ctx->ereject ? "ereject" : "reject"));
+
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/mcht-contains.c b/pigeonhole/src/lib-sieve/mcht-contains.c
new file mode 100644
index 0000000..a9b3190
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/mcht-contains.c
@@ -0,0 +1,66 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Match-type ':contains'
+ */
+
+#include "lib.h"
+
+#include "sieve-match-types.h"
+#include "sieve-comparators.h"
+#include "sieve-match.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * Forward declarations
+ */
+
+static int mcht_contains_match_key
+ (struct sieve_match_context *mctx, const char *val, size_t val_size,
+ const char *key, size_t key_size);
+
+/*
+ * Match-type object
+ */
+
+const struct sieve_match_type_def contains_match_type = {
+ SIEVE_OBJECT("contains",
+ &match_type_operand, SIEVE_MATCH_TYPE_CONTAINS),
+ .validate_context = sieve_match_substring_validate_context,
+ .match_key = mcht_contains_match_key
+};
+
+/*
+ * Match-type implementation
+ */
+
+/* FIXME: Naive substring match implementation. Should switch to more
+ * efficient algorithm if large values need to be searched (e.g. message body).
+ */
+static int mcht_contains_match_key
+(struct sieve_match_context *mctx, const char *val, size_t val_size,
+ const char *key, size_t key_size)
+{
+ const struct sieve_comparator *cmp = mctx->comparator;
+ const char *vend = (const char *) val + val_size;
+ const char *kend = (const char *) key + key_size;
+ const char *vp = val;
+ const char *kp = key;
+
+ if ( val_size == 0 )
+ return ( key_size == 0 ? 1 : 0 );
+
+ if ( cmp->def == NULL || cmp->def->char_match == NULL )
+ return 0;
+
+ while ( (vp < vend) && (kp < kend) ) {
+ if ( !cmp->def->char_match(cmp, &vp, vend, &kp, kend) )
+ vp++;
+ }
+
+ return ( kp == kend ? 1 : 0 );
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/mcht-is.c b/pigeonhole/src/lib-sieve/mcht-is.c
new file mode 100644
index 0000000..db374bb
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/mcht-is.c
@@ -0,0 +1,52 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Match-type ':is':
+ */
+
+#include "lib.h"
+
+#include "sieve-match-types.h"
+#include "sieve-comparators.h"
+#include "sieve-match.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * Forward declarations
+ */
+
+static int mcht_is_match_key
+ (struct sieve_match_context *mctx, const char *val, size_t val_size,
+ const char *key, size_t key_size);
+
+/*
+ * Match-type object
+ */
+
+const struct sieve_match_type_def is_match_type = {
+ SIEVE_OBJECT("is",
+ &match_type_operand, SIEVE_MATCH_TYPE_IS),
+ .match_key = mcht_is_match_key
+};
+
+/*
+ * Match-type implementation
+ */
+
+static int mcht_is_match_key
+(struct sieve_match_context *mctx ATTR_UNUSED,
+ const char *val, size_t val_size,
+ const char *key, size_t key_size)
+{
+ if ( val_size == 0 )
+ return ( key_size == 0 ? 1 : 0 );
+
+ if ( mctx->comparator->def != NULL && mctx->comparator->def->compare != NULL )
+ return (mctx->comparator->def->compare(mctx->comparator,
+ val, val_size, key, key_size) == 0 ? 1 : 0 );
+
+ return 0;
+}
+
diff --git a/pigeonhole/src/lib-sieve/mcht-matches.c b/pigeonhole/src/lib-sieve/mcht-matches.c
new file mode 100644
index 0000000..050fce9
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/mcht-matches.c
@@ -0,0 +1,440 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Match-type ':matches'
+ */
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve-match-types.h"
+#include "sieve-comparators.h"
+#include "sieve-match.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * Forward declarations
+ */
+
+static int mcht_matches_match_key
+ (struct sieve_match_context *mctx, const char *val, size_t val_size,
+ const char *key, size_t key_size);
+
+/*
+ * Match-type object
+ */
+
+const struct sieve_match_type_def matches_match_type = {
+ SIEVE_OBJECT("matches",
+ &match_type_operand, SIEVE_MATCH_TYPE_MATCHES),
+ .validate_context = sieve_match_substring_validate_context,
+ .match_key = mcht_matches_match_key
+};
+
+/*
+ * Match-type implementation
+ */
+
+/* Quick 'n dirty debug */
+//#define MATCH_DEBUG
+#ifdef MATCH_DEBUG
+#define debug_printf(...) printf ("match debug: " __VA_ARGS__)
+#else
+#define debug_printf(...)
+#endif
+
+/* FIXME: Naive implementation, substitute this with dovecot src/lib/str-find.c
+ */
+static inline bool _string_find(const struct sieve_comparator *cmp,
+ const char **valp, const char *vend, const char **keyp, const char *kend)
+{
+ while ( (*valp < vend) && (*keyp < kend) ) {
+ if ( !cmp->def->char_match(cmp, valp, vend, keyp, kend) )
+ (*valp)++;
+ }
+
+ return (*keyp == kend);
+}
+
+static char _scan_key_section
+ (string_t *section, const char **wcardp, const char *key_end)
+{
+ /* Find next wildcard and resolve escape sequences */
+ str_truncate(section, 0);
+ while ( *wcardp < key_end && **wcardp != '*' && **wcardp != '?') {
+ if ( **wcardp == '\\' ) {
+ (*wcardp)++;
+ }
+ str_append_c(section, **wcardp);
+ (*wcardp)++;
+ }
+
+ /* Record wildcard character or \0 */
+ if ( *wcardp < key_end ) {
+ return **wcardp;
+ }
+
+ i_assert( *wcardp == key_end );
+ return '\0';
+}
+
+static int mcht_matches_match_key
+(struct sieve_match_context *mctx, const char *val, size_t val_size,
+ const char *key, size_t key_size)
+{
+ const struct sieve_comparator *cmp = mctx->comparator;
+ struct sieve_match_values *mvalues;
+ string_t *mvalue = NULL, *mchars = NULL;
+ string_t *section, *subsection;
+ const char *vend, *kend, *vp, *kp, *wp, *pvp;
+ bool backtrack = FALSE; /* TRUE: match of '?'-connected sections failed */
+ char wcard = '\0'; /* Current wildcard */
+ char next_wcard = '\0'; /* Next widlcard */
+ unsigned int key_offset = 0;
+
+ if ( cmp->def == NULL || cmp->def->char_match == NULL )
+ return 0;
+
+ /* Key sections */
+ section = t_str_new(32); /* Section (after beginning or *) */
+ subsection = t_str_new(32); /* Sub-section (after ?) */
+
+ /* Mark end of value and key */
+ vend = (const char *) val + val_size;
+ kend = (const char *) key + key_size;
+
+ /* Initialize pointers */
+ vp = val; /* Value pointer */
+ kp = key; /* Key pointer */
+ wp = key; /* Wildcard (key) pointer */
+
+ /* Start match values list if requested */
+ if ( (mvalues = sieve_match_values_start(mctx->runenv)) != NULL ) {
+ /* Skip ${0} for now; added when match succeeds */
+ sieve_match_values_add(mvalues, NULL);
+
+ mvalue = t_str_new(32); /* Match value (*) */
+ mchars = t_str_new(32); /* Match characters (.?..?.??) */
+ }
+
+ /* Match the pattern:
+ * <pattern> = <section>*<section>*<section>...
+ * <section> = <sub-section>?<sub-section>?<sub-section>...
+ *
+ * Escape sequences \? and \* need special attention.
+ */
+
+ debug_printf("=== Start ===\n");
+ debug_printf(" key: %s\n", t_strdup_until(key, kend));
+ debug_printf(" value: %s\n", t_strdup_until(val, vend));
+
+ /* Loop until either key or value ends */
+ while (kp < kend && vp < vend ) {
+ const char *needle, *nend;
+
+ if ( !backtrack ) {
+ /* Search the next '*' wildcard in the key string */
+
+ wcard = next_wcard;
+
+ /* Find the needle to look for in the string */
+ key_offset = 0;
+ for (;;) {
+ next_wcard = _scan_key_section(section, &wp, kend);
+
+ if ( wcard == '\0' || str_len(section) > 0 )
+ break;
+
+ if ( next_wcard == '*' ) {
+ break;
+ }
+
+ if ( wp < kend )
+ wp++;
+ else
+ break;
+ key_offset++;
+ }
+
+ debug_printf("found wildcard '%c' at pos [%d]\n",
+ next_wcard, (int) (wp-key));
+
+ if ( mvalues != NULL )
+ str_truncate(mvalue, 0);
+ } else {
+ /* Backtracked; '*' wildcard is retained */
+ debug_printf("backtracked");
+ backtrack = FALSE;
+ }
+
+ /* Determine what we are looking for */
+ needle = str_c(section);
+ nend = PTR_OFFSET(needle, str_len(section));
+
+ debug_printf(" section needle: '%s'\n", t_strdup_until(needle, nend));
+ debug_printf(" section key: '%s'\n", t_strdup_until(kp, kend));
+ debug_printf(" section remnant: '%s'\n", t_strdup_until(wp, kend));
+ debug_printf(" value remnant: '%s'\n", t_strdup_until(vp, vend));
+ debug_printf(" key offset: %d\n", key_offset);
+
+ pvp = vp;
+ if ( next_wcard == '\0' ) {
+ if ( wcard == '\0' ) {
+ /* No current wildcard; match needs to happen right at the beginning */
+ debug_printf("next_wcard = NULL && wcard = NUL; needle should be equal to value.\n");
+
+ if ( (vend - vp) != (nend - needle) ||
+ !cmp->def->char_match(cmp, &vp, vend, &needle, nend) ) {
+ debug_printf(" key not equal to value\n");
+ break;
+ }
+
+ } else {
+ const char *qp, *qend;
+ size_t slen;
+
+ /* No more wildcards; find the needle substring at the end of string */
+ debug_printf("next_wcard = NUL; must find needle at end\n");
+
+ /* Check if the value is still large enough */
+ slen = str_len(section);
+ if ( (vp + slen) > vend ) {
+ debug_printf(" wont match: value is too short\n");
+ break;
+ }
+
+ /* Move value pointer to where the needle should be */
+ vp = vend - slen;
+
+ /* Record match values */
+ qend = vp;
+ qp = vp - key_offset;
+
+ if ( mvalues != NULL )
+ str_append_data(mvalue, pvp, qp-pvp);
+
+ /* Compare needle to end of value string */
+ if ( !cmp->def->char_match(cmp, &vp, vend, &needle, nend) ) {
+ debug_printf(" match at end failed\n");
+ break;
+ }
+
+ /* Add match values */
+ if ( mvalues != NULL ) {
+ /* Append '*' match value */
+ sieve_match_values_add(mvalues, mvalue);
+
+ /* Append any initial '?' match values */
+ for ( ; qp < qend; qp++ )
+ sieve_match_values_add_char(mvalues, *qp);
+ }
+ }
+
+ /* Finish match */
+ kp = kend;
+ vp = vend;
+
+ debug_printf(" matched end of value\n");
+ break;
+ } else {
+ /* Next wildcard found; match needle before next wildcard */
+
+ const char *prv = NULL; /* Stored value pointer for backtrack */
+ const char *prk = NULL; /* Stored key pointer for backtrack */
+ const char *prw = NULL; /* Stored wildcard pointer for backtrack */
+ const char *chars;
+
+ /* Reset '?' match values */
+ if ( mvalues != NULL )
+ str_truncate(mchars, 0);
+
+ if ( wcard == '\0' ) {
+ /* No current wildcard; match needs to happen right at the beginning */
+ debug_printf("wcard = NUL; needle should be found at the beginning.\n");
+ debug_printf(" begin needle: '%s'\n", t_strdup_until(needle, nend));
+ debug_printf(" begin value: '%s'\n", t_strdup_until(vp, vend));
+
+ if ( !cmp->def->char_match(cmp, &vp, vend, &needle, nend) ) {
+ debug_printf(" failed to find needle at beginning\n");
+ break;
+ }
+
+ } else {
+ /* Current wildcard present; match needle between current and next wildcard */
+ debug_printf("wcard != NUL; must find needle at an offset (>= %d).\n",
+ key_offset);
+
+ /* Match may happen at any offset (>= key offset): find substring */
+ vp += key_offset;
+ if ( (vp >= vend) || !_string_find(cmp, &vp, vend, &needle, nend) ) {
+ debug_printf(" failed to find needle at an offset\n");
+ break;
+ }
+
+ prv = vp - str_len(section);
+ prk = kp;
+ prw = wp;
+
+ /* Append match values */
+ if ( mvalues != NULL ) {
+ const char *qend = vp - str_len(section);
+ const char *qp = qend - key_offset;
+
+ /* Append '*' match value */
+ str_append_data(mvalue, pvp, qp-pvp);
+
+ /* Append any initial '?' match values (those that caused the key
+ * offset.
+ */
+ for ( ; qp < qend; qp++ )
+ str_append_c(mchars, *qp);
+ }
+ }
+
+ /* Update wildcard and key pointers for next wildcard scan */
+ if ( wp < kend ) wp++;
+ kp = wp;
+
+ /* Scan successive '?' wildcards */
+ while ( next_wcard == '?' ) {
+ debug_printf("next_wcard = '?'; need to match arbitrary character\n");
+
+ /* Add match value */
+ if ( mvalues != NULL )
+ str_append_c(mchars, *vp);
+
+ vp++;
+
+ /* Scan for next '?' wildcard */
+ next_wcard = _scan_key_section(subsection, &wp, kend);
+ debug_printf("found next wildcard '%c' at pos [%d] (fixed match)\n",
+ next_wcard, (int) (wp-key));
+
+ /* Determine what we are looking for */
+ needle = str_c(subsection);
+ nend = needle + str_len(subsection);
+
+ debug_printf(" sub key: '%s'\n", t_strdup_until(needle, nend));
+ debug_printf(" value remnant: '%s'\n", vp <= vend ? t_strdup_until(vp, vend) : "");
+
+ /* Try matching the needle at fixed position */
+ if ( (needle == nend && next_wcard == '\0' && vp < vend ) ||
+ !cmp->def->char_match(cmp, &vp, vend, &needle, nend) ) {
+
+ /* Match failed: now we have a problem. We need to backtrack to the previous
+ * '*' wildcard occurrence and start scanning for the next possible match.
+ */
+
+ debug_printf(" failed fixed match\n");
+
+ /* Start backtrack */
+ if ( prv != NULL && prv + 1 < vend ) {
+ /* Restore pointers */
+ vp = prv;
+ kp = prk;
+ wp = prw;
+
+ /* Skip forward one value character to scan the next possible match */
+ if ( mvalues != NULL )
+ str_append_c(mvalue, *vp);
+ vp++;
+
+ /* Set wildcard state appropriately */
+ wcard = '*';
+ next_wcard = '?';
+
+ /* Backtrack */
+ backtrack = TRUE;
+
+ debug_printf(" BACKTRACK\n");
+ }
+
+ /* Break '?' wildcard scanning loop */
+ break;
+ }
+
+ /* Update wildcard and key pointers for next wildcard scan */
+ if ( wp < kend ) wp++;
+ kp = wp;
+ }
+
+ if ( !backtrack ) {
+ unsigned int i;
+
+ if ( next_wcard == '?' ) {
+ debug_printf("failed to match '?'\n");
+ break;
+ }
+
+ if ( mvalues != NULL ) {
+ if ( prv != NULL )
+ sieve_match_values_add(mvalues, mvalue);
+
+ chars = (const char *) str_data(mchars);
+
+ for ( i = 0; i < str_len(mchars); i++ ) {
+ sieve_match_values_add_char(mvalues, chars[i]);
+ }
+ }
+
+ if ( next_wcard != '*' ) {
+ debug_printf("failed to match at end of string\n");
+ break;
+ }
+ }
+ }
+
+ /* Check whether string ends in a wildcard
+ * (avoid scanning the rest of the string)
+ */
+ if ( kp == kend && next_wcard == '*' ) {
+ /* Add the rest of the string as match value */
+ if ( mvalues != NULL ) {
+ str_truncate(mvalue, 0);
+ str_append_data(mvalue, vp, vend-vp);
+ sieve_match_values_add(mvalues, mvalue);
+ }
+
+ /* Finish match */
+ kp = kend;
+ vp = vend;
+
+ debug_printf("key ends with '*'\n");
+ break;
+ }
+
+ debug_printf("== Loop ==\n");
+ }
+
+ /* Eat away a trailing series of *s */
+ if ( vp == vend ) {
+ while ( kp < kend && *kp == '*' ) kp++;
+ }
+
+ /* By definition, the match is only successful if both value and key pattern
+ * are exhausted.
+ */
+
+ debug_printf("=== Finish ===\n");
+ debug_printf(" result: %s\n", (kp == kend && vp == vend) ? "true" : "false");
+
+ if (kp == kend && vp == vend) {
+ /* Activate new match values after successful match */
+ if ( mvalues != NULL ) {
+ /* Set ${0} */
+ string_t *matched = str_new_const(pool_datastack_create(), val, val_size);
+ sieve_match_values_set(mvalues, 0, matched);
+
+ /* Commit new match values */
+ sieve_match_values_commit(mctx->runenv, &mvalues);
+ }
+ return 1;
+ }
+
+ /* No match; drop collected match values */
+ sieve_match_values_abort(&mvalues);
+ return 0;
+}
+
diff --git a/pigeonhole/src/lib-sieve/plugins/Makefile.am b/pigeonhole/src/lib-sieve/plugins/Makefile.am
new file mode 100644
index 0000000..2a1c054
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/Makefile.am
@@ -0,0 +1,32 @@
+if BUILD_UNFINISHED
+UNFINISHED =
+endif
+
+SUBDIRS = \
+ vacation \
+ subaddress \
+ comparator-i-ascii-numeric \
+ relational \
+ regex \
+ imap4flags \
+ copy \
+ include \
+ body \
+ variables \
+ enotify \
+ notify \
+ environment \
+ mailbox \
+ date \
+ spamvirustest \
+ ihave \
+ editheader \
+ duplicate \
+ index \
+ metadata \
+ mime \
+ special-use \
+ vnd.dovecot \
+ $(UNFINISHED)
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/Makefile.in b/pigeonhole/src/lib-sieve/plugins/Makefile.in
new file mode 100644
index 0000000..8443114
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/Makefile.in
@@ -0,0 +1,719 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@BUILD_UNFINISHED_TRUE@UNFINISHED =
+SUBDIRS = \
+ vacation \
+ subaddress \
+ comparator-i-ascii-numeric \
+ relational \
+ regex \
+ imap4flags \
+ copy \
+ include \
+ body \
+ variables \
+ enotify \
+ notify \
+ environment \
+ mailbox \
+ date \
+ spamvirustest \
+ ihave \
+ editheader \
+ duplicate \
+ index \
+ metadata \
+ mime \
+ special-use \
+ vnd.dovecot \
+ $(UNFINISHED)
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/body/Makefile.am b/pigeonhole/src/lib-sieve/plugins/body/Makefile.am
new file mode 100644
index 0000000..251b8d6
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/body/Makefile.am
@@ -0,0 +1,16 @@
+noinst_LTLIBRARIES = libsieve_ext_body.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+tsts = \
+ tst-body.c
+
+libsieve_ext_body_la_SOURCES = \
+ ext-body-common.c \
+ $(tsts) \
+ ext-body.c
+
+noinst_HEADERS = \
+ ext-body-common.h
diff --git a/pigeonhole/src/lib-sieve/plugins/body/Makefile.in b/pigeonhole/src/lib-sieve/plugins/body/Makefile.in
new file mode 100644
index 0000000..5d58bbd
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/body/Makefile.in
@@ -0,0 +1,692 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/body
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_body_la_LIBADD =
+am__objects_1 = tst-body.lo
+am_libsieve_ext_body_la_OBJECTS = ext-body-common.lo $(am__objects_1) \
+ ext-body.lo
+libsieve_ext_body_la_OBJECTS = $(am_libsieve_ext_body_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ext-body-common.Plo \
+ ./$(DEPDIR)/ext-body.Plo ./$(DEPDIR)/tst-body.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_body_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_body_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_body.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+tsts = \
+ tst-body.c
+
+libsieve_ext_body_la_SOURCES = \
+ ext-body-common.c \
+ $(tsts) \
+ ext-body.c
+
+noinst_HEADERS = \
+ ext-body-common.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/body/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/body/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_body.la: $(libsieve_ext_body_la_OBJECTS) $(libsieve_ext_body_la_DEPENDENCIES) $(EXTRA_libsieve_ext_body_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_body_la_OBJECTS) $(libsieve_ext_body_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-body-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-body.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-body.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ext-body-common.Plo
+ -rm -f ./$(DEPDIR)/ext-body.Plo
+ -rm -f ./$(DEPDIR)/tst-body.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ext-body-common.Plo
+ -rm -f ./$(DEPDIR)/ext-body.Plo
+ -rm -f ./$(DEPDIR)/tst-body.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/body/ext-body-common.c b/pigeonhole/src/lib-sieve/plugins/body/ext-body-common.c
new file mode 100644
index 0000000..c19940e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/body/ext-body-common.c
@@ -0,0 +1,102 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "mempool.h"
+#include "buffer.h"
+#include "array.h"
+#include "str.h"
+#include "istream.h"
+#include "mail-storage.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-message.h"
+#include "sieve-interpreter.h"
+
+#include "ext-body-common.h"
+
+
+/*
+ * Body part stringlist
+ */
+
+static int ext_body_stringlist_next_item
+ (struct sieve_stringlist *_strlist, string_t **str_r);
+static void ext_body_stringlist_reset
+ (struct sieve_stringlist *_strlist);
+
+struct ext_body_stringlist {
+ struct sieve_stringlist strlist;
+
+ struct sieve_message_part_data *body_parts;
+ struct sieve_message_part_data *body_parts_iter;
+};
+
+int ext_body_get_part_list
+(const struct sieve_runtime_env *renv, enum tst_body_transform transform,
+ const char * const *content_types, struct sieve_stringlist **strlist_r)
+{
+ static const char * const _no_content_types[] = { "", NULL };
+ struct ext_body_stringlist *strlist;
+ struct sieve_message_part_data *body_parts = NULL;
+ int ret;
+
+ *strlist_r = NULL;
+
+ if ( content_types == NULL ) content_types = _no_content_types;
+
+ switch ( transform ) {
+ case TST_BODY_TRANSFORM_RAW:
+ if ( (ret=sieve_message_body_get_raw(renv, &body_parts)) <= 0 )
+ return ret;
+ break;
+ case TST_BODY_TRANSFORM_CONTENT:
+ if ( (ret=sieve_message_body_get_content
+ (renv, content_types, &body_parts)) <= 0 )
+ return ret;
+ break;
+ case TST_BODY_TRANSFORM_TEXT:
+ if ( (ret=sieve_message_body_get_text(renv, &body_parts)) <= 0 )
+ return ret;
+ break;
+ default:
+ i_unreached();
+ }
+
+ strlist = t_new(struct ext_body_stringlist, 1);
+ strlist->strlist.runenv = renv;
+ strlist->strlist.next_item = ext_body_stringlist_next_item;
+ strlist->strlist.reset = ext_body_stringlist_reset;
+ strlist->body_parts = body_parts;
+ strlist->body_parts_iter = body_parts;
+
+ *strlist_r = &strlist->strlist;
+ return SIEVE_EXEC_OK;
+}
+
+static int ext_body_stringlist_next_item
+(struct sieve_stringlist *_strlist, string_t **str_r)
+{
+ struct ext_body_stringlist *strlist =
+ (struct ext_body_stringlist *)_strlist;
+
+ *str_r = NULL;
+
+ if ( strlist->body_parts_iter->content == NULL ) return 0;
+
+ *str_r = t_str_new_const
+ (strlist->body_parts_iter->content, strlist->body_parts_iter->size);
+ strlist->body_parts_iter++;
+ return 1;
+}
+
+static void ext_body_stringlist_reset
+(struct sieve_stringlist *_strlist)
+{
+ struct ext_body_stringlist *strlist =
+ (struct ext_body_stringlist *)_strlist;
+
+ strlist->body_parts_iter = strlist->body_parts;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/body/ext-body-common.h b/pigeonhole/src/lib-sieve/plugins/body/ext-body-common.h
new file mode 100644
index 0000000..290ca13
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/body/ext-body-common.h
@@ -0,0 +1,40 @@
+#ifndef EXT_BODY_COMMON_H
+#define EXT_BODY_COMMON_H
+
+/*
+ * Types
+ */
+
+enum tst_body_transform {
+ TST_BODY_TRANSFORM_RAW,
+ TST_BODY_TRANSFORM_CONTENT,
+ TST_BODY_TRANSFORM_TEXT
+};
+
+/*
+ * Extension
+ */
+
+extern const struct sieve_extension_def body_extension;
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def body_test;
+
+/*
+ * Operations
+ */
+
+extern const struct sieve_operation_def body_operation;
+
+/*
+ * Message body part extraction
+ */
+
+int ext_body_get_part_list
+ (const struct sieve_runtime_env *renv, enum tst_body_transform transform,
+ const char * const *content_types, struct sieve_stringlist **strlist_r);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/body/ext-body.c b/pigeonhole/src/lib-sieve/plugins/body/ext-body.c
new file mode 100644
index 0000000..27218bd
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/body/ext-body.c
@@ -0,0 +1,54 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension body
+ * ------------------
+ *
+ * Authors: Stephan Bosch
+ * Original CMUSieve implementation by Timo Sirainen
+ * Specification: RFC 5173
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "lib.h"
+#include "array.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-address-parts.h"
+
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-body-common.h"
+
+/*
+ * Extension
+ */
+
+static bool ext_body_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def body_extension = {
+ .name = "body",
+ .validator_load = ext_body_validator_load,
+ SIEVE_EXT_DEFINE_OPERATION(body_operation)
+};
+
+static bool ext_body_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Register new test */
+ sieve_validator_register_command(valdtr, ext, &body_test);
+
+ return TRUE;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/body/tst-body.c b/pigeonhole/src/lib-sieve/plugins/body/tst-body.c
new file mode 100644
index 0000000..f08dd54
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/body/tst-body.c
@@ -0,0 +1,385 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-address-parts.h"
+
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-match.h"
+
+#include "ext-body-common.h"
+
+/*
+ * Body test
+ *
+ * Syntax
+ * body [COMPARATOR] [MATCH-TYPE] [BODY-TRANSFORM]
+ * <key-list: string-list>
+ */
+
+static bool tst_body_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool tst_body_validate
+ (struct sieve_validator *valdtr, struct sieve_command *tst);
+static bool tst_body_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+const struct sieve_command_def body_test = {
+ .identifier = "body",
+ .type = SCT_TEST,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_body_registered,
+ .validate = tst_body_validate,
+ .generate = tst_body_generate
+};
+
+/*
+ * Body operation
+ */
+
+static bool ext_body_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int ext_body_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def body_operation = {
+ .mnemonic = "body",
+ .ext_def = &body_extension,
+ .dump = ext_body_operation_dump,
+ .execute = ext_body_operation_execute
+};
+
+/*
+ * Optional operands
+ */
+
+enum tst_body_optional {
+ OPT_BODY_TRANSFORM = SIEVE_MATCH_OPT_LAST
+};
+
+/*
+ * Tagged arguments
+ */
+
+/* Forward declarations */
+
+static bool tag_body_transform_validate
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool tag_body_transform_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd);
+
+/* Argument objects */
+
+static const struct sieve_argument_def body_raw_tag = {
+ .identifier = "raw",
+ .validate = tag_body_transform_validate,
+ .generate = tag_body_transform_generate
+};
+
+static const struct sieve_argument_def body_content_tag = {
+ .identifier = "content",
+ .validate = tag_body_transform_validate,
+ .generate = tag_body_transform_generate
+};
+
+static const struct sieve_argument_def body_text_tag = {
+ .identifier = "text",
+ .validate = tag_body_transform_validate,
+ .generate = tag_body_transform_generate
+};
+
+/* Argument implementation */
+
+static bool tag_body_transform_validate
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ enum tst_body_transform transform;
+ struct sieve_ast_argument *tag = *arg;
+
+ /* BODY-TRANSFORM:
+ * :raw
+ * / :content <content-types: string-list>
+ * / :text
+ */
+ if ( (bool) cmd->data ) {
+ sieve_argument_validate_error(valdtr, *arg,
+ "the :raw, :content and :text arguments for the body test are mutually "
+ "exclusive, but more than one was specified");
+ return FALSE;
+ }
+
+ /* Skip tag */
+ *arg = sieve_ast_argument_next(*arg);
+
+ /* :content tag has a string-list argument */
+ if ( sieve_argument_is(tag, body_raw_tag) )
+ transform = TST_BODY_TRANSFORM_RAW;
+
+ else if ( sieve_argument_is(tag, body_text_tag) )
+ transform = TST_BODY_TRANSFORM_TEXT;
+
+ else if ( sieve_argument_is(tag, body_content_tag) ) {
+ /* Check syntax:
+ * :content <content-types: string-list>
+ */
+ if ( !sieve_validate_tag_parameter
+ (valdtr, cmd, tag, *arg, NULL, 0, SAAT_STRING_LIST, FALSE) ) {
+ return FALSE;
+ }
+
+ /* Assign tag parameters */
+ tag->parameters = *arg;
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ transform = TST_BODY_TRANSFORM_CONTENT;
+ } else
+ return FALSE;
+
+ /* Signal the presence of this tag */
+ cmd->data = (void *) TRUE;
+
+ /* Assign context data */
+ tag->argument->data = (void *) transform;
+
+ return TRUE;
+}
+
+/*
+ * Command Registration
+ */
+
+static bool tst_body_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ /* The order of these is not significant */
+ sieve_comparators_link_tag(valdtr, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
+ sieve_match_types_link_tags(valdtr, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
+
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, ext, &body_raw_tag, OPT_BODY_TRANSFORM);
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, ext, &body_content_tag, OPT_BODY_TRANSFORM);
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, ext, &body_text_tag, OPT_BODY_TRANSFORM);
+
+ return TRUE;
+}
+
+/*
+ * Validation
+ */
+
+static bool tst_body_validate
+(struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+ const struct sieve_match_type mcht_default =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ const struct sieve_comparator cmp_default =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "key list", 1, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ /* Validate the key argument to a specified match type */
+ return sieve_match_type_validate
+ (valdtr, tst, arg, &mcht_default, &cmp_default);
+}
+
+/*
+ * Code generation
+ */
+
+static bool tst_body_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ (void)sieve_operation_emit(cgenv->sblock, cmd->ext, &body_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, cmd, NULL);
+}
+
+static bool tag_body_transform_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ enum tst_body_transform transform =
+ POINTER_CAST_TO(arg->argument->data, enum tst_body_transform);
+
+ sieve_binary_emit_byte(cgenv->sblock, transform);
+ sieve_generate_argument_parameters(cgenv, cmd, arg);
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool ext_body_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ unsigned int transform;
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "BODY");
+ sieve_code_descend(denv);
+
+ /* Handle any optional arguments */
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_match_opr_optional_dump(denv, address, &opt_code))
+ < 0 )
+ return FALSE;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_BODY_TRANSFORM:
+ if ( !sieve_binary_read_byte(denv->sblock, address, &transform) )
+ return FALSE;
+
+ switch ( transform ) {
+ case TST_BODY_TRANSFORM_RAW:
+ sieve_code_dumpf(denv, "BODY-TRANSFORM: RAW");
+ break;
+ case TST_BODY_TRANSFORM_TEXT:
+ sieve_code_dumpf(denv, "BODY-TRANSFORM: TEXT");
+ break;
+ case TST_BODY_TRANSFORM_CONTENT:
+ sieve_code_dumpf(denv, "BODY-TRANSFORM: CONTENT");
+
+ sieve_code_descend(denv);
+ if ( !sieve_opr_stringlist_dump(denv, address, "content types") )
+ return FALSE;
+ sieve_code_ascend(denv);
+ break;
+ default:
+ return FALSE;
+ }
+ break;
+ default:
+ return FALSE;
+ }
+ };
+
+ return sieve_opr_stringlist_dump(denv, address, "key list");
+}
+
+/*
+ * Interpretation
+ */
+
+static int ext_body_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ int opt_code = 0;
+ struct sieve_comparator cmp =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+ struct sieve_match_type mcht =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ unsigned int transform = TST_BODY_TRANSFORM_TEXT;
+ struct sieve_stringlist *ctype_list, *value_list, *key_list;
+ bool mvalues_active;
+ const char * const *content_types = NULL;
+ int match, ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Optional operands */
+
+ ctype_list = NULL;
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_match_opr_optional_read
+ (renv, address, &opt_code, &ret, &cmp, &mcht)) < 0 )
+ return ret;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_BODY_TRANSFORM:
+ if ( !sieve_binary_read_byte(renv->sblock, address, &transform) ||
+ transform > TST_BODY_TRANSFORM_TEXT ) {
+ sieve_runtime_trace_error(renv, "invalid body transform type");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if ( transform == TST_BODY_TRANSFORM_CONTENT &&
+ (ret=sieve_opr_stringlist_read
+ (renv, address, "content-type-list", &ctype_list)) <= 0 )
+ return ret;
+
+ break;
+
+ default:
+ sieve_runtime_trace_error(renv, "unknown optional operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ }
+
+ /* Read key-list */
+
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "key-list", &key_list))
+ <= 0 )
+ return ret;
+
+ if ( ctype_list != NULL && sieve_stringlist_read_all
+ (ctype_list, pool_datastack_create(), &content_types) < 0 ) {
+ sieve_runtime_trace_error(renv, "failed to read content-type-list operand");
+ return ctype_list->exec_status;
+ }
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "body test");
+
+ /* Extract requested parts */
+ if ( (ret=ext_body_get_part_list(renv,
+ (enum tst_body_transform) transform, content_types,&value_list)) <= 0 )
+ return ret;
+
+ /* Disable match values processing as required by RFC */
+ mvalues_active = sieve_match_values_set_enabled(renv, FALSE);
+
+ /* Perform match */
+ match = sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret);
+
+ /* Restore match values processing */
+ (void)sieve_match_values_set_enabled(renv, mvalues_active);
+
+ if ( match < 0 )
+ return ret;
+
+ /* Set test result for subsequent conditional jump */
+ sieve_interpreter_set_test_result(renv->interp, match > 0);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile.am b/pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile.am
new file mode 100644
index 0000000..8e385c5
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile.am
@@ -0,0 +1,8 @@
+noinst_LTLIBRARIES = libsieve_ext_comparator-i-ascii-numeric.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+libsieve_ext_comparator_i_ascii_numeric_la_SOURCES = \
+ ext-cmp-i-ascii-numeric.c
diff --git a/pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile.in b/pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile.in
new file mode 100644
index 0000000..35ef51f
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile.in
@@ -0,0 +1,674 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/comparator-i-ascii-numeric
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_comparator_i_ascii_numeric_la_LIBADD =
+am_libsieve_ext_comparator_i_ascii_numeric_la_OBJECTS = \
+ ext-cmp-i-ascii-numeric.lo
+libsieve_ext_comparator_i_ascii_numeric_la_OBJECTS = \
+ $(am_libsieve_ext_comparator_i_ascii_numeric_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ext-cmp-i-ascii-numeric.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_comparator_i_ascii_numeric_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_comparator_i_ascii_numeric_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_comparator-i-ascii-numeric.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+libsieve_ext_comparator_i_ascii_numeric_la_SOURCES = \
+ ext-cmp-i-ascii-numeric.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/comparator-i-ascii-numeric/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_comparator-i-ascii-numeric.la: $(libsieve_ext_comparator_i_ascii_numeric_la_OBJECTS) $(libsieve_ext_comparator_i_ascii_numeric_la_DEPENDENCIES) $(EXTRA_libsieve_ext_comparator_i_ascii_numeric_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_comparator_i_ascii_numeric_la_OBJECTS) $(libsieve_ext_comparator_i_ascii_numeric_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-cmp-i-ascii-numeric.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ext-cmp-i-ascii-numeric.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ext-cmp-i-ascii-numeric.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c b/pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
new file mode 100644
index 0000000..20ec38b
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
@@ -0,0 +1,160 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension comparator-i;ascii-numeric
+ * ------------------------------------
+ *
+ * Author: Stephan Bosch
+ * Specification: RFC 2244
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "sieve-common.h"
+
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-comparators.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+#include <ctype.h>
+
+/*
+ * Forward declarations
+ */
+
+static const struct sieve_operand_def my_comparator_operand;
+
+const struct sieve_comparator_def i_ascii_numeric_comparator;
+
+/*
+ * Extension
+ */
+
+static bool ext_cmp_i_ascii_numeric_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *validator);
+
+const struct sieve_extension_def comparator_i_ascii_numeric_extension = {
+ .name = "comparator-i;ascii-numeric",
+ .validator_load = ext_cmp_i_ascii_numeric_validator_load,
+ SIEVE_EXT_DEFINE_OPERAND(my_comparator_operand)
+};
+
+static bool ext_cmp_i_ascii_numeric_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *validator)
+{
+ sieve_comparator_register(validator, ext, &i_ascii_numeric_comparator);
+ return TRUE;
+}
+
+/*
+ * Operand
+ */
+
+static const struct sieve_extension_objects ext_comparators =
+ SIEVE_EXT_DEFINE_COMPARATOR(i_ascii_numeric_comparator);
+
+static const struct sieve_operand_def my_comparator_operand = {
+ .name = "comparator-i;ascii-numeric",
+ .ext_def = &comparator_i_ascii_numeric_extension,
+ .class = &sieve_comparator_operand_class,
+ .interface = &ext_comparators
+};
+
+/*
+ * Comparator
+ */
+
+/* Forward declarations */
+
+static int cmp_i_ascii_numeric_compare
+ (const struct sieve_comparator *cmp,
+ const char *val1, size_t val1_size, const char *val2, size_t val2_size);
+
+/* Comparator object */
+
+const struct sieve_comparator_def i_ascii_numeric_comparator = {
+ SIEVE_OBJECT("i;ascii-numeric",
+ &my_comparator_operand, 0),
+ .flags =
+ SIEVE_COMPARATOR_FLAG_ORDERING |
+ SIEVE_COMPARATOR_FLAG_EQUALITY,
+ .compare = cmp_i_ascii_numeric_compare
+};
+
+/* Comparator implementation */
+
+static int cmp_i_ascii_numeric_compare
+ (const struct sieve_comparator *cmp ATTR_UNUSED,
+ const char *val, size_t val_size, const char *key, size_t key_size)
+{
+ const char *vend = val + val_size;
+ const char *kend = key + key_size;
+ const char *vp = val;
+ const char *kp = key;
+ int digits, i;
+
+ /* RFC 4790: All input is valid; strings that do not start with a digit
+ * represent positive infinity.
+ */
+ if ( !i_isdigit(*vp) ) {
+ if ( i_isdigit(*kp) ) {
+ /* Value is greater */
+ return 1;
+ }
+ } else {
+ if ( !i_isdigit(*kp) ) {
+ /* Value is less */
+ return -1;
+ }
+ }
+
+ /* Ignore leading zeros */
+
+ while ( *vp == '0' && vp < vend )
+ vp++;
+
+ while ( *kp == '0' && kp < kend )
+ kp++;
+
+ /* Check whether both numbers are equally long in terms of digits */
+
+ digits = 0;
+ while ( vp < vend && kp < kend && i_isdigit(*vp) && i_isdigit(*kp) ) {
+ vp++;
+ kp++;
+ digits++;
+ }
+
+ if ( vp == vend || !i_isdigit(*vp) ) {
+ if ( kp != kend && i_isdigit(*kp) ) {
+ /* Value is less */
+ return -1;
+ }
+ } else {
+ /* Value is greater */
+ return 1;
+ }
+
+ /* Equally long: compare digits */
+
+ vp -= digits;
+ kp -= digits;
+ i = 0;
+ while ( i < digits ) {
+ if ( *vp > *kp )
+ return 1;
+ else if ( *vp < *kp )
+ return -1;
+
+ kp++;
+ vp++;
+ i++;
+ }
+
+ return 0;
+}
+
diff --git a/pigeonhole/src/lib-sieve/plugins/copy/Makefile.am b/pigeonhole/src/lib-sieve/plugins/copy/Makefile.am
new file mode 100644
index 0000000..483032a
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/copy/Makefile.am
@@ -0,0 +1,18 @@
+noinst_LTLIBRARIES = libsieve_ext_copy.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+libsieve_ext_copy_la_SOURCES = \
+ ext-copy.c
+
+public_headers = \
+ sieve-ext-copy.h
+
+headers =
+
+pkginc_libdir=$(dovecot_pkgincludedir)/sieve
+pkginc_lib_HEADERS = $(public_headers)
+noinst_HEADERS = $(headers)
+
diff --git a/pigeonhole/src/lib-sieve/plugins/copy/Makefile.in b/pigeonhole/src/lib-sieve/plugins/copy/Makefile.in
new file mode 100644
index 0000000..9824089
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/copy/Makefile.in
@@ -0,0 +1,735 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/copy
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(pkginc_lib_HEADERS) $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_copy_la_LIBADD =
+am_libsieve_ext_copy_la_OBJECTS = ext-copy.lo
+libsieve_ext_copy_la_OBJECTS = $(am_libsieve_ext_copy_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ext-copy.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_copy_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_copy_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkginc_libdir)"
+HEADERS = $(noinst_HEADERS) $(pkginc_lib_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_copy.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+libsieve_ext_copy_la_SOURCES = \
+ ext-copy.c
+
+public_headers = \
+ sieve-ext-copy.h
+
+headers =
+pkginc_libdir = $(dovecot_pkgincludedir)/sieve
+pkginc_lib_HEADERS = $(public_headers)
+noinst_HEADERS = $(headers)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/copy/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/copy/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_copy.la: $(libsieve_ext_copy_la_OBJECTS) $(libsieve_ext_copy_la_DEPENDENCIES) $(EXTRA_libsieve_ext_copy_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_copy_la_OBJECTS) $(libsieve_ext_copy_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-copy.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
+ done
+
+uninstall-pkginc_libHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(pkginc_libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ext-copy.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkginc_libHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ext-copy.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkginc_libHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-pkginc_libHEADERS install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-pkginc_libHEADERS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/copy/ext-copy.c b/pigeonhole/src/lib-sieve/plugins/copy/ext-copy.c
new file mode 100644
index 0000000..e7db9dd
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/copy/ext-copy.c
@@ -0,0 +1,183 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension copy
+ * --------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 3894
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "sieve-common.h"
+
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-actions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-result.h"
+
+#include "sieve-ext-copy.h"
+
+/*
+ * Forward declarations
+ */
+
+static const struct sieve_argument_def copy_tag;
+static const struct sieve_operand_def copy_side_effect_operand;
+
+/*
+ * Extension
+ */
+
+static bool
+ext_copy_validator_load(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr);
+
+const struct sieve_extension_def copy_extension = {
+ .name = "copy",
+ .validator_load = ext_copy_validator_load,
+ SIEVE_EXT_DEFINE_OPERAND(copy_side_effect_operand),
+};
+
+static bool
+ext_copy_validator_load(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr)
+{
+ /* Register copy tag with redirect and fileinto commands and we don't
+ care whether these commands are registered or even whether they will
+ be registered at all. The validator handles either situation
+ gracefully.
+ */
+ sieve_validator_register_external_tag(valdtr, "redirect", ext,
+ &copy_tag, SIEVE_OPT_SIDE_EFFECT);
+ sieve_validator_register_external_tag(valdtr, "fileinto", ext,
+ &copy_tag, SIEVE_OPT_SIDE_EFFECT);
+ return TRUE;
+}
+
+/*
+ * Side effect
+ */
+
+static void
+seff_copy_print(const struct sieve_side_effect *seffect,
+ const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv, bool *keep);
+static int
+seff_copy_post_execute(const struct sieve_side_effect *seffect ATTR_UNUSED,
+ const struct sieve_action_exec_env *aenv ATTR_UNUSED,
+ void *tr_context ATTR_UNUSED,
+ void *se_tr_context ATTR_UNUSED, bool *keep);
+
+const struct sieve_side_effect_def copy_side_effect = {
+ SIEVE_OBJECT("copy", &copy_side_effect_operand, 0),
+ .to_action = &act_store,
+ .print = seff_copy_print,
+ .post_execute = seff_copy_post_execute,
+};
+
+/*
+ * Tagged argument
+ */
+
+static bool
+tag_copy_validate(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg, struct sieve_command *cmd);
+static bool
+tag_copy_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_argument *arg, struct sieve_command *cmd);
+
+static const struct sieve_argument_def copy_tag = {
+ .identifier = "copy",
+ .validate = tag_copy_validate,
+ .generate = tag_copy_generate,
+};
+
+/*
+ * Operand
+ */
+
+static const struct sieve_extension_objects ext_side_effects =
+ SIEVE_EXT_DEFINE_SIDE_EFFECT(copy_side_effect);
+
+static const struct sieve_operand_def copy_side_effect_operand = {
+ .name = "copy operand",
+ .ext_def = &copy_extension,
+ .class = &sieve_side_effect_operand_class,
+ .interface = &ext_side_effects,
+};
+
+/*
+ * Tag registration
+ */
+
+void sieve_ext_copy_register_tag(struct sieve_validator *valdtr,
+ const struct sieve_extension *copy_ext,
+ const char *command)
+{
+ if (sieve_validator_extension_loaded(valdtr, copy_ext)) {
+ sieve_validator_register_external_tag(
+ valdtr, command, copy_ext, &copy_tag,
+ SIEVE_OPT_SIDE_EFFECT);
+ }
+}
+
+/*
+ * Tag validation
+ */
+
+static bool
+tag_copy_validate(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_ast_argument **arg ATTR_UNUSED,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+tag_copy_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_argument *arg,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ if (sieve_ast_argument_type(arg) != SAAT_TAG)
+ return FALSE;
+
+ sieve_opr_side_effect_emit(cgenv->sblock, sieve_argument_ext(arg),
+ &copy_side_effect);
+ return TRUE;
+}
+
+/*
+ * Side effect implementation
+ */
+
+static void
+seff_copy_print(const struct sieve_side_effect *seffect ATTR_UNUSED,
+ const struct sieve_action *action ATTR_UNUSED,
+ const struct sieve_result_print_env *rpenv, bool *keep)
+{
+ sieve_result_seffect_printf(rpenv, "preserve implicit keep");
+ *keep = TRUE;
+}
+
+static int
+seff_copy_post_execute(const struct sieve_side_effect *seffect ATTR_UNUSED,
+ const struct sieve_action_exec_env *aenv ATTR_UNUSED,
+ void *tr_context ATTR_UNUSED,
+ void *se_tr_context ATTR_UNUSED, bool *keep)
+{
+ *keep = TRUE;
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/copy/sieve-ext-copy.h b/pigeonhole/src/lib-sieve/plugins/copy/sieve-ext-copy.h
new file mode 100644
index 0000000..faf19dc
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/copy/sieve-ext-copy.h
@@ -0,0 +1,21 @@
+#ifndef SIEVE_EXT_COPY_H
+#define SIEVE_EXT_COPY_H
+
+/* sieve_ext_copy_get_extension():
+ * Get the extension struct for the copy extension.
+ */
+static inline const struct sieve_extension *sieve_ext_copy_get_extension
+(struct sieve_instance *svinst)
+{
+ return sieve_extension_get_by_name(svinst, "copy");
+}
+
+/* sieve_ext_copy_register_tag():
+ * Register the :copy tagged argument for a command other than fileinto and
+ * redirect.
+ */
+void sieve_ext_copy_register_tag
+ (struct sieve_validator *valdtr, const struct sieve_extension *copy_ext,
+ const char *command);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/date/Makefile.am b/pigeonhole/src/lib-sieve/plugins/date/Makefile.am
new file mode 100644
index 0000000..bf257ac
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/date/Makefile.am
@@ -0,0 +1,16 @@
+noinst_LTLIBRARIES = libsieve_ext_date.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+tests = \
+ tst-date.c
+
+libsieve_ext_date_la_SOURCES = \
+ $(tests) \
+ ext-date-common.c \
+ ext-date.c
+
+noinst_HEADERS = \
+ ext-date-common.h
diff --git a/pigeonhole/src/lib-sieve/plugins/date/Makefile.in b/pigeonhole/src/lib-sieve/plugins/date/Makefile.in
new file mode 100644
index 0000000..0bc3ec0
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/date/Makefile.in
@@ -0,0 +1,692 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/date
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_date_la_LIBADD =
+am__objects_1 = tst-date.lo
+am_libsieve_ext_date_la_OBJECTS = $(am__objects_1) ext-date-common.lo \
+ ext-date.lo
+libsieve_ext_date_la_OBJECTS = $(am_libsieve_ext_date_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ext-date-common.Plo \
+ ./$(DEPDIR)/ext-date.Plo ./$(DEPDIR)/tst-date.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_date_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_date_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_date.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+tests = \
+ tst-date.c
+
+libsieve_ext_date_la_SOURCES = \
+ $(tests) \
+ ext-date-common.c \
+ ext-date.c
+
+noinst_HEADERS = \
+ ext-date-common.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/date/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/date/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_date.la: $(libsieve_ext_date_la_OBJECTS) $(libsieve_ext_date_la_DEPENDENCIES) $(EXTRA_libsieve_ext_date_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_date_la_OBJECTS) $(libsieve_ext_date_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-date-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-date.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-date.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ext-date-common.Plo
+ -rm -f ./$(DEPDIR)/ext-date.Plo
+ -rm -f ./$(DEPDIR)/tst-date.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ext-date-common.Plo
+ -rm -f ./$(DEPDIR)/ext-date.Plo
+ -rm -f ./$(DEPDIR)/tst-date.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/date/ext-date-common.c b/pigeonhole/src/lib-sieve/plugins/date/ext-date-common.c
new file mode 100644
index 0000000..7493b87
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/date/ext-date-common.c
@@ -0,0 +1,593 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "utc-offset.h"
+#include "str.h"
+#include "iso8601-date.h"
+#include "message-date.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-interpreter.h"
+#include "sieve-message.h"
+
+#include "ext-date-common.h"
+
+#include <time.h>
+#include <ctype.h>
+
+struct ext_date_context {
+ time_t current_date;
+ int zone_offset;
+};
+
+/*
+ * Runtime initialization
+ */
+
+static int ext_date_runtime_init
+(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ void *context ATTR_UNUSED, bool deferred ATTR_UNUSED)
+{
+ struct ext_date_context *dctx;
+ pool_t pool;
+ struct timeval msg_time;
+ time_t current_date;
+ struct tm *tm;
+ int zone_offset;
+
+ /* Get current time at instance main script is started */
+ sieve_message_context_time(renv->msgctx, &msg_time);
+ current_date = msg_time.tv_sec;
+
+ tm = localtime(&current_date);
+ zone_offset = utc_offset(tm, current_date);
+
+ /* Create context */
+ pool = sieve_message_context_pool(renv->msgctx);
+ dctx = p_new(pool, struct ext_date_context, 1);
+ dctx->current_date = current_date;
+ dctx->zone_offset = zone_offset;
+
+ sieve_message_context_extension_set
+ (renv->msgctx, ext, (void *) dctx);
+ return SIEVE_EXEC_OK;
+}
+
+static struct sieve_interpreter_extension
+date_interpreter_extension = {
+ .ext_def = &date_extension,
+ .run = ext_date_runtime_init
+};
+
+bool ext_date_interpreter_load
+(const struct sieve_extension *ext, const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ /* Register runtime hook to obtain stript start timestamp */
+ if ( renv->msgctx == NULL ||
+ sieve_message_context_extension_get(renv->msgctx, ext) == NULL ) {
+ sieve_interpreter_extension_register
+ (renv->interp, ext, &date_interpreter_extension, NULL);
+ }
+
+ return TRUE;
+}
+
+/*
+ * Zone string
+ */
+
+bool ext_date_parse_timezone
+(const char *zone, int *zone_offset_r)
+{
+ const unsigned char *str = (const unsigned char *) zone;
+ size_t len = strlen(zone);
+
+ if (len == 5 && (*str == '+' || *str == '-')) {
+ int offset;
+
+ if (!i_isdigit(str[1]) || !i_isdigit(str[2]) ||
+ !i_isdigit(str[3]) || !i_isdigit(str[4]))
+ return FALSE;
+
+ offset = ((str[1]-'0') * 10 + (str[2]-'0')) * 60 +
+ (str[3]-'0') * 10 + (str[4]-'0');
+
+ if ( zone_offset_r != NULL )
+ *zone_offset_r = *str == '+' ? offset : -offset;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * Current date
+ */
+
+time_t ext_date_get_current_date
+(const struct sieve_runtime_env *renv, int *zone_offset_r)
+{
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ struct ext_date_context *dctx = (struct ext_date_context *)
+ sieve_message_context_extension_get(renv->msgctx, this_ext);
+
+ if ( dctx == NULL ) {
+ ext_date_runtime_init(this_ext, renv, NULL, FALSE);
+ dctx = (struct ext_date_context *)
+ sieve_message_context_extension_get(renv->msgctx, this_ext);
+
+ i_assert(dctx != NULL);
+ }
+
+ /* Read script start timestamp from message context */
+
+ if ( zone_offset_r != NULL )
+ *zone_offset_r = dctx->zone_offset;
+
+ return dctx->current_date;
+}
+
+/*
+ * Date parts
+ */
+
+/* "year" => the year, "0000" .. "9999".
+ */
+
+static const char *ext_date_year_part_get(struct tm *tm, int zone_offset);
+
+static const struct ext_date_part year_date_part = {
+ "year",
+ ext_date_year_part_get
+};
+
+/* "month" => the month, "01" .. "12".
+ */
+
+static const char *ext_date_month_part_get(struct tm *tm, int zone_offset);
+
+static const struct ext_date_part month_date_part = {
+ "month",
+ ext_date_month_part_get
+};
+
+/* "day" => the day, "01" .. "31".
+ */
+
+static const char *ext_date_day_part_get(struct tm *tm, int zone_offset);
+
+static const struct ext_date_part day_date_part = {
+ "day",
+ ext_date_day_part_get
+};
+
+/* "date" => the date in "yyyy-mm-dd" format.
+ */
+
+static const char *ext_date_date_part_get(struct tm *tm, int zone_offset);
+
+static const struct ext_date_part date_date_part = {
+ "date",
+ ext_date_date_part_get
+};
+
+/* "julian" => the Modified Julian Day, that is, the date
+ * expressed as an integer number of days since
+ * 00:00 UTC on November 17, 1858 (using the Gregorian
+ * calendar). This corresponds to the regular
+ * Julian Day minus 2400000.5. Sample routines to
+ * convert to and from modified Julian dates are
+ * given in Appendix A.
+ */
+
+static const char *ext_date_julian_part_get(struct tm *tm, int zone_offset);
+
+static const struct ext_date_part julian_date_part = {
+ "julian",
+ ext_date_julian_part_get
+};
+
+/* "hour" => the hour, "00" .. "23".
+ */
+static const char *ext_date_hour_part_get(struct tm *tm, int zone_offset);
+
+static const struct ext_date_part hour_date_part = {
+ "hour",
+ ext_date_hour_part_get
+};
+
+/* "minute" => the minute, "00" .. "59".
+ */
+static const char *ext_date_minute_part_get(struct tm *tm, int zone_offset);
+
+static const struct ext_date_part minute_date_part = {
+ "minute",
+ ext_date_minute_part_get
+};
+
+/* "second" => the second, "00" .. "60".
+ */
+static const char *ext_date_second_part_get(struct tm *tm, int zone_offset);
+
+static const struct ext_date_part second_date_part = {
+ "second",
+ ext_date_second_part_get
+};
+
+/* "time" => the time in "hh:mm:ss" format.
+ */
+static const char *ext_date_time_part_get(struct tm *tm, int zone_offset);
+
+static const struct ext_date_part time_date_part = {
+ "time",
+ ext_date_time_part_get
+};
+
+/* "iso8601" => the date and time in restricted ISO 8601 format.
+ */
+static const char *ext_date_iso8601_part_get(struct tm *tm, int zone_offset);
+
+static const struct ext_date_part iso8601_date_part = {
+ "iso8601",
+ ext_date_iso8601_part_get
+};
+
+/* "std11" => the date and time in a format appropriate
+ * for use in a Date: header field [RFC2822].
+ */
+static const char *ext_date_std11_part_get(struct tm *tm, int zone_offset);
+
+static const struct ext_date_part std11_date_part = {
+ "std11",
+ ext_date_std11_part_get
+};
+
+/* "zone" => the time zone in use. If the user specified a
+ * time zone with ":zone", "zone" will
+ * contain that value. If :originalzone is specified
+ * this value will be the original zone specified
+ * in the date-time value. If neither argument is
+ * specified the value will be the server's default
+ * time zone in offset format "+hhmm" or "-hhmm". An
+ * offset of 0 (Zulu) always has a positive sign.
+ */
+static const char *ext_date_zone_part_get(struct tm *tm, int zone_offset);
+
+static const struct ext_date_part zone_date_part = {
+ "zone",
+ ext_date_zone_part_get
+};
+
+/* "weekday" => the day of the week expressed as an integer between
+ * "0" and "6". "0" is Sunday, "1" is Monday, etc.
+ */
+static const char *ext_date_weekday_part_get(struct tm *tm, int zone_offset);
+
+static const struct ext_date_part weekday_date_part = {
+ "weekday",
+ ext_date_weekday_part_get
+};
+
+/*
+ * Date part extraction
+ */
+
+static const struct ext_date_part *date_parts[] = {
+ &year_date_part, &month_date_part, &day_date_part, &date_date_part,
+ &julian_date_part, &hour_date_part, &minute_date_part, &second_date_part,
+ &time_date_part, &iso8601_date_part, &std11_date_part, &zone_date_part,
+ &weekday_date_part
+};
+
+unsigned int date_parts_count = N_ELEMENTS(date_parts);
+
+const struct ext_date_part *ext_date_part_find(const char *part)
+{
+ unsigned int i;
+
+ for ( i = 0; i < date_parts_count; i++ ) {
+ if ( strcasecmp(date_parts[i]->identifier, part) == 0 ) {
+ return date_parts[i];
+ }
+ }
+
+ return NULL;
+}
+
+const char *ext_date_part_extract
+(const struct ext_date_part *dpart, struct tm *tm, int zone_offset)
+{
+ if ( dpart == NULL || dpart->get_string == NULL )
+ return NULL;
+
+ return dpart->get_string(tm, zone_offset);
+}
+
+/*
+ * Date part implementations
+ */
+
+static const char *month_names[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static const char *weekday_names[] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+
+static const char *ext_date_year_part_get
+(struct tm *tm, int zone_offset ATTR_UNUSED)
+{
+ return t_strdup_printf("%04d", tm->tm_year + 1900);
+}
+
+static const char *ext_date_month_part_get
+(struct tm *tm, int zone_offset ATTR_UNUSED)
+{
+ return t_strdup_printf("%02d", tm->tm_mon + 1);
+}
+
+static const char *ext_date_day_part_get
+(struct tm *tm, int zone_offset ATTR_UNUSED)
+{
+ return t_strdup_printf("%02d", tm->tm_mday);
+}
+
+static const char *ext_date_date_part_get
+(struct tm *tm, int zone_offset ATTR_UNUSED)
+{
+ return t_strdup_printf("%04d-%02d-%02d",
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
+}
+
+static const char *ext_date_julian_part_get
+(struct tm *tm, int zone_offset ATTR_UNUSED)
+{
+ int year = tm->tm_year+1900;
+ int month = tm->tm_mon+1;
+ int day = tm->tm_mday;
+ int c, ya, jd;
+
+ /* Modified from RFC 5260 Appendix A (refer to Errata) */
+
+ if ( month > 2 )
+ month -= 3;
+ else {
+ month += 9;
+ year--;
+ }
+
+ c = year / 100;
+ ya = year - c * 100;
+
+ jd = c * 146097 / 4 + ya * 1461 / 4 + (month * 153 + 2) / 5 + day + 1721119;
+
+ return t_strdup_printf("%d", jd - 2400001);
+}
+
+static const char *ext_date_hour_part_get
+(struct tm *tm, int zone_offset ATTR_UNUSED)
+{
+ return t_strdup_printf("%02d", tm->tm_hour);
+}
+
+static const char *ext_date_minute_part_get
+(struct tm *tm, int zone_offset ATTR_UNUSED)
+{
+ return t_strdup_printf("%02d", tm->tm_min);
+}
+
+static const char *ext_date_second_part_get
+(struct tm *tm, int zone_offset ATTR_UNUSED)
+{
+ return t_strdup_printf("%02d", tm->tm_sec);
+}
+
+static const char *ext_date_time_part_get
+(struct tm *tm, int zone_offset ATTR_UNUSED)
+{
+ return t_strdup_printf("%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+
+static const char *ext_date_iso8601_part_get
+(struct tm *tm, int zone_offset)
+{
+ /* From RFC: `The restricted ISO 8601 format is specified by the date-time
+ * ABNF production given in [RFC3339], Section 5.6, with the added
+ * restrictions that the letters "T" and "Z" MUST be in upper case, and
+ * a time zone offset of zero MUST be represented by "Z" and not "+00:00".
+ */
+ if ( zone_offset == 0 )
+ zone_offset = INT_MAX;
+
+ return iso8601_date_create_tm(tm, zone_offset);
+}
+
+
+static const char *ext_date_std11_part_get
+(struct tm *tm, int zone_offset)
+{
+ return t_strdup_printf("%s, %02d %s %04d %02d:%02d:%02d %s",
+ weekday_names[tm->tm_wday],
+ tm->tm_mday,
+ month_names[tm->tm_mon],
+ tm->tm_year+1900,
+ tm->tm_hour, tm->tm_min, tm->tm_sec,
+ ext_date_zone_part_get(tm, zone_offset));
+}
+
+static const char *ext_date_zone_part_get
+(struct tm *tm ATTR_UNUSED, int zone_offset)
+{
+ bool negative;
+ int offset = zone_offset;
+
+ if (zone_offset >= 0)
+ negative = FALSE;
+ else {
+ negative = TRUE;
+ offset = -offset;
+ }
+
+ return t_strdup_printf
+ ("%c%02d%02d", negative ? '-' : '+', offset / 60, offset % 60);
+}
+
+static const char *ext_date_weekday_part_get
+(struct tm *tm, int zone_offset ATTR_UNUSED)
+{
+ return t_strdup_printf("%d", tm->tm_wday);
+}
+
+/*
+ * Date stringlist
+ */
+
+/* Forward declarations */
+
+static int ext_date_stringlist_next_item
+ (struct sieve_stringlist *_strlist, string_t **str_r);
+static void ext_date_stringlist_reset
+ (struct sieve_stringlist *_strlist);
+
+/* Stringlist object */
+
+struct ext_date_stringlist {
+ struct sieve_stringlist strlist;
+
+ struct sieve_stringlist *field_values;
+ int time_zone;
+ const struct ext_date_part *date_part;
+
+ time_t local_time;
+ int local_zone;
+
+ bool read:1;
+};
+
+struct sieve_stringlist *ext_date_stringlist_create
+(const struct sieve_runtime_env *renv, struct sieve_stringlist *field_values,
+ int time_zone, const struct ext_date_part *dpart)
+{
+ struct ext_date_stringlist *strlist;
+
+ strlist = t_new(struct ext_date_stringlist, 1);
+ strlist->strlist.runenv = renv;
+ strlist->strlist.exec_status = SIEVE_EXEC_OK;
+ strlist->strlist.next_item = ext_date_stringlist_next_item;
+ strlist->strlist.reset = ext_date_stringlist_reset;
+ strlist->field_values = field_values;
+ strlist->time_zone = time_zone;
+ strlist->date_part = dpart;
+
+ strlist->local_time = ext_date_get_current_date(renv, &strlist->local_zone);
+
+ return &strlist->strlist;
+}
+
+/* Stringlist implementation */
+
+static int ext_date_stringlist_next_item
+(struct sieve_stringlist *_strlist, string_t **str_r)
+{
+ struct ext_date_stringlist *strlist =
+ (struct ext_date_stringlist *) _strlist;
+ bool got_date = FALSE;
+ time_t date_value;
+ const char *part_value = NULL;
+ int original_zone;
+
+ /* Check whether the item was already read */
+ if ( strlist->read ) return 0;
+
+ if ( strlist->field_values != NULL ) {
+ string_t *hdr_item;
+ const char *header_value, *date_string;
+ int ret;
+
+ /* Use header field value */
+
+ /* Read first */
+ if ( (ret=sieve_stringlist_next_item(strlist->field_values, &hdr_item))
+ <= 0 )
+ return ret;
+
+ /* Extract the date string value */
+
+ header_value = str_c(hdr_item);
+ date_string = strrchr(header_value, ';');
+
+ if ( date_string == NULL ) {
+ /* Direct header value */
+ date_string = header_value;
+ } else {
+ /* Delimited by ';', e.g. a Received: header */
+ date_string++;
+ }
+
+ /* Parse the date value */
+ if ( message_date_parse((const unsigned char *) date_string,
+ strlen(date_string), &date_value, &original_zone) ) {
+ got_date = TRUE;
+ }
+ } else {
+ /* Use time stamp recorded at the time the script first started */
+ date_value = strlist->local_time;
+ original_zone = strlist->local_zone;
+ got_date = TRUE;
+ }
+
+ if ( got_date ) {
+ int wanted_zone;
+ struct tm *date_tm;
+
+ /* Apply wanted timezone */
+
+ switch ( strlist->time_zone ) {
+ case EXT_DATE_TIMEZONE_LOCAL:
+ wanted_zone = strlist->local_zone;
+ break;
+ case EXT_DATE_TIMEZONE_ORIGINAL:
+ wanted_zone = original_zone;
+ break;
+ default:
+ wanted_zone = strlist->time_zone;
+ }
+
+ date_value += wanted_zone * 60;
+
+ /* Convert timestamp to struct tm */
+
+ if ( (date_tm=gmtime(&date_value)) != NULL ) {
+ /* Extract the date part */
+ part_value = ext_date_part_extract
+ (strlist->date_part, date_tm, wanted_zone);
+ }
+ }
+
+ strlist->read = TRUE;
+
+ if ( part_value == NULL )
+ return 0;
+
+ *str_r = t_str_new_const(part_value, strlen(part_value));
+ return 1;
+}
+
+static void ext_date_stringlist_reset
+(struct sieve_stringlist *_strlist)
+{
+ struct ext_date_stringlist *strlist =
+ (struct ext_date_stringlist *) _strlist;
+
+ if ( strlist->field_values != NULL )
+ sieve_stringlist_reset(strlist->field_values);
+ strlist->read = FALSE;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/date/ext-date-common.h b/pigeonhole/src/lib-sieve/plugins/date/ext-date-common.h
new file mode 100644
index 0000000..116af3e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/date/ext-date-common.h
@@ -0,0 +1,80 @@
+#ifndef EXT_DATE_COMMON_H
+#define EXT_DATE_COMMON_H
+
+#include "sieve-common.h"
+
+#include <time.h>
+
+/*
+ * Extension
+ */
+
+extern const struct sieve_extension_def date_extension;
+
+bool ext_date_interpreter_load
+ (const struct sieve_extension *ext, const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED);
+
+/*
+ * Tests
+ */
+
+extern const struct sieve_command_def date_test;
+extern const struct sieve_command_def currentdate_test;
+
+/*
+ * Operations
+ */
+
+enum ext_date_opcode {
+ EXT_DATE_OPERATION_DATE,
+ EXT_DATE_OPERATION_CURRENTDATE
+};
+
+extern const struct sieve_operation_def date_operation;
+extern const struct sieve_operation_def currentdate_operation;
+
+/*
+ * Zone string
+ */
+
+bool ext_date_parse_timezone(const char *zone, int *zone_offset_r);
+
+/*
+ * Current date
+ */
+
+time_t ext_date_get_current_date
+ (const struct sieve_runtime_env *renv, int *zone_offset_r);
+
+/*
+ * Date part
+ */
+
+struct ext_date_part {
+ const char *identifier;
+
+ const char *(*get_string)(struct tm *tm, int zone_offset);
+};
+
+const struct ext_date_part *ext_date_part_find(const char *part);
+
+const char *ext_date_part_extract
+ (const struct ext_date_part *dpart, struct tm *tm, int zone_offset);
+
+/*
+ * Date stringlist
+ */
+
+enum ext_date_timezone_special {
+ EXT_DATE_TIMEZONE_LOCAL = 100,
+ EXT_DATE_TIMEZONE_ORIGINAL = 101
+};
+
+struct sieve_stringlist *ext_date_stringlist_create
+(const struct sieve_runtime_env *renv, struct sieve_stringlist *field_values,
+ int time_zone, const struct ext_date_part *dpart);
+
+
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/date/ext-date.c b/pigeonhole/src/lib-sieve/plugins/date/ext-date.c
new file mode 100644
index 0000000..3880d82
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/date/ext-date.c
@@ -0,0 +1,62 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension date
+ * ------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5260
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "lib.h"
+#include "array.h"
+
+#include "sieve-common.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-address-parts.h"
+
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-date-common.h"
+
+/*
+ * Extension
+ */
+
+static bool ext_date_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *validator);
+
+const struct sieve_operation_def *ext_date_operations[] = {
+ &date_operation,
+ &currentdate_operation
+};
+
+const struct sieve_extension_def date_extension = {
+ .name = "date",
+ .validator_load = ext_date_validator_load,
+ .interpreter_load = ext_date_interpreter_load,
+ SIEVE_EXT_DEFINE_OPERATIONS(ext_date_operations)
+};
+
+static bool ext_date_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Register new test */
+ sieve_validator_register_command(valdtr, ext, &date_test);
+ sieve_validator_register_command(valdtr, ext, &currentdate_test);
+
+ return TRUE;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/date/tst-date.c b/pigeonhole/src/lib-sieve/plugins/date/tst-date.c
new file mode 100644
index 0000000..60ee92c
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/date/tst-date.c
@@ -0,0 +1,496 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-address-parts.h"
+#include "sieve-message.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-match.h"
+
+#include "ext-date-common.h"
+
+#include <time.h>
+
+/*
+ * Tests
+ */
+
+static bool tst_date_validate
+ (struct sieve_validator *valdtr, struct sieve_command *tst);
+static bool tst_date_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+/* Date test
+ *
+ * Syntax:
+ * date [<":zone" <time-zone: string>> / ":originalzone"]
+ * [COMPARATOR] [MATCH-TYPE] <header-name: string>
+ * <date-part: string> <key-list: string-list>
+ */
+
+static bool tst_date_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+
+const struct sieve_command_def date_test = {
+ .identifier = "date",
+ .type = SCT_TEST,
+ .positional_args = 3,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_date_registered,
+ .validate = tst_date_validate,
+ .generate = tst_date_generate
+};
+
+/* Currentdate test
+ *
+ * Syntax:
+ * currentdate [":zone" <time-zone: string>]
+ * [COMPARATOR] [MATCH-TYPE]
+ * <date-part: string> <key-list: string-list>
+ */
+
+static bool tst_currentdate_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+
+const struct sieve_command_def currentdate_test = {
+ .identifier = "currentdate",
+ .type = SCT_TEST,
+ .positional_args = 2,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_currentdate_registered,
+ .validate = tst_date_validate,
+ .generate = tst_date_generate
+};
+
+/*
+ * Tagged arguments
+ */
+
+/* Forward declarations */
+
+static bool tag_zone_validate
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool tag_zone_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd);
+
+/* Argument objects */
+
+static const struct sieve_argument_def date_zone_tag = {
+ .identifier = "zone",
+ .validate = tag_zone_validate,
+ .generate = tag_zone_generate
+};
+
+static const struct sieve_argument_def date_originalzone_tag = {
+ .identifier = "originalzone",
+ .validate = tag_zone_validate,
+ .generate = tag_zone_generate
+};
+
+/*
+ * Date operation
+ */
+
+static bool tst_date_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int tst_date_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def date_operation = {
+ .mnemonic = "DATE",
+ .ext_def = &date_extension,
+ .code = EXT_DATE_OPERATION_DATE,
+ .dump = tst_date_operation_dump,
+ .execute = tst_date_operation_execute
+};
+
+const struct sieve_operation_def currentdate_operation = {
+ .mnemonic = "CURRENTDATE",
+ .ext_def = &date_extension,
+ .code = EXT_DATE_OPERATION_CURRENTDATE,
+ .dump = tst_date_operation_dump,
+ .execute = tst_date_operation_execute
+};
+
+/*
+ * Optional operands
+ */
+
+enum tst_date_optional {
+ OPT_DATE_ZONE = SIEVE_AM_OPT_LAST,
+ OPT_DATE_LAST
+};
+
+/*
+ * Tag implementation
+ */
+
+static bool tag_zone_validate
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+
+ if ( (bool) cmd->data ) {
+ if ( sieve_command_is(cmd, date_test) ) {
+ sieve_argument_validate_error(valdtr, *arg,
+ "multiple :zone or :originalzone arguments specified for "
+ "the currentdate test");
+ } else {
+ sieve_argument_validate_error(valdtr, *arg,
+ "multiple :zone arguments specified for the currentdate test");
+ }
+ return FALSE;
+ }
+
+ /* Skip tag */
+ *arg = sieve_ast_argument_next(*arg);
+
+ /* :content tag has a string-list argument */
+ if ( sieve_argument_is(tag, date_zone_tag) ) {
+
+ /* Check syntax:
+ * :zone <time-zone: string>
+ */
+ if ( !sieve_validate_tag_parameter
+ (valdtr, cmd, tag, *arg, NULL, 0, SAAT_STRING, FALSE) ) {
+ return FALSE;
+ }
+
+ /* Check it */
+ if ( sieve_argument_is_string_literal(*arg) ) {
+ const char *zone = sieve_ast_argument_strc(*arg);
+
+ if ( !ext_date_parse_timezone(zone, NULL) ) {
+ sieve_argument_validate_warning(valdtr, *arg,
+ "specified :zone argument '%s' is not a valid timezone",
+ str_sanitize(zone, 40));
+ }
+ }
+
+ /* Assign tag parameters */
+ tag->parameters = *arg;
+ *arg = sieve_ast_arguments_detach(*arg,1);
+ }
+
+ cmd->data = (void *) TRUE;
+
+ return TRUE;
+}
+
+/*
+ * Test registration
+ */
+
+static bool tst_date_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_comparators_link_tag(valdtr, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
+ sieve_match_types_link_tags(valdtr, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
+
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, ext, &date_zone_tag, OPT_DATE_ZONE);
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, ext, &date_originalzone_tag, OPT_DATE_ZONE);
+
+ return TRUE;
+}
+
+static bool tst_currentdate_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_comparators_link_tag(valdtr, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
+ sieve_match_types_link_tags(valdtr, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
+
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, ext, &date_zone_tag, OPT_DATE_ZONE);
+
+ return TRUE;
+}
+
+/*
+ * Validation
+ */
+
+static bool tst_date_validate
+(struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+ unsigned int arg_offset = 0 ;
+ const struct sieve_match_type mcht_default =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ const struct sieve_comparator cmp_default =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+
+ /* Check header name */
+
+ if ( sieve_command_is(tst, date_test) ) {
+ arg_offset = 1;
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "header name", 1, SAAT_STRING) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ if ( !sieve_command_verify_headers_argument(valdtr, arg) )
+ return FALSE;
+
+ arg = sieve_ast_argument_next(arg);
+ }
+
+ /* Check date part */
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "date part", arg_offset + 1, SAAT_STRING) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ if ( sieve_argument_is_string_literal(arg) ) {
+ const char * part = sieve_ast_argument_strc(arg);
+
+ if ( ext_date_part_find(part) == NULL ) {
+ sieve_argument_validate_warning
+ (valdtr, arg, "specified date part `%s' is not known",
+ str_sanitize(part, 80));
+ }
+ }
+
+ arg = sieve_ast_argument_next(arg);
+
+ /* Check key list */
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "key list", arg_offset + 2, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ /* Validate the key argument to a specified match type */
+ return sieve_match_type_validate
+ (valdtr, tst, arg, &mcht_default, &cmp_default);
+}
+
+/*
+ * Code generation
+ */
+
+static bool tst_date_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
+{
+ if ( sieve_command_is(tst, date_test) )
+ sieve_operation_emit(cgenv->sblock, tst->ext, &date_operation);
+ else if ( sieve_command_is(tst, currentdate_test) )
+ sieve_operation_emit(cgenv->sblock, tst->ext, &currentdate_operation);
+ else
+ i_unreached();
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, tst, NULL);
+}
+
+static bool tag_zone_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd)
+{
+ if ( arg->parameters == NULL ) {
+ sieve_opr_omitted_emit(cgenv->sblock);
+ return TRUE;
+ }
+
+ return sieve_generate_argument_parameters(cgenv, cmd, arg);
+}
+
+/*
+ * Code dump
+ */
+
+static bool tst_date_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ int opt_code = 0;
+ const struct sieve_operation *op = denv->oprtn;
+
+ sieve_code_dumpf(denv, "%s", sieve_operation_mnemonic(op));
+ sieve_code_descend(denv);
+
+ /* Handle any optional arguments */
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_message_opr_optional_dump(denv, address, &opt_code)) < 0 )
+ return FALSE;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_DATE_ZONE:
+ if ( !sieve_opr_string_dump_ex(denv, address, "zone", "ORIGINAL") )
+ return FALSE;
+ break;
+ default:
+ return FALSE;
+ }
+ }
+
+ if ( sieve_operation_is(op, date_operation) &&
+ !sieve_opr_string_dump(denv, address, "header name") )
+ return FALSE;
+
+ return
+ sieve_opr_string_dump(denv, address, "date part") &&
+ sieve_opr_stringlist_dump(denv, address, "key list");
+}
+
+
+/*
+ * Code execution
+ */
+
+static int tst_date_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ const struct sieve_operation *op = renv->oprtn;
+ int opt_code = 0;
+ struct sieve_match_type mcht =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ struct sieve_comparator cmp =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+ ARRAY_TYPE(sieve_message_override) svmos;
+ string_t *date_part = NULL, *zone = NULL;
+ struct sieve_stringlist *hdr_list = NULL, *hdr_value_list;
+ struct sieve_stringlist *value_list, *key_list;
+ bool zone_specified = FALSE, zone_literal = TRUE;
+ const struct ext_date_part *dpart;
+ int time_zone;
+ int match, ret;
+
+ /* Read optional operands */
+ for (;;) {
+ int opt;
+
+ /* Optional operands */
+ i_zero(&svmos);
+ if ( (opt=sieve_message_opr_optional_read
+ (renv, address, &opt_code, &ret, NULL, &mcht, &cmp, &svmos)) < 0 )
+ return ret;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_DATE_ZONE:
+ if ( (ret=sieve_opr_string_read_ex
+ (renv, address, "zone", TRUE, &zone, &zone_literal)) <= 0 )
+ return ret;
+
+ zone_specified = TRUE;
+ break;
+ default:
+ sieve_runtime_trace_error(renv, "unknown optional operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ }
+
+ if ( sieve_operation_is(op, date_operation) ) {
+ /* Read header name as stringlist */
+ if ( (ret=sieve_opr_stringlist_read
+ (renv, address, "header-name", &hdr_list)) <= 0 )
+ return ret;
+ }
+
+ /* Read date part */
+ if ( (ret=sieve_opr_string_read(renv, address, "date-part", &date_part))
+ <= 0 )
+ return ret;
+
+ /* Read key-list */
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "key-list", &key_list))
+ <= 0 )
+ return ret;
+
+ /* Determine what time zone to use in the result */
+ if ( !zone_specified ) {
+ time_zone = EXT_DATE_TIMEZONE_LOCAL;
+ } else if ( zone == NULL ) {
+ time_zone = EXT_DATE_TIMEZONE_ORIGINAL;
+ } else if ( !ext_date_parse_timezone(str_c(zone), &time_zone) ) {
+ if ( !zone_literal )
+ sieve_runtime_warning(renv, NULL,
+ "specified :zone argument `%s' is not a valid timezone "
+ "(using local zone)", str_sanitize(str_c(zone), 40));
+ time_zone = EXT_DATE_TIMEZONE_LOCAL;
+ }
+
+ if ( (dpart=ext_date_part_find(str_c(date_part))) == NULL ) {
+ sieve_runtime_warning(renv, NULL,
+ "specified date part argument `%s' is not known",
+ str_sanitize(str_c(date_part), 40));
+ sieve_interpreter_set_test_result(renv->interp, FALSE);
+ return SIEVE_EXEC_OK;
+ }
+
+ /*
+ * Perform test
+ */
+
+ if ( sieve_operation_is(op, date_operation) ) {
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "date test");
+
+ /* Get header */
+ sieve_runtime_trace_descend(renv);
+ if ( (ret=sieve_message_get_header_fields
+ (renv, hdr_list, &svmos, FALSE, &hdr_value_list)) <= 0 )
+ return ret;
+ sieve_runtime_trace_ascend(renv);
+
+ /* Create value stringlist */
+ value_list = ext_date_stringlist_create
+ (renv, hdr_value_list, time_zone, dpart);
+
+ } else if ( sieve_operation_is(op, currentdate_operation) ) {
+ /* Use time stamp recorded at the time the script first started */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "currentdatedate test");
+
+ /* Create value stringlist */
+ value_list = ext_date_stringlist_create(renv, NULL, time_zone, dpart);
+ } else {
+ i_unreached();
+ }
+
+ /* Perform match */
+ if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret)) < 0 )
+ return ret;
+
+ /* Set test result for subsequent conditional jump */
+ sieve_interpreter_set_test_result(renv->interp, match > 0);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/duplicate/Makefile.am b/pigeonhole/src/lib-sieve/plugins/duplicate/Makefile.am
new file mode 100644
index 0000000..7469b98
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/duplicate/Makefile.am
@@ -0,0 +1,20 @@
+noinst_LTLIBRARIES = libsieve_ext_duplicate.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+tests = \
+ tst-duplicate.c
+
+extensions = \
+ ext-duplicate.c
+
+libsieve_ext_duplicate_la_SOURCES = \
+ $(tests) \
+ $(extensions) \
+ ext-duplicate-common.c
+
+noinst_HEADERS = \
+ ext-duplicate-common.h
+
diff --git a/pigeonhole/src/lib-sieve/plugins/duplicate/Makefile.in b/pigeonhole/src/lib-sieve/plugins/duplicate/Makefile.in
new file mode 100644
index 0000000..d29f834
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/duplicate/Makefile.in
@@ -0,0 +1,697 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/duplicate
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_duplicate_la_LIBADD =
+am__objects_1 = tst-duplicate.lo
+am__objects_2 = ext-duplicate.lo
+am_libsieve_ext_duplicate_la_OBJECTS = $(am__objects_1) \
+ $(am__objects_2) ext-duplicate-common.lo
+libsieve_ext_duplicate_la_OBJECTS = \
+ $(am_libsieve_ext_duplicate_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ext-duplicate-common.Plo \
+ ./$(DEPDIR)/ext-duplicate.Plo ./$(DEPDIR)/tst-duplicate.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_duplicate_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_duplicate_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_duplicate.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+tests = \
+ tst-duplicate.c
+
+extensions = \
+ ext-duplicate.c
+
+libsieve_ext_duplicate_la_SOURCES = \
+ $(tests) \
+ $(extensions) \
+ ext-duplicate-common.c
+
+noinst_HEADERS = \
+ ext-duplicate-common.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/duplicate/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/duplicate/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_duplicate.la: $(libsieve_ext_duplicate_la_OBJECTS) $(libsieve_ext_duplicate_la_DEPENDENCIES) $(EXTRA_libsieve_ext_duplicate_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_duplicate_la_OBJECTS) $(libsieve_ext_duplicate_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-duplicate-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-duplicate.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-duplicate.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ext-duplicate-common.Plo
+ -rm -f ./$(DEPDIR)/ext-duplicate.Plo
+ -rm -f ./$(DEPDIR)/tst-duplicate.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ext-duplicate-common.Plo
+ -rm -f ./$(DEPDIR)/ext-duplicate.Plo
+ -rm -f ./$(DEPDIR)/tst-duplicate.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/duplicate/ext-duplicate-common.c b/pigeonhole/src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
new file mode 100644
index 0000000..5af7e04
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
@@ -0,0 +1,298 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "md5.h"
+#include "ioloop.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-settings.h"
+#include "sieve-error.h"
+#include "sieve-extensions.h"
+#include "sieve-message.h"
+#include "sieve-code.h"
+#include "sieve-runtime.h"
+#include "sieve-interpreter.h"
+#include "sieve-actions.h"
+#include "sieve-result.h"
+
+#include "ext-duplicate-common.h"
+
+/*
+ * Extension configuration
+ */
+
+#define EXT_DUPLICATE_DEFAULT_PERIOD (12*60*60)
+#define EXT_DUPLICATE_DEFAULT_MAX_PERIOD (2*24*60*60)
+
+bool ext_duplicate_load(const struct sieve_extension *ext, void **context)
+{
+ struct sieve_instance *svinst = ext->svinst;
+ struct ext_duplicate_config *config;
+ sieve_number_t default_period, max_period;
+
+ if (*context != NULL)
+ ext_duplicate_unload(ext);
+
+ if (!sieve_setting_get_duration_value(
+ svinst, "sieve_duplicate_default_period", &default_period))
+ default_period = EXT_DUPLICATE_DEFAULT_PERIOD;
+ if (!sieve_setting_get_duration_value(
+ svinst, "sieve_duplicate_max_period", &max_period)) {
+ max_period = EXT_DUPLICATE_DEFAULT_MAX_PERIOD;
+ }
+
+ config = i_new(struct ext_duplicate_config, 1);
+ config->default_period = default_period;
+ config->max_period = max_period;
+
+ *context = (void *) config;
+ return TRUE;
+}
+
+void ext_duplicate_unload(const struct sieve_extension *ext)
+{
+ struct ext_duplicate_config *config =
+ (struct ext_duplicate_config *)ext->context;
+
+ i_free(config);
+}
+
+/*
+ * Duplicate_mark action
+ */
+
+struct act_duplicate_mark_data {
+ const char *handle;
+ unsigned int period;
+ unsigned char hash[MD5_RESULTLEN];
+ bool last:1;
+};
+
+static void
+act_duplicate_mark_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv,
+ bool *keep);
+static void
+act_duplicate_mark_finish(const struct sieve_action_exec_env *aenv,
+ void *tr_context, int status);
+
+static const struct sieve_action_def act_duplicate_mark = {
+ .name = "duplicate_mark",
+ .print = act_duplicate_mark_print,
+ .finish = act_duplicate_mark_finish
+};
+
+static void
+act_duplicate_mark_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv,
+ bool *keep ATTR_UNUSED)
+{
+ struct act_duplicate_mark_data *data =
+ (struct act_duplicate_mark_data *)action->context;
+ const char *last = (data->last ? " last" : "");
+
+ if (data->handle != NULL) {
+ sieve_result_action_printf(
+ rpenv, "track%s duplicate with handle: %s",
+ last, str_sanitize(data->handle, 128));
+ } else {
+ sieve_result_action_printf(rpenv, "track%s duplicate", last);
+ }
+}
+
+static void
+act_duplicate_mark_finish(const struct sieve_action_exec_env *aenv,
+ void *tr_context ATTR_UNUSED, int status)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct act_duplicate_mark_data *data =
+ (struct act_duplicate_mark_data *)aenv->action->context;
+
+ if (status != SIEVE_EXEC_OK) {
+ e_debug(aenv->event, "Not marking duplicate (status=%s)",
+ sieve_execution_exitcode_to_str(status));
+ return;
+ }
+
+ e_debug(aenv->event, "Marking duplicate");
+
+ /* Message was handled successfully, so track duplicate for this
+ * message.
+ */
+ eenv->exec_status->significant_action_executed = TRUE;
+ sieve_action_duplicate_mark(aenv, data->hash, sizeof(data->hash),
+ ioloop_time + data->period);
+}
+
+/*
+ * Duplicate checking
+ */
+
+struct ext_duplicate_handle {
+ const char *handle;
+ bool last:1;
+ bool duplicate:1;
+};
+
+struct ext_duplicate_hash {
+ unsigned char hash[MD5_RESULTLEN];
+ ARRAY(struct ext_duplicate_handle) handles;
+};
+
+struct ext_duplicate_context {
+ ARRAY(struct ext_duplicate_hash) hashes;
+};
+
+static void
+ext_duplicate_hash(string_t *handle, const char *value, size_t value_len,
+ bool last, unsigned char hash_r[])
+{
+ static const char *id = "sieve duplicate";
+ struct md5_context md5ctx;
+
+ md5_init(&md5ctx);
+ md5_update(&md5ctx, id, strlen(id));
+ if (last)
+ md5_update(&md5ctx, "0", 1);
+ else
+ md5_update(&md5ctx, "+", 1);
+ if (handle != NULL) {
+ md5_update(&md5ctx, "h-", 2);
+ md5_update(&md5ctx, str_c(handle), str_len(handle));
+ } else {
+ md5_update(&md5ctx, "default", 7);
+ }
+ md5_update(&md5ctx, value, value_len);
+ md5_final(&md5ctx, hash_r);
+}
+
+int ext_duplicate_check(const struct sieve_runtime_env *renv, string_t *handle,
+ const char *value, size_t value_len,
+ sieve_number_t period, bool last, bool *duplicate_r)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ struct ext_duplicate_context *rctx;
+ bool duplicate = FALSE;
+ pool_t msg_pool = NULL, result_pool = NULL;
+ unsigned char hash[MD5_RESULTLEN];
+ struct ext_duplicate_hash *hash_record = NULL;
+ struct ext_duplicate_handle *handle_record = NULL;
+ struct act_duplicate_mark_data *act;
+ int ret;
+
+ *duplicate_r = FALSE;
+
+ if (!sieve_execute_duplicate_check_available(eenv)) {
+ sieve_runtime_warning(
+ renv, NULL, "duplicate test: "
+ "duplicate checking not available in this context");
+ return SIEVE_EXEC_OK;
+ }
+
+ if (value == NULL)
+ return SIEVE_EXEC_OK;
+
+ /* Create hash */
+ ext_duplicate_hash(handle, value, value_len, last, hash);
+
+ /* Get context; find out whether duplicate was checked earlier */
+ rctx = (struct ext_duplicate_context *)
+ sieve_message_context_extension_get(renv->msgctx, this_ext);
+
+ if (rctx == NULL) {
+ /* Create context */
+ msg_pool = sieve_message_context_pool(renv->msgctx);
+ rctx = p_new(msg_pool, struct ext_duplicate_context, 1);
+ sieve_message_context_extension_set(renv->msgctx, this_ext,
+ (void *)rctx);
+ } else if (array_is_created(&rctx->hashes)) {
+ struct ext_duplicate_hash *record;
+
+ array_foreach_modifiable(&rctx->hashes, record) {
+ if (memcmp(record->hash, hash, MD5_RESULTLEN) == 0) {
+ hash_record = record;
+ break;
+ }
+ }
+ }
+ if (hash_record != NULL) {
+ const struct ext_duplicate_handle *rhandle;
+ array_foreach(&hash_record->handles, rhandle) {
+ const char *handle_str =
+ (handle == NULL ? NULL : str_c(handle));
+ if (null_strcmp(rhandle->handle, handle_str) == 0 &&
+ rhandle->last == last)
+ return (rhandle->duplicate ?
+ SIEVE_DUPLICATE_CHECK_RESULT_EXISTS :
+ SIEVE_DUPLICATE_CHECK_RESULT_NOT_FOUND);
+ }
+ }
+
+ result_pool = sieve_result_pool(renv->result);
+ act = p_new(result_pool, struct act_duplicate_mark_data, 1);
+ if (handle != NULL)
+ act->handle = p_strdup(result_pool, str_c(handle));
+ act->period = period;
+ memcpy(act->hash, hash, MD5_RESULTLEN);
+ act->last = last;
+
+ /* Check duplicate */
+ ret = sieve_execute_duplicate_check(eenv, hash, sizeof(hash),
+ &duplicate);
+ if (ret >= SIEVE_EXEC_OK && !duplicate && last) {
+ unsigned char no_last_hash[MD5_RESULTLEN];
+
+ /* Check for entry without :last */
+ ext_duplicate_hash(handle, value, value_len,
+ FALSE, no_last_hash);
+ ret = sieve_execute_duplicate_check(
+ eenv, no_last_hash, sizeof(no_last_hash),
+ &duplicate);
+ }
+ if (ret < SIEVE_EXEC_OK) {
+ sieve_runtime_critical(
+ renv, NULL, "failed to check for duplicate",
+ "failed to check for duplicate%s",
+ (ret == SIEVE_EXEC_TEMP_FAILURE ?
+ " (temporary failure)" : ""));
+ return ret;
+ }
+
+ /* We may only mark the message as duplicate when Sieve script executes
+ * successfully; therefore defer this operation until successful result
+ * execution.
+ */
+ if (!duplicate || last) {
+ if (sieve_result_add_action(renv, NULL, NULL,
+ &act_duplicate_mark,
+ NULL, (void *) act, 0, FALSE) < 0)
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ /* Cache result */
+ if (msg_pool == NULL)
+ msg_pool = sieve_message_context_pool(renv->msgctx);
+ if (hash_record == NULL) {
+ if (!array_is_created(&rctx->hashes))
+ p_array_init(&rctx->hashes, msg_pool, 64);
+ hash_record = array_append_space(&rctx->hashes);
+ memcpy(hash_record->hash, hash, MD5_RESULTLEN);
+ p_array_init(&hash_record->handles, msg_pool, 64);
+ }
+
+ handle_record = array_append_space(&hash_record->handles);
+ if (handle != NULL)
+ handle_record->handle = p_strdup(msg_pool, str_c(handle));
+ handle_record->last = last;
+ handle_record->duplicate = duplicate;
+
+ *duplicate_r = duplicate;
+
+ return SIEVE_EXEC_OK;
+}
+
diff --git a/pigeonhole/src/lib-sieve/plugins/duplicate/ext-duplicate-common.h b/pigeonhole/src/lib-sieve/plugins/duplicate/ext-duplicate-common.h
new file mode 100644
index 0000000..c802b08
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/duplicate/ext-duplicate-common.h
@@ -0,0 +1,41 @@
+#ifndef EXT_DUPLICATE_COMMON_H
+#define EXT_DUPLICATE_COMMON_H
+
+#include "sieve-common.h"
+
+/*
+ * Extension
+ */
+
+struct ext_duplicate_config {
+ unsigned int default_period;
+ unsigned int max_period;
+};
+
+bool ext_duplicate_load(const struct sieve_extension *ext, void **context);
+void ext_duplicate_unload(const struct sieve_extension *ext);
+
+extern const struct sieve_extension_def duplicate_extension;
+extern const struct sieve_extension_def vnd_duplicate_extension;
+
+/*
+ * Tests
+ */
+
+extern const struct sieve_command_def tst_duplicate;
+
+/*
+ * Operations
+ */
+
+extern const struct sieve_operation_def tst_duplicate_operation;
+
+/*
+ * Duplicate checking
+ */
+
+int ext_duplicate_check(const struct sieve_runtime_env *renv, string_t *handle,
+ const char *value, size_t value_len,
+ sieve_number_t period, bool last, bool *duplicate_r);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/duplicate/ext-duplicate.c b/pigeonhole/src/lib-sieve/plugins/duplicate/ext-duplicate.c
new file mode 100644
index 0000000..54de5e5
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/duplicate/ext-duplicate.c
@@ -0,0 +1,107 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension duplicate
+ * -------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: vendor-defined; spec-bosch-sieve-duplicate
+ * Implementation: full
+ * Status: experimental
+ *
+ */
+
+/* Extension vnd.dovecot.duplicate
+ * -------------------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: vendor-defined; spec-bosch-sieve-duplicate
+ * Implementation: full, but deprecated; provided for backwards compatibility
+ * Status: experimental
+ *
+ */
+
+#include "lib.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-binary.h"
+
+#include "sieve-validator.h"
+
+#include "ext-duplicate-common.h"
+
+/*
+ * Extensions
+ */
+
+static bool ext_duplicate_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def duplicate_extension = {
+ .name = "duplicate",
+ .load = ext_duplicate_load,
+ .unload = ext_duplicate_unload,
+ .validator_load = ext_duplicate_validator_load,
+ SIEVE_EXT_DEFINE_OPERATION(tst_duplicate_operation)
+};
+
+const struct sieve_extension_def vnd_duplicate_extension = {
+ .name = "vnd.dovecot.duplicate",
+ .load = ext_duplicate_load,
+ .unload = ext_duplicate_unload,
+ .validator_load = ext_duplicate_validator_load,
+ SIEVE_EXT_DEFINE_OPERATION(tst_duplicate_operation)
+};
+
+/*
+ * Validation
+ */
+
+static bool ext_duplicate_validator_check_conflict
+ (const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context,
+ struct sieve_ast_argument *require_arg,
+ const struct sieve_extension *ext_other,
+ bool required);
+
+const struct sieve_validator_extension
+duplicate_validator_extension = {
+ .ext = &vnd_duplicate_extension,
+ .check_conflict = ext_duplicate_validator_check_conflict
+};
+
+static bool ext_duplicate_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Register validator extension to check for conflict between
+ vnd.dovecot.duplicate and duplicate extensions */
+ if ( sieve_extension_is(ext, vnd_duplicate_extension) ) {
+ sieve_validator_extension_register
+ (valdtr, ext, &duplicate_validator_extension, NULL);
+ }
+
+ /* Register duplicate test */
+ sieve_validator_register_command(valdtr, ext, &tst_duplicate);
+
+ return TRUE;
+}
+
+static bool ext_duplicate_validator_check_conflict
+(const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_validator *valdtr, void *context ATTR_UNUSED,
+ struct sieve_ast_argument *require_arg,
+ const struct sieve_extension *ext_other,
+ bool required ATTR_UNUSED)
+{
+ /* Check for conflict with duplicate extension */
+ if ( sieve_extension_name_is(ext_other, "duplicate") ) {
+ sieve_argument_validate_error(valdtr, require_arg,
+ "the (deprecated) vnd.dovecot.duplicate extension "
+ "cannot be used together with the duplicate extension");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
diff --git a/pigeonhole/src/lib-sieve/plugins/duplicate/tst-duplicate.c b/pigeonhole/src/lib-sieve/plugins/duplicate/tst-duplicate.c
new file mode 100644
index 0000000..d211e04
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/duplicate/tst-duplicate.c
@@ -0,0 +1,449 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "mail-storage.h"
+
+#include "sieve-common.h"
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-duplicate-common.h"
+
+/* Duplicate test
+ *
+ * Syntax:
+ * Usage: "duplicate" [":handle" <handle: string>]
+ * [":header" <header-name: string> /
+ * ":uniqueid" <value: string>]
+ * [":seconds" <timeout: number>] [":last"]
+ */
+
+static bool
+tst_duplicate_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool
+tst_duplicate_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+const struct sieve_command_def tst_duplicate = {
+ .identifier = "duplicate",
+ .type = SCT_TEST,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_duplicate_registered,
+ .generate = tst_duplicate_generate
+};
+
+/*
+ * Duplicate test tags
+ */
+
+static bool
+tst_duplicate_validate_number_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool
+tst_duplicate_validate_string_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+static const struct sieve_argument_def duplicate_seconds_tag = {
+ .identifier = "seconds",
+ .validate = tst_duplicate_validate_number_tag
+};
+
+static const struct sieve_argument_def duplicate_header_tag = {
+ .identifier = "header",
+ .validate = tst_duplicate_validate_string_tag
+};
+
+static const struct sieve_argument_def duplicate_uniqueid_tag = {
+ .identifier = "uniqueid",
+ .validate = tst_duplicate_validate_string_tag
+};
+
+static const struct sieve_argument_def duplicate_value_tag = {
+ .identifier = "value", /* vnd.dovecot.duplicate (deprecated) */
+ .validate = tst_duplicate_validate_string_tag
+};
+
+static const struct sieve_argument_def duplicate_handle_tag = {
+ .identifier = "handle",
+ .validate = tst_duplicate_validate_string_tag
+};
+
+static const struct sieve_argument_def duplicate_last_tag = {
+ .identifier = "last"
+};
+
+/* Codes for optional arguments */
+
+enum tst_duplicate_optional {
+ OPT_END,
+ OPT_SECONDS,
+ OPT_HEADER,
+ OPT_UNIQUEID,
+ OPT_LAST,
+ OPT_HANDLE
+};
+
+/*
+ * Duplicate operation
+ */
+
+static bool
+tst_duplicate_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+tst_duplicate_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def tst_duplicate_operation = {
+ .mnemonic = "DUPLICATE",
+ .ext_def = &duplicate_extension,
+ .dump = tst_duplicate_operation_dump,
+ .execute = tst_duplicate_operation_execute
+};
+
+/*
+ * Tag validation
+ */
+
+static bool
+tst_duplicate_validate_number_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ const struct sieve_extension *ext = sieve_argument_ext(*arg);
+ const struct ext_duplicate_config *config =
+ (const struct ext_duplicate_config *)ext->context;
+ struct sieve_ast_argument *tag = *arg;
+ sieve_number_t seconds;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ /* Check syntax:
+ * :seconds number
+ */
+ if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0,
+ SAAT_NUMBER, FALSE))
+ return FALSE;
+
+ seconds = sieve_ast_argument_number(*arg);
+ /* Enforce :days <= max_period */
+ if (config->max_period > 0 && seconds > config->max_period) {
+ seconds = config->max_period;
+
+ sieve_argument_validate_warning(
+ valdtr, *arg,
+ "specified :seconds value '%llu' is over the maximum",
+ (unsigned long long)seconds);
+ }
+
+ sieve_ast_argument_number_set(*arg, seconds);
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+ return TRUE;
+}
+
+static bool
+tst_duplicate_validate_string_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ const struct sieve_extension *ext = cmd->ext;
+ struct sieve_ast_argument *tag = *arg;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ /* Check syntax:
+ * :header <header-name: string>
+ * :value <value: string>
+ * :handle <handle: string>
+ */
+ if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0,
+ SAAT_STRING, FALSE))
+ return FALSE;
+
+ if (!sieve_argument_is(tag, duplicate_handle_tag) && (bool)cmd->data) {
+ sieve_argument_validate_error(
+ valdtr, *arg,
+ "conflicting :header and %s arguments specified "
+ "for the duplicate test",
+ (sieve_extension_is(ext, duplicate_extension) ?
+ ":uniqueid" : ":value"));
+ return FALSE;
+ }
+
+ /* :header <header-name: string> */
+ if (sieve_argument_is(tag, duplicate_header_tag)) {
+ if (!sieve_command_verify_headers_argument(valdtr, *arg))
+ return FALSE;
+ cmd->data = (void *)TRUE;
+ /* :handle <handle: string> */
+ } else if (sieve_argument_is(tag, duplicate_handle_tag)) {
+ /* nothing to be done */
+ } else if (sieve_argument_is(tag, duplicate_uniqueid_tag)) {
+ i_assert(sieve_extension_is(ext, duplicate_extension));
+ cmd->data = (void *)TRUE;
+ /* :value <value: string> (vnd.dovecot.duplicate) */
+ } else if (sieve_argument_is(tag, duplicate_value_tag)) {
+ i_assert(sieve_extension_is(ext, vnd_duplicate_extension));
+ cmd->data = (void *)TRUE;
+ } else {
+ i_unreached();
+ }
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+ return TRUE;
+}
+
+/*
+ * Command registration
+ */
+
+static bool
+tst_duplicate_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &duplicate_seconds_tag, OPT_SECONDS);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &duplicate_last_tag, OPT_LAST);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &duplicate_header_tag, OPT_HEADER);
+ if (sieve_extension_is(ext, duplicate_extension)) {
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &duplicate_uniqueid_tag,
+ OPT_UNIQUEID);
+ } else {
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &duplicate_value_tag,
+ OPT_UNIQUEID);
+ }
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &duplicate_handle_tag, OPT_HANDLE);
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+tst_duplicate_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &tst_duplicate_operation);
+
+ if (!sieve_generate_arguments(cgenv, cmd, NULL))
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+tst_duplicate_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ const struct sieve_extension *ext = denv->oprtn->ext;
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "DUPLICATE");
+ sieve_code_descend(denv);
+
+ /* Dump optional operands */
+
+ for (;;) {
+ int opt;
+ bool opok = TRUE;
+
+ if ((opt = sieve_opr_optional_dump(denv, address,
+ &opt_code)) < 0)
+ return FALSE;
+
+ if (opt == 0)
+ break;
+
+ switch (opt_code) {
+ case OPT_SECONDS:
+ opok = sieve_opr_number_dump(denv, address, "seconds");
+ break;
+ case OPT_LAST:
+ sieve_code_dumpf(denv, "last");
+ break;
+ case OPT_HEADER:
+ opok = sieve_opr_string_dump(denv, address, "header");
+ break;
+ case OPT_UNIQUEID:
+ if (sieve_extension_is(ext, duplicate_extension)) {
+ opok = sieve_opr_string_dump(denv, address,
+ "uniqueid");
+ } else {
+ opok = sieve_opr_string_dump(denv, address,
+ "value");
+ }
+ break;
+ case OPT_HANDLE:
+ opok = sieve_opr_string_dump(denv, address, "handle");
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (!opok)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Code execution
+ */
+
+static int
+tst_duplicate_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_extension *ext = renv->oprtn->ext;
+ const struct ext_duplicate_config *config =
+ (const struct ext_duplicate_config *)ext->context;
+ struct mail *mail = eenv->msgdata->mail;
+ int opt_code = 0;
+ string_t *handle = NULL, *header = NULL, *uniqueid = NULL;
+ const char *val = NULL;
+ size_t val_len = 0;
+ sieve_number_t seconds = config->default_period;
+ bool last = FALSE, duplicate = FALSE;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Optional operands */
+
+ for (;;) {
+ int opt;
+
+ if ((opt = sieve_opr_optional_read(renv, address,
+ &opt_code)) < 0)
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ if (opt == 0)
+ break;
+
+ switch (opt_code) {
+ case OPT_SECONDS:
+ ret = sieve_opr_number_read(renv, address, "seconds",
+ &seconds);
+ break;
+ case OPT_LAST:
+ last = TRUE;
+ ret = SIEVE_EXEC_OK;
+ break;
+ case OPT_HEADER:
+ ret = sieve_opr_string_read(renv, address, "header",
+ &header);
+ break;
+ case OPT_UNIQUEID:
+ if (sieve_extension_is(ext, duplicate_extension)) {
+ ret = sieve_opr_string_read(renv, address,
+ "uniqueid",
+ &uniqueid);
+ } else {
+ ret = sieve_opr_string_read(renv, address,
+ "value", &uniqueid);
+ }
+ break;
+ case OPT_HANDLE:
+ ret = sieve_opr_string_read(renv, address,
+ "handle", &handle);
+ break;
+ default:
+ sieve_runtime_trace_error(
+ renv, "unknown optional operand");
+ ret = SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if (ret <= 0)
+ return ret;
+ }
+
+ /*
+ * Perform operation
+ */
+
+ /* Trace */
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "duplicate test");
+ sieve_runtime_trace_descend(renv);
+
+ /* Get value */
+ if (uniqueid != NULL) {
+ val = str_c(uniqueid);
+ val_len = str_len(uniqueid);
+ } else {
+ if (header == NULL) {
+ ret = mail_get_message_id(mail, &val);
+ if (ret < 0) {
+ return sieve_runtime_mail_error(
+ renv, mail, "duplicate test: "
+ "failed to read header field `message-id'");
+ }
+ } else {
+ ret = mail_get_first_header_utf8(mail, str_c(header),
+ &val);
+ if (ret < 0) {
+ return sieve_runtime_mail_error(
+ renv, mail, "duplicate test: "
+ "failed to read header field `%s'",
+ str_c(header));
+ }
+ }
+
+ if (ret > 0)
+ val_len = strlen(val);
+ }
+
+ /* Check duplicate */
+ if (val == NULL) {
+ duplicate = FALSE;
+ } else {
+ ret = ext_duplicate_check(renv, handle, val, val_len,
+ seconds, last, &duplicate);
+ if (ret < SIEVE_EXEC_OK)
+ return ret;
+ }
+
+ /* Trace */
+ if (duplicate) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "message is a duplicate");
+ } else {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "message is not a duplicate");
+ }
+
+ /* Set test result for subsequent conditional jump */
+ sieve_interpreter_set_test_result(renv->interp, duplicate);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/editheader/Makefile.am b/pigeonhole/src/lib-sieve/plugins/editheader/Makefile.am
new file mode 100644
index 0000000..6824ec0
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/editheader/Makefile.am
@@ -0,0 +1,19 @@
+noinst_LTLIBRARIES = libsieve_ext_editheader.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../../util \
+ $(LIBDOVECOT_INCLUDE)
+
+commands = \
+ cmd-addheader.c \
+ cmd-deleteheader.c
+
+libsieve_ext_editheader_la_SOURCES = \
+ $(commands) \
+ ext-editheader.c \
+ ext-editheader-common.c
+
+noinst_HEADERS = \
+ ext-editheader-limits.h \
+ ext-editheader-common.h
diff --git a/pigeonhole/src/lib-sieve/plugins/editheader/Makefile.in b/pigeonhole/src/lib-sieve/plugins/editheader/Makefile.in
new file mode 100644
index 0000000..75d9571
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/editheader/Makefile.in
@@ -0,0 +1,701 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/editheader
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_editheader_la_LIBADD =
+am__objects_1 = cmd-addheader.lo cmd-deleteheader.lo
+am_libsieve_ext_editheader_la_OBJECTS = $(am__objects_1) \
+ ext-editheader.lo ext-editheader-common.lo
+libsieve_ext_editheader_la_OBJECTS = \
+ $(am_libsieve_ext_editheader_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cmd-addheader.Plo \
+ ./$(DEPDIR)/cmd-deleteheader.Plo \
+ ./$(DEPDIR)/ext-editheader-common.Plo \
+ ./$(DEPDIR)/ext-editheader.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_editheader_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_editheader_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_editheader.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../../util \
+ $(LIBDOVECOT_INCLUDE)
+
+commands = \
+ cmd-addheader.c \
+ cmd-deleteheader.c
+
+libsieve_ext_editheader_la_SOURCES = \
+ $(commands) \
+ ext-editheader.c \
+ ext-editheader-common.c
+
+noinst_HEADERS = \
+ ext-editheader-limits.h \
+ ext-editheader-common.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/editheader/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/editheader/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_editheader.la: $(libsieve_ext_editheader_la_OBJECTS) $(libsieve_ext_editheader_la_DEPENDENCIES) $(EXTRA_libsieve_ext_editheader_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_editheader_la_OBJECTS) $(libsieve_ext_editheader_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-addheader.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-deleteheader.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-editheader-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-editheader.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/cmd-addheader.Plo
+ -rm -f ./$(DEPDIR)/cmd-deleteheader.Plo
+ -rm -f ./$(DEPDIR)/ext-editheader-common.Plo
+ -rm -f ./$(DEPDIR)/ext-editheader.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/cmd-addheader.Plo
+ -rm -f ./$(DEPDIR)/cmd-deleteheader.Plo
+ -rm -f ./$(DEPDIR)/ext-editheader-common.Plo
+ -rm -f ./$(DEPDIR)/ext-editheader.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/editheader/cmd-addheader.c b/pigeonhole/src/lib-sieve/plugins/editheader/cmd-addheader.c
new file mode 100644
index 0000000..f39cbb7
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/editheader/cmd-addheader.c
@@ -0,0 +1,337 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+#include "mail-storage.h"
+
+#include "rfc2822.h"
+#include "edit-mail.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-message.h"
+
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-editheader-common.h"
+
+/*
+ * Addheader command
+ *
+ * Syntax
+ * "addheader" [":last"] <field-name: string> <value: string>
+ */
+
+static bool cmd_addheader_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool cmd_addheader_validate
+ (struct sieve_validator *valdtr, struct sieve_command *tst);
+static bool cmd_addheader_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+const struct sieve_command_def addheader_command = {
+ .identifier = "addheader",
+ .type = SCT_COMMAND,
+ .positional_args = 2,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = cmd_addheader_registered,
+ .validate = cmd_addheader_validate,
+ .generate = cmd_addheader_generate
+};
+
+/*
+ * Addheader command tags
+ */
+
+/* Argument objects */
+
+static const struct sieve_argument_def addheader_last_tag = {
+ .identifier = "last"
+};
+
+/* Codes for optional arguments */
+
+enum cmd_addheader_optional {
+ OPT_END,
+ OPT_LAST
+};
+
+/*
+ * Addheader operation
+ */
+
+static bool cmd_addheader_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int cmd_addheader_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def addheader_operation = {
+ .mnemonic = "ADDHEADER",
+ .ext_def = &editheader_extension,
+ .code = EXT_EDITHEADER_OPERATION_ADDHEADER,
+ .dump = cmd_addheader_operation_dump,
+ .execute = cmd_addheader_operation_execute
+};
+
+/*
+ * Utility
+ */
+
+static bool _str_contains_nul(const string_t *str)
+{
+ const unsigned char *p, *pend;
+
+ p = str_data(str);
+ pend = p + str_len(str);
+ while (p < pend) {
+ if (*p == '\0')
+ return TRUE;
+ p++;
+ }
+ return FALSE;
+}
+
+/*
+ * Validation
+ */
+
+static bool cmd_addheader_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+
+ /* Check field-name syntax */
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, cmd, arg, "field-name", 1, SAAT_STRING) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, cmd, arg, FALSE) )
+ return FALSE;
+
+ if ( sieve_argument_is_string_literal(arg) ) {
+ string_t *fname = sieve_ast_argument_str(arg);
+
+ if ( !rfc2822_header_field_name_verify(str_c(fname), str_len(fname)) ) {
+ sieve_argument_validate_error
+ (valdtr, arg, "addheader command: specified field name `%s' is invalid",
+ str_sanitize(str_c(fname), 80));
+ return FALSE;
+ }
+
+ if ( !ext_editheader_header_allow_add
+ (cmd->ext, str_c(fname)) ) {
+ sieve_argument_validate_warning
+ (valdtr, arg, "addheader command: "
+ "adding specified header field `%s' is forbidden; "
+ "modification will be denied",
+ str_sanitize(str_c(fname), 80));
+ }
+ }
+
+ /* Check value syntax */
+
+ arg = sieve_ast_argument_next(arg);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, cmd, arg, "value", 2, SAAT_STRING) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, cmd, arg, FALSE) )
+ return FALSE;
+
+ if ( sieve_argument_is_string_literal(arg) ) {
+ string_t *fvalue = sieve_ast_argument_str(arg);
+
+ if ( _str_contains_nul(fvalue) ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "addheader command: specified value `%s' is invalid "
+ "(contains NUL character)", str_sanitize(str_c(fvalue), 80));
+ return FALSE;
+ }
+
+ if ( !rfc2822_header_field_body_verify
+ (str_c(fvalue), str_len(fvalue), TRUE, TRUE) ) {
+ sieve_argument_validate_warning(valdtr, arg,
+ "addheader command: specified value `%s' is invalid",
+ str_sanitize(str_c(fvalue), 80));
+ }
+
+ if ( ext_editheader_header_too_large(cmd->ext, str_len(fvalue)) ) {
+ sieve_argument_validate_error(valdtr, arg, "addheader command: "
+ "specified header value `%s' is too large (%zu bytes)",
+ str_sanitize(str_c(fvalue), 80), str_len(fvalue));
+ return SIEVE_EXEC_FAILURE;
+ }
+ }
+
+ return TRUE;
+}
+
+/*
+ * Command registration
+ */
+
+static bool cmd_addheader_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, ext, &addheader_last_tag, OPT_LAST);
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool cmd_addheader_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ (void)sieve_operation_emit(cgenv->sblock, cmd->ext, &addheader_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, cmd, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool cmd_addheader_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "addheader");
+ sieve_code_descend(denv);
+
+ /* Dump optional operands */
+
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_opr_optional_dump(denv, address, &opt_code)) < 0 )
+ return FALSE;
+
+ if ( opt == 0 ) break;
+
+ if ( opt_code == OPT_LAST ) {
+ sieve_code_dumpf(denv, "last");
+ } else {
+ return FALSE;
+ }
+ }
+
+ return
+ sieve_opr_string_dump(denv, address, "field-name") &&
+ sieve_opr_string_dump(denv, address, "value");
+}
+
+/*
+ * Interpretation
+ */
+
+static int cmd_addheader_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ string_t *field_name;
+ string_t *value;
+ struct edit_mail *edmail;
+ bool last = FALSE;
+ int opt_code = 0;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Optional operands */
+
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_opr_optional_read(renv, address, &opt_code)) < 0 )
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_LAST:
+ last = TRUE;
+ break;
+ default:
+ sieve_runtime_trace_error(renv, "unknown optional operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ }
+
+ /* Read message */
+
+ if ( (ret=sieve_opr_string_read
+ (renv, address, "field-name", &field_name)) <= 0 )
+ return ret;
+
+ if ( (ret=sieve_opr_string_read
+ (renv, address, "value", &value)) <= 0 )
+ return ret;
+
+ /*
+ * Verify arguments
+ */
+
+ if ( !rfc2822_header_field_name_verify
+ (str_c(field_name), str_len(field_name)) ) {
+ sieve_runtime_error(renv, NULL, "addheader action: "
+ "specified field name `%s' is invalid",
+ str_sanitize(str_c(field_name), 80));
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ if ( !ext_editheader_header_allow_add
+ (this_ext, str_c(field_name)) ) {
+ sieve_runtime_warning(renv, NULL, "addheader action: "
+ "adding specified header field `%s' is forbidden; "
+ "modification denied", str_sanitize(str_c(field_name), 80));
+ return SIEVE_EXEC_OK;
+ }
+
+ if ( _str_contains_nul(value) ) {
+ sieve_runtime_error(renv, NULL, "addheader action: "
+ "specified value `%s' is invalid (contains NUL character)",
+ str_sanitize(str_c(value), 80));
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ if ( ext_editheader_header_too_large(this_ext, str_len(value)) ) {
+ sieve_runtime_error(renv, NULL, "addheader action: "
+ "specified header value `%s' is too large (%zu bytes)",
+ str_sanitize(str_c(value), 80), str_len(value));
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "addheader \"%s: %s\"",
+ str_sanitize(str_c(field_name), 80), str_sanitize(str_c(value), 80));
+
+ edmail = sieve_message_edit(renv->msgctx);
+ edit_mail_header_add(edmail,
+ rfc2822_header_field_name_sanitize(str_c(field_name)),
+ str_c(value), last);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/editheader/cmd-deleteheader.c b/pigeonhole/src/lib-sieve/plugins/editheader/cmd-deleteheader.c
new file mode 100644
index 0000000..a6964b7
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/editheader/cmd-deleteheader.c
@@ -0,0 +1,551 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+#include "mail-storage.h"
+
+#include "rfc2822.h"
+#include "edit-mail.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-message.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-match.h"
+
+#include "ext-editheader-common.h"
+
+/*
+ * Deleteheader command
+ *
+ * Syntax:
+ * deleteheader [":index" <fieldno: number> [":last"]]
+ * [COMPARATOR] [MATCH-TYPE]
+ * <field-name: string> [<value-patterns: string-list>]
+ */
+
+static bool cmd_deleteheader_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool cmd_deleteheader_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool cmd_deleteheader_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
+
+const struct sieve_command_def deleteheader_command = {
+ .identifier = "deleteheader",
+ .type = SCT_COMMAND,
+ .positional_args = -1, /* We check positional arguments ourselves */
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = cmd_deleteheader_registered,
+ .validate = cmd_deleteheader_validate,
+ .generate = cmd_deleteheader_generate
+};
+
+/*
+ * Deleteheader command tags
+ */
+
+/* Forward declarations */
+
+static bool cmd_deleteheader_validate_index_tag
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool cmd_deleteheader_validate_last_tag
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+/* Argument objects */
+
+static const struct sieve_argument_def deleteheader_index_tag = {
+ .identifier = "index",
+ .validate = cmd_deleteheader_validate_index_tag
+};
+
+static const struct sieve_argument_def deleteheader_last_tag = {
+ .identifier = "last",
+ .validate = cmd_deleteheader_validate_last_tag
+};
+
+/* Codes for optional arguments */
+
+enum cmd_deleteheader_optional {
+ OPT_INDEX = SIEVE_MATCH_OPT_LAST,
+ OPT_LAST
+};
+
+/*
+ * Deleteheader operation
+ */
+
+static bool cmd_deleteheader_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int cmd_deleteheader_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def deleteheader_operation = {
+ .mnemonic = "DELETEHEADER",
+ .ext_def = &editheader_extension,
+ .code = EXT_EDITHEADER_OPERATION_DELETEHEADER,
+ .dump = cmd_deleteheader_operation_dump,
+ .execute = cmd_deleteheader_operation_execute
+};
+
+/*
+ * Command registration
+ */
+
+static bool cmd_deleteheader_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_command_registration *cmd_reg)
+{
+ /* The order of these is not significant */
+ sieve_comparators_link_tag(valdtr, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
+ sieve_match_types_link_tags(valdtr, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
+
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, ext, &deleteheader_index_tag, OPT_INDEX);
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, ext, &deleteheader_last_tag, OPT_LAST);
+
+ return TRUE;
+}
+
+/*
+ * Command validation context
+ */
+
+struct cmd_deleteheader_context_data {
+ struct sieve_ast_argument *arg_index;
+ struct sieve_ast_argument *arg_last;
+};
+
+/*
+ * Tag validation
+ */
+
+static struct cmd_deleteheader_context_data *
+cmd_deleteheader_get_context
+(struct sieve_command *cmd)
+{
+ struct cmd_deleteheader_context_data *ctx_data =
+ (struct cmd_deleteheader_context_data *)cmd->data;
+
+ if ( ctx_data != NULL ) return ctx_data;
+
+ ctx_data = p_new
+ (sieve_command_pool(cmd), struct cmd_deleteheader_context_data, 1);
+ cmd->data = (void *)ctx_data;
+
+ return ctx_data;
+}
+
+static bool cmd_deleteheader_validate_index_tag
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+ struct cmd_deleteheader_context_data *ctx_data;
+ sieve_number_t index;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ /* Check syntax:
+ * :index number
+ */
+ if ( !sieve_validate_tag_parameter
+ (valdtr, cmd, tag, *arg, NULL, 0, SAAT_NUMBER, FALSE) ) {
+ return FALSE;
+ }
+
+ index = sieve_ast_argument_number(*arg);
+ if ( index > INT_MAX ) {
+ sieve_argument_validate_warning(valdtr, *arg,
+ "the :%s tag for the %s %s has a parameter value '%llu' "
+ "exceeding the maximum (%d)",
+ sieve_argument_identifier(tag), sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd), (unsigned long long) index,
+ INT_MAX);
+ return FALSE;
+ }
+
+ ctx_data = cmd_deleteheader_get_context(cmd);
+ ctx_data->arg_index = *arg;
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+static bool cmd_deleteheader_validate_last_tag
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct cmd_deleteheader_context_data *ctx_data;
+
+ ctx_data = cmd_deleteheader_get_context(cmd);
+ ctx_data->arg_last = *arg;
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+/*
+ * Validation
+ */
+
+static bool cmd_deleteheader_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+ struct cmd_deleteheader_context_data *ctx_data =
+ (struct cmd_deleteheader_context_data *)cmd->data;
+ struct sieve_comparator cmp_default =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+ struct sieve_match_type mcht_default =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+
+ if ( ctx_data != NULL ) {
+ if ( ctx_data->arg_last != NULL && ctx_data->arg_index == NULL ) {
+ sieve_argument_validate_error(valdtr, ctx_data->arg_last,
+ "the :last tag for the %s %s cannot be specified "
+ "without the :index tag",
+ sieve_command_identifier(cmd), sieve_command_type_name(cmd));
+ }
+ }
+
+ /* Field name argument */
+
+ if ( arg == NULL ) {
+ sieve_command_validate_error(valdtr, cmd,
+ "the %s %s expects at least one positional argument, but none was found",
+ sieve_command_identifier(cmd), sieve_command_type_name(cmd));
+ return FALSE;
+ }
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, cmd, arg, "field name", 1, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, cmd, arg, FALSE) )
+ return FALSE;
+
+ if ( sieve_argument_is_string_literal(arg) ) {
+ string_t *fname = sieve_ast_argument_str(arg);
+
+ if ( !rfc2822_header_field_name_verify(str_c(fname), str_len(fname)) ) {
+ sieve_argument_validate_error(valdtr, arg, "deleteheader command:"
+ "specified field name `%s' is invalid",
+ str_sanitize(str_c(fname), 80));
+ return FALSE;
+ }
+
+ if ( !ext_editheader_header_allow_delete
+ (cmd->ext, str_c(fname)) ) {
+ sieve_argument_validate_warning
+ (valdtr, arg, "deleteheader command: "
+ "deleting specified header field `%s' is forbidden; "
+ "modification will be denied",
+ str_sanitize(str_c(fname), 80));
+ }
+ }
+
+ /* Value patterns argument */
+
+ arg = sieve_ast_argument_next(arg);
+ if ( arg == NULL ) {
+ /* There is none; let's not generate code for useless match arguments */
+ sieve_match_type_arguments_remove(valdtr, cmd);
+
+ return TRUE;
+ }
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, cmd, arg, "value patterns", 2, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, cmd, arg, FALSE) )
+ return FALSE;
+
+ /* Validate the value patterns to a specified match type */
+ return sieve_match_type_validate
+ (valdtr, cmd, arg, &mcht_default, &cmp_default);
+}
+
+/*
+ * Code generation
+ */
+
+static bool cmd_deleteheader_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &deleteheader_operation);
+
+ /* Generate arguments */
+ if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
+ return FALSE;
+
+ /* Emit a placeholder when the value-patterns argument is missing */
+ if ( sieve_ast_argument_next(cmd->first_positional) == NULL )
+ sieve_opr_omitted_emit(cgenv->sblock);
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool cmd_deleteheader_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "DELETEHEADER");
+ sieve_code_descend(denv);
+
+ /* Optional operands */
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_match_opr_optional_dump(denv, address, &opt_code)) < 0 )
+ return FALSE;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_INDEX:
+ if ( !sieve_opr_number_dump(denv, address, "index") )
+ return FALSE;
+ break;
+ case OPT_LAST:
+ sieve_code_dumpf(denv, "last");
+ break;
+ default:
+ return FALSE;
+ }
+ };
+
+ if ( !sieve_opr_string_dump(denv, address, "field name") )
+ return FALSE;
+
+ return sieve_opr_stringlist_dump_ex(denv, address, "value patterns", "");
+}
+
+/*
+ * Code execution
+ */
+
+static int cmd_deleteheader_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ int opt_code = 0;
+ struct sieve_comparator cmp =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+ struct sieve_match_type mcht =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ string_t *field_name;
+ struct sieve_stringlist *vpattern_list = NULL;
+ struct edit_mail *edmail;
+ sieve_number_t index_offset = 0;
+ bool index_last = FALSE;
+ bool trace = FALSE;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_match_opr_optional_read
+ (renv, address, &opt_code, &ret, &cmp, &mcht)) < 0 )
+ return ret;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_INDEX:
+ if ( (ret=sieve_opr_number_read(renv, address, "index", &index_offset))
+ <= 0 )
+ return ret;
+
+ if ( index_offset > INT_MAX ) {
+ sieve_runtime_trace_error(renv, "index is > %d", INT_MAX);
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ break;
+ case OPT_LAST:
+ index_last = TRUE;
+ break;
+ default:
+ sieve_runtime_trace_error(renv, "unknown optional operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ }
+
+ /* Read field-name */
+ if ( (ret=sieve_opr_string_read(renv, address, "field-name", &field_name))
+ <= 0 )
+ return ret;
+
+ /* Read value-patterns */
+ if ( (ret=sieve_opr_stringlist_read_ex
+ (renv, address, "value-patterns", TRUE, &vpattern_list)) <= 0 )
+ return ret;
+
+ /*
+ * Verify arguments
+ */
+
+ if ( !rfc2822_header_field_name_verify
+ (str_c(field_name), str_len(field_name)) ) {
+ sieve_runtime_error(renv, NULL, "deleteheader action: "
+ "specified field name `%s' is invalid",
+ str_sanitize(str_c(field_name), 80));
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ if ( !ext_editheader_header_allow_delete
+ (this_ext, str_c(field_name)) ) {
+ sieve_runtime_warning(renv, NULL, "deleteheader action: "
+ "deleting specified header field `%s' is forbidden; "
+ "modification denied",
+ str_sanitize(str_c(field_name), 80));
+ return SIEVE_EXEC_OK;
+ }
+
+ /*
+ * Execute command
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "deleteheader command");
+
+ /* Start editing the mail */
+ edmail = sieve_message_edit(renv->msgctx);
+
+ trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS);
+
+ /* Either do string matching or just kill all/indexed notify action(s) */
+ if ( vpattern_list != NULL ) {
+ struct edit_mail_header_iter *edhiter;
+ struct sieve_match_context *mctx;
+
+ if ( trace ) {
+ sieve_runtime_trace_descend(renv);
+ if ( index_offset != 0 ) {
+ sieve_runtime_trace(renv, 0,
+ "deleting matching occurrences of header `%s' at index %llu%s",
+ str_c(field_name), (unsigned long long)index_offset,
+ ( index_last ? " from last": ""));
+ } else {
+ sieve_runtime_trace(renv, 0,
+ "deleting matching occurrences of header `%s'", str_c(field_name));
+ }
+ }
+
+ /* Iterate through all headers and delete those that match */
+ if ( (ret=edit_mail_headers_iterate_init
+ (edmail, str_c(field_name), index_last, &edhiter)) > 0 )
+ {
+ int mret = 0;
+ sieve_number_t pos = 0;
+
+ /* Initialize match */
+ mctx = sieve_match_begin(renv, &mcht, &cmp);
+
+ /* Match */
+ for (;;) {
+ pos++;
+
+ /* Check index if any */
+ if ( index_offset == 0 || pos == index_offset ) {
+ const char *value;
+ int match;
+
+ /* Match value against all value patterns */
+ edit_mail_headers_iterate_get(edhiter, &value);
+ if ( (match=sieve_match_value
+ (mctx, value, strlen(value), vpattern_list)) < 0 )
+ break;
+
+ if ( match > 0 ) {
+ /* Remove it and iterate to next */
+ sieve_runtime_trace(renv, 0, "deleting header with value `%s'",
+ value);
+
+ if ( !edit_mail_headers_iterate_remove(edhiter) ) break;
+ continue;
+ }
+ }
+
+ if ( !edit_mail_headers_iterate_next(edhiter) )
+ break;
+ }
+
+ /* Finish match */
+ mret = sieve_match_end(&mctx, &ret);
+
+ edit_mail_headers_iterate_deinit(&edhiter);
+
+ if ( mret < 0 )
+ return ret;
+ }
+
+ if ( ret == 0 ) {
+ sieve_runtime_trace(renv, 0, "header `%s' not found", str_c(field_name));
+ } else if ( ret < 0 ) {
+ sieve_runtime_warning(renv, NULL, "deleteheader action: "
+ "failed to delete occurrences of header `%s' (this should not happen!)",
+ str_c(field_name));
+ }
+
+ } else {
+ int index = ( index_last ? -((int)index_offset) : ((int)index_offset) );
+
+ if ( trace ) {
+ sieve_runtime_trace_descend(renv);
+ if ( index_offset != 0 ) {
+ sieve_runtime_trace(renv, 0, "deleting header `%s' at index %llu%s",
+ str_c(field_name), (unsigned long long)index_offset,
+ ( index_last ? " from last": ""));
+ } else {
+ sieve_runtime_trace(renv, 0, "deleting header `%s'", str_c(field_name));
+ }
+ }
+
+ /* Delete all occurrences of header */
+ ret = edit_mail_header_delete(edmail, str_c(field_name), index);
+
+ if ( ret < 0 ) {
+ sieve_runtime_warning(renv, NULL, "deleteheader action: "
+ "failed to delete occurrences of header `%s' (this should not happen!)",
+ str_c(field_name));
+ } else if ( trace ) {
+ sieve_runtime_trace(renv, 0, "deleted %d occurrences of header `%s'",
+ ret, str_c(field_name));
+ }
+
+ }
+
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/editheader/ext-editheader-common.c b/pigeonhole/src/lib-sieve/plugins/editheader/ext-editheader-common.c
new file mode 100644
index 0000000..89fb180
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/editheader/ext-editheader-common.c
@@ -0,0 +1,211 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "mempool.h"
+#include "array.h"
+
+#include "rfc2822.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-settings.h"
+#include "sieve-extensions.h"
+
+#include "ext-editheader-limits.h"
+#include "ext-editheader-common.h"
+
+/*
+ * Extension configuration
+ */
+
+struct ext_editheader_header {
+ const char *name;
+
+ bool forbid_add:1;
+ bool forbid_delete:1;
+};
+
+struct ext_editheader_config {
+ pool_t pool;
+
+ ARRAY(struct ext_editheader_header) headers;
+
+ size_t max_header_size;
+};
+
+static struct ext_editheader_header *
+ext_editheader_config_header_find(struct ext_editheader_config *ext_config,
+ const char *hname)
+{
+ struct ext_editheader_header *headers;
+ unsigned int count, i;
+
+ headers = array_get_modifiable(&ext_config->headers, &count);
+ for (i = 0; i < count; i++) {
+ if (strcasecmp(hname, headers[i].name) == 0)
+ return &headers[i];
+ }
+ return NULL;
+}
+
+static void
+ext_editheader_config_headers(struct sieve_instance *svinst,
+ struct ext_editheader_config *ext_config,
+ const char *setting, bool forbid_add,
+ bool forbid_delete)
+{
+ const char *setval;
+
+ setval = sieve_setting_get(svinst, setting);
+ if (setval != NULL) {
+ const char **headers = t_strsplit_spaces(setval, " \t");
+
+ while (*headers != NULL) {
+ struct ext_editheader_header *header;
+
+ if (!rfc2822_header_field_name_verify(
+ *headers, strlen(*headers))) {
+ e_warning(svinst->event, "editheader: "
+ "setting %s contains invalid header field name "
+ "`%s' (ignored)",
+ setting, *headers);
+ headers++;
+ continue;
+ }
+
+ header = ext_editheader_config_header_find(
+ ext_config, *headers);
+ if (header == NULL) {
+ header = array_append_space(
+ &ext_config->headers);
+ header->name = p_strdup(ext_config->pool,
+ *headers);
+ }
+
+ if (forbid_add)
+ header->forbid_add = TRUE;
+ if (forbid_delete)
+ header->forbid_delete = TRUE;
+
+ headers++;
+ }
+ }
+}
+
+bool ext_editheader_load(const struct sieve_extension *ext, void **context)
+{
+ struct ext_editheader_config *ext_config;
+ struct sieve_instance *svinst = ext->svinst;
+ size_t max_header_size;
+ pool_t pool;
+
+ if (*context != NULL) {
+ ext_editheader_unload(ext);
+ *context = NULL;
+ }
+
+ T_BEGIN {
+ pool = pool_alloconly_create("editheader_config", 1024);
+ ext_config = p_new(pool, struct ext_editheader_config, 1);
+ ext_config->pool = pool;
+ ext_config->max_header_size =
+ EXT_EDITHEADER_DEFAULT_MAX_HEADER_SIZE;
+
+ p_array_init(&ext_config->headers, pool, 16);
+
+ ext_editheader_config_headers(
+ svinst, ext_config,
+ "sieve_editheader_protected", TRUE, TRUE);
+ ext_editheader_config_headers(
+ svinst, ext_config,
+ "sieve_editheader_forbid_add", TRUE, FALSE);
+ ext_editheader_config_headers(
+ svinst, ext_config,
+ "sieve_editheader_forbid_delete", FALSE, TRUE);
+
+ if (sieve_setting_get_size_value(
+ svinst, "sieve_editheader_max_header_size",
+ &max_header_size)) {
+ if (max_header_size < EXT_EDITHEADER_MINIMUM_MAX_HEADER_SIZE) {
+ e_warning(svinst->event, "editheader: "
+ "value of sieve_editheader_max_header_size setting "
+ "(=%zu) is less than the minimum (=%zu) "
+ "(ignored)", max_header_size,
+ (size_t)EXT_EDITHEADER_MINIMUM_MAX_HEADER_SIZE);
+ } else {
+ ext_config->max_header_size = max_header_size;
+ }
+ }
+ } T_END;
+
+ *context = (void *)ext_config;
+ return TRUE;
+}
+
+void ext_editheader_unload(const struct sieve_extension *ext)
+{
+ struct ext_editheader_config *ext_config =
+ (struct ext_editheader_config *)ext->context;
+
+ if (ext_config != NULL)
+ pool_unref(&ext_config->pool);
+}
+
+/*
+ * Protected headers
+ */
+
+bool ext_editheader_header_allow_add(const struct sieve_extension *ext,
+ const char *hname)
+{
+ struct ext_editheader_config *ext_config =
+ (struct ext_editheader_config *)ext->context;
+ const struct ext_editheader_header *header;
+
+ if (strcasecmp(hname, "subject") == 0)
+ return TRUE;
+ if (strcasecmp(hname, "x-sieve-redirected-from") == 0)
+ return FALSE;
+
+ header = ext_editheader_config_header_find(ext_config, hname);
+ if (header == NULL)
+ return TRUE;
+
+ return !header->forbid_add;
+}
+
+bool ext_editheader_header_allow_delete(const struct sieve_extension *ext,
+ const char *hname)
+{
+ struct ext_editheader_config *ext_config =
+ (struct ext_editheader_config *)ext->context;
+ const struct ext_editheader_header *header;
+
+ if (strcasecmp(hname, "received") == 0 ||
+ strcasecmp(hname, "auto-submitted") == 0)
+ return FALSE;
+ if (strcasecmp(hname, "x-sieve-redirected-from") == 0)
+ return FALSE;
+ if (strcasecmp(hname, "subject") == 0)
+ return TRUE;
+
+ header = ext_editheader_config_header_find(ext_config, hname);
+ if (header == NULL)
+ return TRUE;
+
+ return !header->forbid_delete;
+}
+
+/*
+ * Limits
+ */
+
+bool ext_editheader_header_too_large(const struct sieve_extension *ext,
+ size_t size)
+{
+ struct ext_editheader_config *ext_config =
+ (struct ext_editheader_config *)ext->context;
+
+ return size > ext_config->max_header_size;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/editheader/ext-editheader-common.h b/pigeonhole/src/lib-sieve/plugins/editheader/ext-editheader-common.h
new file mode 100644
index 0000000..8a6cc36
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/editheader/ext-editheader-common.h
@@ -0,0 +1,48 @@
+#ifndef EXT_EDITHEADER_COMMON_H
+#define EXT_EDITHEADER_COMMON_H
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def addheader_command;
+extern const struct sieve_command_def deleteheader_command;
+
+/*
+ * Operations
+ */
+
+enum ext_imap4flags_opcode {
+ EXT_EDITHEADER_OPERATION_ADDHEADER,
+ EXT_EDITHEADER_OPERATION_DELETEHEADER,
+};
+
+extern const struct sieve_operation_def addheader_operation;
+extern const struct sieve_operation_def deleteheader_operation;
+
+/*
+ * Extension
+ */
+
+extern const struct sieve_extension_def editheader_extension;
+
+bool ext_editheader_load(const struct sieve_extension *ext, void **context);
+void ext_editheader_unload(const struct sieve_extension *ext);
+
+/*
+ * Protected headers
+ */
+
+bool ext_editheader_header_allow_add(const struct sieve_extension *ext,
+ const char *hname);
+bool ext_editheader_header_allow_delete(const struct sieve_extension *ext,
+ const char *hname);
+
+/*
+ * Limits
+ */
+
+bool ext_editheader_header_too_large(const struct sieve_extension *ext,
+ size_t size);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/editheader/ext-editheader-limits.h b/pigeonhole/src/lib-sieve/plugins/editheader/ext-editheader-limits.h
new file mode 100644
index 0000000..a8e834b
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/editheader/ext-editheader-limits.h
@@ -0,0 +1,7 @@
+#ifndef EXT_EDITHEADER_LIMITS_H
+#define EXT_EDITHEADER_LIMITS_H
+
+#define EXT_EDITHEADER_MINIMUM_MAX_HEADER_SIZE 1024
+#define EXT_EDITHEADER_DEFAULT_MAX_HEADER_SIZE 2048
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/editheader/ext-editheader.c b/pigeonhole/src/lib-sieve/plugins/editheader/ext-editheader.c
new file mode 100644
index 0000000..dc8eb12
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/editheader/ext-editheader.c
@@ -0,0 +1,66 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension debug
+ * ---------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5293
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "lib.h"
+#include "array.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-address-parts.h"
+
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-editheader-common.h"
+
+/*
+ * Operations
+ */
+
+const struct sieve_operation_def *editheader_operations[] = {
+ &addheader_operation,
+ &deleteheader_operation
+};
+
+/*
+ * Extension
+ */
+
+static bool ext_editheader_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *validator);
+
+const struct sieve_extension_def editheader_extension = {
+ .name = "editheader",
+ .load = ext_editheader_load,
+ .unload = ext_editheader_unload,
+ .validator_load = ext_editheader_validator_load,
+ SIEVE_EXT_DEFINE_OPERATIONS(editheader_operations)
+};
+
+static bool ext_editheader_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *validator)
+{
+ /* Register new commands */
+ sieve_validator_register_command(validator, ext, &addheader_command);
+ sieve_validator_register_command(validator, ext, &deleteheader_command);
+
+ return TRUE;
+}
+
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/Makefile.am b/pigeonhole/src/lib-sieve/plugins/enotify/Makefile.am
new file mode 100644
index 0000000..4b65630
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/enotify/Makefile.am
@@ -0,0 +1,44 @@
+SUBDIRS = mailto
+
+noinst_LTLIBRARIES = libsieve_ext_enotify.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../variables \
+ $(LIBDOVECOT_INCLUDE)
+
+commands = \
+ cmd-notify.c
+
+tests = \
+ tst-valid-notify-method.c \
+ tst-notify-method-capability.c
+
+var_modifiers = \
+ vmodf-encodeurl.c
+
+notify_methods = \
+ ./mailto/libsieve_ext_enotify_mailto.la
+
+libsieve_ext_enotify_la_DEPENDENCIES = \
+ $(notify_methods)
+libsieve_ext_enotify_la_LIBADD = \
+ $(notify_methods)
+
+libsieve_ext_enotify_la_SOURCES = \
+ ext-enotify.c \
+ ext-enotify-common.c \
+ $(commands) \
+ $(tests) \
+ $(var_modifiers)
+
+public_headers = \
+ sieve-ext-enotify.h
+
+headers = \
+ ext-enotify-limits.h \
+ ext-enotify-common.h
+
+pkginc_libdir=$(dovecot_pkgincludedir)/sieve
+pkginc_lib_HEADERS = $(public_headers)
+noinst_HEADERS = $(headers)
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/Makefile.in b/pigeonhole/src/lib-sieve/plugins/enotify/Makefile.in
new file mode 100644
index 0000000..fea2423
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/enotify/Makefile.in
@@ -0,0 +1,904 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/enotify
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(pkginc_lib_HEADERS) $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__objects_1 = cmd-notify.lo
+am__objects_2 = tst-valid-notify-method.lo \
+ tst-notify-method-capability.lo
+am__objects_3 = vmodf-encodeurl.lo
+am_libsieve_ext_enotify_la_OBJECTS = ext-enotify.lo \
+ ext-enotify-common.lo $(am__objects_1) $(am__objects_2) \
+ $(am__objects_3)
+libsieve_ext_enotify_la_OBJECTS = \
+ $(am_libsieve_ext_enotify_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cmd-notify.Plo \
+ ./$(DEPDIR)/ext-enotify-common.Plo ./$(DEPDIR)/ext-enotify.Plo \
+ ./$(DEPDIR)/tst-notify-method-capability.Plo \
+ ./$(DEPDIR)/tst-valid-notify-method.Plo \
+ ./$(DEPDIR)/vmodf-encodeurl.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_enotify_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_enotify_la_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkginc_libdir)"
+HEADERS = $(noinst_HEADERS) $(pkginc_lib_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = mailto
+noinst_LTLIBRARIES = libsieve_ext_enotify.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../variables \
+ $(LIBDOVECOT_INCLUDE)
+
+commands = \
+ cmd-notify.c
+
+tests = \
+ tst-valid-notify-method.c \
+ tst-notify-method-capability.c
+
+var_modifiers = \
+ vmodf-encodeurl.c
+
+notify_methods = \
+ ./mailto/libsieve_ext_enotify_mailto.la
+
+libsieve_ext_enotify_la_DEPENDENCIES = \
+ $(notify_methods)
+
+libsieve_ext_enotify_la_LIBADD = \
+ $(notify_methods)
+
+libsieve_ext_enotify_la_SOURCES = \
+ ext-enotify.c \
+ ext-enotify-common.c \
+ $(commands) \
+ $(tests) \
+ $(var_modifiers)
+
+public_headers = \
+ sieve-ext-enotify.h
+
+headers = \
+ ext-enotify-limits.h \
+ ext-enotify-common.h
+
+pkginc_libdir = $(dovecot_pkgincludedir)/sieve
+pkginc_lib_HEADERS = $(public_headers)
+noinst_HEADERS = $(headers)
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/enotify/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/enotify/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_enotify.la: $(libsieve_ext_enotify_la_OBJECTS) $(libsieve_ext_enotify_la_DEPENDENCIES) $(EXTRA_libsieve_ext_enotify_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_enotify_la_OBJECTS) $(libsieve_ext_enotify_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-notify.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-enotify-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-enotify.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-notify-method-capability.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-valid-notify-method.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vmodf-encodeurl.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
+ done
+
+uninstall-pkginc_libHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(pkginc_libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f ./$(DEPDIR)/cmd-notify.Plo
+ -rm -f ./$(DEPDIR)/ext-enotify-common.Plo
+ -rm -f ./$(DEPDIR)/ext-enotify.Plo
+ -rm -f ./$(DEPDIR)/tst-notify-method-capability.Plo
+ -rm -f ./$(DEPDIR)/tst-valid-notify-method.Plo
+ -rm -f ./$(DEPDIR)/vmodf-encodeurl.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-pkginc_libHEADERS
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f ./$(DEPDIR)/cmd-notify.Plo
+ -rm -f ./$(DEPDIR)/ext-enotify-common.Plo
+ -rm -f ./$(DEPDIR)/ext-enotify.Plo
+ -rm -f ./$(DEPDIR)/tst-notify-method-capability.Plo
+ -rm -f ./$(DEPDIR)/tst-valid-notify-method.Plo
+ -rm -f ./$(DEPDIR)/vmodf-encodeurl.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-pkginc_libHEADERS
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--depfiles check check-am clean clean-generic clean-libtool \
+ clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pkginc_libHEADERS \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am \
+ uninstall-pkginc_libHEADERS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/cmd-notify.c b/pigeonhole/src/lib-sieve/plugins/enotify/cmd-notify.c
new file mode 100644
index 0000000..4fe121a
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/enotify/cmd-notify.c
@@ -0,0 +1,621 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-result.h"
+
+#include "ext-enotify-common.h"
+
+/*
+ * Forward declarations
+ */
+
+static const struct sieve_argument_def notify_importance_tag;
+static const struct sieve_argument_def notify_from_tag;
+static const struct sieve_argument_def notify_options_tag;
+static const struct sieve_argument_def notify_message_tag;
+
+/*
+ * Notify command
+ *
+ * Syntax:
+ * notify [":from" string]
+ * [":importance" <"1" / "2" / "3">]
+ * [":options" string-list]
+ * [":message" string]
+ * <method: string>
+ */
+
+static bool
+cmd_notify_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool
+cmd_notify_pre_validate(struct sieve_validator *validator,
+ struct sieve_command *cmd);
+static bool
+cmd_notify_validate(struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool
+cmd_notify_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+const struct sieve_command_def notify_command = {
+ .identifier = "notify",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = cmd_notify_registered,
+ .pre_validate = cmd_notify_pre_validate,
+ .validate = cmd_notify_validate,
+ .generate = cmd_notify_generate,
+};
+
+/*
+ * Notify command tags
+ */
+
+/* Forward declarations */
+
+static bool
+cmd_notify_validate_string_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool
+cmd_notify_validate_stringlist_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool
+cmd_notify_validate_importance_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+/* Argument objects */
+
+static const struct sieve_argument_def notify_from_tag = {
+ .identifier = "from",
+ .validate = cmd_notify_validate_string_tag
+};
+
+static const struct sieve_argument_def notify_options_tag = {
+ .identifier = "options",
+ .validate = cmd_notify_validate_stringlist_tag
+};
+
+static const struct sieve_argument_def notify_message_tag = {
+ .identifier = "message",
+ .validate = cmd_notify_validate_string_tag
+};
+
+static const struct sieve_argument_def notify_importance_tag = {
+ .identifier = "importance",
+ .validate = cmd_notify_validate_importance_tag
+};
+
+/*
+ * Notify operation
+ */
+
+static bool
+cmd_notify_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_notify_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def notify_operation = {
+ .mnemonic = "NOTIFY",
+ .ext_def = &enotify_extension,
+ .code = EXT_ENOTIFY_OPERATION_NOTIFY,
+ .dump = cmd_notify_operation_dump,
+ .execute = cmd_notify_operation_execute
+};
+
+/*
+ * Notify action
+ */
+
+/* Forward declarations */
+
+static int
+act_notify_check_duplicate(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other);
+static void
+act_notify_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv,
+ bool *keep);
+static int
+act_notify_commit(const struct sieve_action_exec_env *aenv, void *tr_context);
+
+/* Action object */
+
+const struct sieve_action_def act_notify = {
+ .name = "notify",
+ .check_duplicate =act_notify_check_duplicate,
+ .print = act_notify_print,
+ .commit = act_notify_commit,
+};
+
+/*
+ * Command validation context
+ */
+
+struct cmd_notify_context_data {
+ struct sieve_ast_argument *from;
+ struct sieve_ast_argument *message;
+ struct sieve_ast_argument *options;
+};
+
+/*
+ * Tag validation
+ */
+
+static bool
+cmd_notify_validate_string_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+ struct cmd_notify_context_data *ctx_data =
+ (struct cmd_notify_context_data *)cmd->data;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ /* Check syntax:
+ * :from <string>
+ * :message <string>
+ */
+ if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0,
+ SAAT_STRING, FALSE))
+ return FALSE;
+
+ if (sieve_argument_is(tag, notify_from_tag)) {
+ ctx_data->from = *arg;
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+ } else if (sieve_argument_is(tag, notify_message_tag)) {
+ ctx_data->message = *arg;
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+ }
+ return TRUE;
+}
+
+static bool
+cmd_notify_validate_stringlist_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+ struct cmd_notify_context_data *ctx_data =
+ (struct cmd_notify_context_data *)cmd->data;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ /* Check syntax:
+ * :options string-list
+ */
+ if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0,
+ SAAT_STRING_LIST, FALSE))
+ return FALSE;
+
+ /* Assign context */
+ ctx_data->options = *arg;
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+static bool
+cmd_notify_validate_importance_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ const struct sieve_ast_argument *tag = *arg;
+ const char *impstr;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ /* Check syntax:
+ * :importance <"1" / "2" / "3">
+ */
+ if (sieve_ast_argument_type(*arg) != SAAT_STRING) {
+ /* Not a string */
+ sieve_argument_validate_error(
+ valdtr, *arg,
+ "the :importance tag for the notify command requires a string parameter, "
+ "but %s was found", sieve_ast_argument_name(*arg));
+ return FALSE;
+ }
+
+ impstr = sieve_ast_argument_strc(*arg);
+ if (impstr[0] < '1' || impstr[0] > '3' || impstr[1] != '\0') {
+ /* Invalid importance */
+ sieve_argument_validate_error(
+ valdtr, *arg,
+ "invalid :importance value for notify command: %s",
+ impstr);
+ return FALSE;
+ }
+
+ sieve_ast_argument_number_substitute(*arg, impstr[0] - '0');
+ (*arg)->argument = sieve_argument_create((*arg)->ast, &number_argument,
+ tag->argument->ext,
+ tag->argument->id_code);
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+/*
+ * Command registration
+ */
+
+static bool
+cmd_notify_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &notify_importance_tag,
+ CMD_NOTIFY_OPT_IMPORTANCE);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &notify_from_tag, CMD_NOTIFY_OPT_FROM);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &notify_options_tag,
+ CMD_NOTIFY_OPT_OPTIONS);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &notify_message_tag,
+ CMD_NOTIFY_OPT_MESSAGE);
+ return TRUE;
+}
+
+/*
+ * Command validation
+ */
+
+static bool
+cmd_notify_pre_validate(struct sieve_validator *validator ATTR_UNUSED,
+ struct sieve_command *cmd)
+{
+ struct cmd_notify_context_data *ctx_data;
+
+ /* Assign context */
+ ctx_data = p_new(sieve_command_pool(cmd),
+ struct cmd_notify_context_data, 1);
+ cmd->data = ctx_data;
+
+ return TRUE;
+}
+
+static bool
+cmd_notify_validate(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+ struct cmd_notify_context_data *ctx_data =
+ (struct cmd_notify_context_data *)cmd->data;
+
+ if (!sieve_validate_positional_argument(valdtr, cmd, arg, "method", 1,
+ SAAT_STRING))
+ return FALSE;
+
+ if (!sieve_validator_argument_activate(valdtr, cmd, arg, FALSE))
+ return FALSE;
+
+ return ext_enotify_compile_check_arguments(
+ valdtr, cmd, arg, ctx_data->message, ctx_data->from,
+ ctx_data->options);
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+cmd_notify_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &notify_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, cmd, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+cmd_notify_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "NOTIFY");
+ sieve_code_descend(denv);
+
+ /* Dump optional operands */
+
+ for (;;) {
+ int opt;
+ bool opok = TRUE;
+
+ if ((opt = sieve_opr_optional_dump(denv, address,
+ &opt_code)) < 0)
+ return FALSE;
+
+ if (opt == 0)
+ break;
+
+ switch (opt_code) {
+ case CMD_NOTIFY_OPT_IMPORTANCE:
+ opok = sieve_opr_number_dump(denv, address,
+ "importance");
+ break;
+ case CMD_NOTIFY_OPT_FROM:
+ opok = sieve_opr_string_dump(denv, address, "from");
+ break;
+ case CMD_NOTIFY_OPT_OPTIONS:
+ opok = sieve_opr_stringlist_dump(denv, address,
+ "options");
+ break;
+ case CMD_NOTIFY_OPT_MESSAGE:
+ opok = sieve_opr_string_dump(denv, address, "message");
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (!opok)
+ return FALSE;
+ }
+
+ /* Dump method operand */
+ return sieve_opr_string_dump(denv, address, "method");
+}
+
+/*
+ * Code execution
+ */
+
+static int
+cmd_notify_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ struct sieve_side_effects_list *slist = NULL;
+ struct sieve_enotify_action *act;
+ void *method_context;
+ pool_t pool;
+ int opt_code = 0;
+ sieve_number_t importance = 2;
+ struct sieve_stringlist *options = NULL;
+ const struct sieve_enotify_method *method;
+ string_t *method_uri, *message = NULL, *from = NULL;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Optional operands */
+
+ for (;;) {
+ int opt;
+
+ if ((opt = sieve_opr_optional_read(renv, address,
+ &opt_code)) < 0)
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ if (opt == 0) break;
+
+ switch (opt_code) {
+ case CMD_NOTIFY_OPT_IMPORTANCE:
+ ret = sieve_opr_number_read(renv, address, "importance",
+ &importance);
+ break;
+ case CMD_NOTIFY_OPT_FROM:
+ ret = sieve_opr_string_read(renv, address, "from",
+ &from);
+ break;
+ case CMD_NOTIFY_OPT_MESSAGE:
+ ret = sieve_opr_string_read(renv, address, "message",
+ &message);
+ break;
+ case CMD_NOTIFY_OPT_OPTIONS:
+ ret = sieve_opr_stringlist_read(renv, address,
+ "options", &options);
+ break;
+ default:
+ sieve_runtime_trace_error(
+ renv, "unknown optional operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if (ret <= 0)
+ return ret;
+ }
+
+ /* Method operand */
+
+ if ((ret = sieve_opr_string_read(renv, address, "method",
+ &method_uri)) <= 0)
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ /* Enforce 0 < importance < 4 (just to be sure) */
+
+ if (importance < 1)
+ importance = 1;
+ else if (importance > 3)
+ importance = 3;
+
+ /* Trace */
+
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_ACTIONS)) {
+ sieve_runtime_trace(renv, 0, "notify action");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(renv, 0, "notify with uri `%s'",
+ str_sanitize(str_c(method_uri), 80));
+ }
+
+ /* Check operands */
+
+ if ((ret = ext_enotify_runtime_check_operands(renv, method_uri, message,
+ from, options, &method,
+ &method_context)) > 0)
+ {
+ /* Add notify action to the result */
+ pool = sieve_result_pool(renv->result);
+ act = p_new(pool, struct sieve_enotify_action, 1);
+ act->method = method;
+ act->method_context = method_context;
+ act->importance = importance;
+ if (message != NULL)
+ act->message = p_strdup(pool, str_c(message));
+ if (from != NULL)
+ act->from = p_strdup(pool, str_c(from));
+
+ if (sieve_result_add_action(renv, this_ext, "notify",
+ &act_notify, slist,
+ (void *)act, 0, FALSE) < 0)
+ return SIEVE_EXEC_FAILURE;
+
+ return SIEVE_EXEC_OK;
+ }
+ return ret;
+}
+
+/*
+ * Action
+ */
+
+/* Runtime verification */
+
+static int
+act_notify_check_duplicate(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_enotify_action *nact, *nact_other;
+ const struct sieve_enotify_method_def *nmth_def;
+ struct sieve_enotify_env nenv;
+ int result;
+
+ if (act->context == NULL || act_other->context == NULL)
+ return 0;
+
+ nact = (const struct sieve_enotify_action *)act->context;
+ nact_other = (const struct sieve_enotify_action *)act_other->context;
+
+ if (nact->method == NULL || nact->method->def == NULL)
+ return 0;
+
+ nmth_def = nact->method->def;
+ if (nmth_def->action_check_duplicates == NULL)
+ return 0;
+
+ i_zero(&nenv);
+ nenv.svinst = eenv->svinst;
+ nenv.method = nact->method;
+ nenv.ehandler = renv->ehandler;
+ nenv.location = act->location;
+ nenv.event = event_create(nenv.svinst->event);
+ event_set_append_log_prefix(nenv.event, "notify: ");
+
+ result = nmth_def->action_check_duplicates(&nenv, nact, nact_other);
+
+ event_unref(&nenv.event);
+
+ return result;
+}
+
+/* Result printing */
+
+static void
+act_notify_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv,
+ bool *keep ATTR_UNUSED)
+{
+ const struct sieve_enotify_action *act =
+ (const struct sieve_enotify_action *)action->context;
+ const struct sieve_enotify_method *method;
+
+ method = act->method;
+
+ if (method->def != NULL) {
+ sieve_result_action_printf(
+ rpenv, "send notification with method '%s:':",
+ method->def->identifier);
+
+ if (method->def->action_print != NULL) {
+ struct sieve_enotify_print_env penv;
+
+ i_zero(&penv);
+ penv.result_penv = rpenv;
+
+ method->def->action_print(&penv, act);
+ }
+ }
+}
+
+/* Result execution */
+
+static int
+act_notify_commit(const struct sieve_action_exec_env *aenv,
+ void *tr_context ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ const struct sieve_enotify_action *act =
+ (const struct sieve_enotify_action *)aenv->action->context;
+ const struct sieve_enotify_method *method = act->method;
+ struct sieve_enotify_exec_env nenv;
+ int ret = 0;
+
+ if (method->def != NULL && method->def->action_execute != NULL) {
+ /* Compose log structure */
+ i_zero(&nenv);
+ nenv.svinst = eenv->svinst;
+ nenv.flags = eenv->flags;
+ nenv.method = method;
+ nenv.scriptenv = eenv->scriptenv;
+ nenv.msgdata = eenv->msgdata;
+ nenv.msgctx = aenv->msgctx;
+
+ nenv.ehandler = aenv->ehandler;
+ nenv.event = aenv->event;
+
+ ret = method->def->action_execute(&nenv, act);
+ if (ret >= 0)
+ eenv->exec_status->significant_action_executed = TRUE;
+ }
+
+ return (ret >= 0 ? SIEVE_EXEC_OK : SIEVE_EXEC_TEMP_FAILURE);
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-common.c b/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-common.c
new file mode 100644
index 0000000..e0539f0
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-common.c
@@ -0,0 +1,718 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-ast.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-interpreter.h"
+#include "sieve-result.h"
+
+#include "ext-enotify-limits.h"
+#include "ext-enotify-common.h"
+
+#include <ctype.h>
+
+/* FIXME: (from draft RFC)
+
+ Header/envelope tests [Sieve] together with Sieve variables can be used to
+ extract the list of users to receive notifications from the incoming email
+ message or its envelope. This is potentially quite dangerous, as this can be
+ used for Deny Of Service attacks on recipients controlled by the message
+ sender. For this reason implementations SHOULD NOT allow use of variables
+ containing values extracted from the email message in the method parameter to
+ the notify action. Note that violation of this SHOULD NOT may result in* the
+ creation of an open relay, i.e. any sender would be able to create specially
+ crafted email messages that would result in notifications delivered to
+ recipients under the control of the sender. In worst case this might result
+ in financial loss by user controlling the Sieve script and/or by recipients
+ of notifications (e.g. if a notification is an SMS message).
+
+ --> This is currently not possible to check.
+ */
+
+/*
+ * Notify capability
+ */
+
+static const char *
+ext_notify_get_methods_string(const struct sieve_extension *ntfy_ext);
+
+const struct sieve_extension_capabilities notify_capabilities = {
+ "notify",
+ ext_notify_get_methods_string
+};
+
+/*
+ * Core notification methods
+ */
+
+extern const struct sieve_enotify_method_def mailto_notify;
+
+/*
+ * Notify method registry
+ */
+
+static const struct sieve_enotify_method *
+ext_enotify_method_register(struct sieve_instance *svinst,
+ struct ext_enotify_context *ectx,
+ const struct sieve_enotify_method_def *nmth_def)
+{
+ struct sieve_enotify_method *nmth;
+ int nmth_id = (int)array_count(&ectx->notify_methods);
+
+ nmth = array_append_space(&ectx->notify_methods);
+ nmth->def = nmth_def;
+ nmth->id = nmth_id;
+ nmth->svinst = svinst;
+
+ if (nmth_def->load != NULL)
+ nmth_def->load(nmth, &nmth->context);
+
+ return nmth;
+}
+
+void ext_enotify_methods_init(struct sieve_instance *svinst,
+ struct ext_enotify_context *ectx)
+{
+ p_array_init(&ectx->notify_methods, default_pool, 4);
+
+ ext_enotify_method_register(svinst, ectx, &mailto_notify);
+}
+
+void ext_enotify_methods_deinit(struct ext_enotify_context *ectx)
+{
+ const struct sieve_enotify_method *methods;
+ unsigned int meth_count, i;
+
+ methods = array_get(&ectx->notify_methods, &meth_count);
+ for (i = 0; i < meth_count; i++) {
+ if (methods[i].def != NULL && methods[i].def->unload != NULL)
+ methods[i].def->unload(&methods[i]);
+ }
+
+ array_free(&ectx->notify_methods);
+}
+
+const struct sieve_enotify_method *
+sieve_enotify_method_register(struct sieve_instance *svinst,
+ const struct sieve_enotify_method_def *nmth_def)
+{
+ const struct sieve_extension *ntfy_ext =
+ sieve_extension_get_by_name(svinst, "enotify");
+
+ if (ntfy_ext != NULL) {
+ struct ext_enotify_context *ectx =
+ (struct ext_enotify_context *) ntfy_ext->context;
+
+ return ext_enotify_method_register(svinst, ectx, nmth_def);
+ }
+ return NULL;
+}
+
+void sieve_enotify_method_unregister(const struct sieve_enotify_method *nmth)
+{
+ struct sieve_instance *svinst = nmth->svinst;
+ const struct sieve_extension *ntfy_ext =
+ sieve_extension_get_by_name(svinst, "enotify");
+
+ if (ntfy_ext != NULL) {
+ struct ext_enotify_context *ectx =
+ (struct ext_enotify_context *) ntfy_ext->context;
+ int nmth_id = nmth->id;
+
+ if (nmth_id >= 0 &&
+ nmth_id < (int)array_count(&ectx->notify_methods)) {
+ struct sieve_enotify_method *nmth_mod =
+ array_idx_modifiable(&ectx->notify_methods,
+ nmth_id);
+
+ nmth_mod->def = NULL;
+ }
+ }
+}
+
+const struct sieve_enotify_method *
+ext_enotify_method_find(const struct sieve_extension *ntfy_ext,
+ const char *identifier)
+{
+ struct ext_enotify_context *ectx =
+ (struct ext_enotify_context *)ntfy_ext->context;
+ unsigned int meth_count, i;
+ const struct sieve_enotify_method *methods;
+
+ methods = array_get(&ectx->notify_methods, &meth_count);
+ for (i = 0; i < meth_count; i++) {
+ if (methods[i].def == NULL)
+ continue;
+
+ if (strcasecmp(methods[i].def->identifier, identifier) == 0)
+ return &methods[i];
+ }
+ return NULL;
+}
+
+static const char *
+ext_notify_get_methods_string(const struct sieve_extension *ntfy_ext)
+{
+ struct ext_enotify_context *ectx =
+ (struct ext_enotify_context *) ntfy_ext->context;
+ unsigned int meth_count, i;
+ const struct sieve_enotify_method *methods;
+ string_t *result = t_str_new(128);
+
+ methods = array_get(&ectx->notify_methods, &meth_count);
+ if (meth_count > 0) {
+ for (i = 0; i < meth_count; i++) {
+ if (str_len(result) > 0)
+ str_append_c(result, ' ');
+ if (methods[i].def != NULL)
+ str_append(result, methods[i].def->identifier);
+ }
+ return str_c(result);
+ }
+ return NULL;
+}
+
+/*
+ * Compile-time argument validation
+ */
+
+static const char *ext_enotify_uri_scheme_parse(const char **uri_p)
+{
+ string_t *scheme = t_str_new(EXT_ENOTIFY_MAX_SCHEME_LEN);
+ const char *p = *uri_p;
+ unsigned int len = 0;
+
+ /* RFC 3968:
+
+ scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+
+ FIXME: we do not allow '%' in schemes. Is this correct?
+ */
+
+ if (!i_isalpha(*p))
+ return NULL;
+
+ str_append_c(scheme, *p);
+ p++;
+
+ while (*p != '\0' && len < EXT_ENOTIFY_MAX_SCHEME_LEN) {
+ if (!i_isalnum(*p) && *p != '+' && *p != '-' && *p != '.')
+ break;
+
+ str_append_c(scheme, *p);
+ p++;
+ len++;
+ }
+
+ if (*p != ':')
+ return NULL;
+ p++;
+
+ *uri_p = p;
+ return str_c(scheme);
+}
+
+static bool
+ext_enotify_option_parse(struct sieve_enotify_env *nenv,
+ const char *option, bool name_only,
+ const char **opt_name_r, const char **opt_value_r)
+{
+ const char *p = option;
+
+ /* "<optionname>=<value>".
+
+ l-d = ALPHA / DIGIT
+ l-d-p = l-d / "." / "-" / "_"
+ optionname = l-d *l-d-p
+ value = *(%x01-09 / %x0B-0C / %x0E-FF)
+ */
+
+ /*
+ * Parse option name
+ */
+
+ /* optionname = l-d *l-d-p
+ */
+
+ /* Explicitly report empty option as such */
+ if (*p == '\0') {
+ sieve_enotify_error(nenv, "empty option specified");
+ return FALSE;
+ }
+
+ /* l-d = ALPHA / DIGIT */
+ if (i_isalnum(*p)) {
+ p++;
+
+ /* l-d-p = l-d / "." / "-" / "_" */
+ while (i_isalnum(*p) || *p == '.' || *p == '-' || *p == '_')
+ p++;
+ }
+
+ /* Parsing must end at '=' and we must parse at least one character */
+ if (*p != '=' || p == option) {
+ sieve_enotify_error(
+ nenv, "invalid option name specified in option '%s'",
+ str_sanitize(option, 80));
+ return FALSE;
+ }
+
+ /* Assign option name */
+ if (opt_name_r != NULL)
+ *opt_name_r = t_strdup_until(option, p);
+
+ /* Skip '=' */
+ p++;
+
+ /* Exit now if only the option name is of interest */
+ if (name_only)
+ return TRUE;
+
+ /*
+ * Parse option value
+ */
+
+ /* value = *(%x01-09 / %x0B-0C / %x0E-FF) */
+ while (*p != '\0' && *p != 0x0A && *p != 0x0D)
+ p++;
+
+ /* Parse must end at end of string */
+ if (*p != '\0') {
+ sieve_enotify_error(
+ nenv, "notify command: "
+ "invalid option value specified in option '%s'",
+ str_sanitize(option, 80));
+ return FALSE;
+ }
+
+ /* Assign option value */
+ if (opt_value_r != NULL)
+ *opt_value_r = p;
+
+ return TRUE;
+}
+
+struct _ext_enotify_option_check_context {
+ struct sieve_instance *svinst;
+ struct sieve_validator *valdtr;
+ const struct sieve_enotify_method *method;
+};
+
+static int
+_ext_enotify_option_check(void *context, struct sieve_ast_argument *arg)
+{
+ struct _ext_enotify_option_check_context *optn_context =
+ (struct _ext_enotify_option_check_context *) context;
+ struct sieve_validator *valdtr = optn_context->valdtr;
+ const struct sieve_enotify_method *method = optn_context->method;
+ struct sieve_enotify_env nenv;
+ const char *option = sieve_ast_argument_strc(arg);
+ const char *opt_name = NULL, *opt_value = NULL;
+ bool check = TRUE;
+ int result = 1;
+
+ /* Compose log structure */
+ i_zero(&nenv);
+ nenv.svinst = optn_context->svinst;
+ nenv.method = method;
+ nenv.ehandler = sieve_validator_error_handler(valdtr);
+ nenv.location = sieve_error_script_location(
+ sieve_validator_script(valdtr), arg->source_line);
+ nenv.event = event_create(nenv.svinst->event);
+ event_set_append_log_prefix(nenv.event, "notify command: ");
+
+ /* Parse option */
+ if (!sieve_argument_is_string_literal(arg)) {
+ /* Variable string: partial option parse
+
+ If the string item is not a string literal, it cannot be
+ validated fully at compile time. We can however check whether
+ the '=' is in the string specification and whether the part
+ before the '=' is a valid option name. In that case, the
+ method option check function is called with the value
+ parameter equal to NULL, meaning that it should only check
+ the validity of the option itself and not the assigned value.
+ */
+ if (!ext_enotify_option_parse(NULL, option, TRUE,
+ &opt_name, &opt_value))
+ check = FALSE;
+ } else {
+ /* Literal string: full option parse */
+ if (!ext_enotify_option_parse(&nenv, option, FALSE,
+ &opt_name, &opt_value))
+ result = -1;
+ }
+
+ /* Call method's option check function */
+ if (result > 0 && check && method->def != NULL &&
+ method->def->compile_check_option != NULL) {
+ result = (method->def->compile_check_option(&nenv, opt_name,
+ opt_value) ?
+ 1 : -1 );
+ }
+
+ event_unref(&nenv.event);
+ return result;
+}
+
+bool ext_enotify_compile_check_arguments(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument *uri_arg,
+ struct sieve_ast_argument *msg_arg,
+ struct sieve_ast_argument *from_arg,
+ struct sieve_ast_argument *options_arg)
+{
+ const struct sieve_extension *this_ext = cmd->ext;
+ struct sieve_instance *svinst = this_ext->svinst;
+ const char *uri = sieve_ast_argument_strc(uri_arg);
+ const char *scheme;
+ const struct sieve_enotify_method *method;
+ struct sieve_enotify_env nenv;
+ bool result = TRUE;
+
+ /* If the uri string is not a constant literal, we cannot determine
+ which method is used, so we bail out successfully and defer checking
+ to runtime.
+ */
+ if (!sieve_argument_is_string_literal(uri_arg))
+ return TRUE;
+
+ /* Parse scheme part of URI */
+ if ((scheme = ext_enotify_uri_scheme_parse(&uri)) == NULL) {
+ sieve_argument_validate_error(
+ valdtr, uri_arg, "notify command: "
+ "invalid scheme part for method URI '%s'",
+ str_sanitize(sieve_ast_argument_strc(uri_arg), 80));
+ return FALSE;
+ }
+
+ /* Find used method with the parsed scheme identifier */
+ if ((method = ext_enotify_method_find(this_ext, scheme)) == NULL) {
+ sieve_argument_validate_error(
+ valdtr, uri_arg, "notify command: "
+ "invalid method '%s'", scheme);
+ return FALSE;
+ }
+
+ if (method->def == NULL)
+ return TRUE;
+
+ /* Compose log structure */
+ i_zero(&nenv);
+ nenv.svinst = svinst;
+ nenv.method = method;
+
+ /* Check URI itself */
+ if (result && method->def->compile_check_uri != NULL) {
+ /* Set log location to location of URI argument */
+ nenv.ehandler = sieve_validator_error_handler(valdtr);
+ nenv.location = sieve_error_script_location(
+ sieve_validator_script(valdtr), uri_arg->source_line);
+ nenv.event = event_create(nenv.svinst->event);
+ event_set_append_log_prefix(nenv.event, "notify command: ");
+
+ /* Execute method check function */
+ result = method->def->compile_check_uri(
+ &nenv, sieve_ast_argument_strc(uri_arg), uri);
+ }
+
+ /* Check :message argument */
+ if (result && msg_arg != NULL &&
+ sieve_argument_is_string_literal(msg_arg) &&
+ method->def->compile_check_message != NULL ) {
+ /* Set log location to location of :message argument */
+ event_unref(&nenv.event);
+ nenv.ehandler = sieve_validator_error_handler(valdtr);
+ nenv.location = sieve_error_script_location(
+ sieve_validator_script(valdtr), msg_arg->source_line);
+ nenv.event = event_create(nenv.svinst->event);
+ event_set_append_log_prefix(nenv.event, "notify command: ");
+
+ /* Execute method check function */
+ result = method->def->compile_check_message(
+ &nenv, sieve_ast_argument_str(msg_arg));
+ }
+
+ /* Check :from argument */
+ if (result && from_arg != NULL &&
+ sieve_argument_is_string_literal(from_arg) &&
+ method->def->compile_check_from != NULL ) {
+ /* Set log location to location of :from argument */
+ event_unref(&nenv.event);
+ nenv.ehandler = sieve_validator_error_handler(valdtr);
+ nenv.location = sieve_error_script_location(
+ sieve_validator_script(valdtr), from_arg->source_line);
+ nenv.event = event_create(nenv.svinst->event);
+ event_set_append_log_prefix(nenv.event, "notify command: ");
+
+ /* Execute method check function */
+ result = method->def->compile_check_from(
+ &nenv, sieve_ast_argument_str(from_arg));
+ }
+
+ event_unref(&nenv.event);
+
+ /* Check :options argument */
+ if (result && options_arg != NULL) {
+ struct sieve_ast_argument *option = options_arg;
+ struct _ext_enotify_option_check_context optn_context = {
+ svinst, valdtr, method };
+
+ /* Parse and check options */
+ result = (sieve_ast_stringlist_map(
+ &option, (void *) &optn_context,
+ _ext_enotify_option_check) > 0);
+
+ /* Discard argument if options are not accepted by method */
+ if (result && method->def->compile_check_option == NULL) {
+ sieve_argument_validate_warning(
+ valdtr, options_arg, "notify command: "
+ "method '%s' accepts no options", scheme);
+ (void)sieve_ast_arguments_detach(options_arg, 1);
+ }
+ }
+ return result;
+}
+
+/*
+ * Runtime operand checking
+ */
+
+bool ext_enotify_runtime_method_validate(const struct sieve_runtime_env *renv,
+ string_t *method_uri)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ const struct sieve_enotify_method *method;
+ const char *uri = str_c(method_uri);
+ const char *scheme;
+ bool result = TRUE;
+
+ /* Get the method */
+
+ if ((scheme = ext_enotify_uri_scheme_parse(&uri)) == NULL)
+ return FALSE;
+ if ((method = ext_enotify_method_find(this_ext, scheme)) == NULL)
+ return FALSE;
+
+ /* Validate the provided URI */
+
+ if (method->def != NULL && method->def->runtime_check_uri != NULL) {
+ struct sieve_enotify_env nenv;
+
+ i_zero(&nenv);
+ nenv.svinst = eenv->svinst;
+ nenv.method = method;
+ nenv.ehandler = renv->ehandler;
+ nenv.location = sieve_runtime_get_full_command_location(renv),
+ nenv.event = event_create(nenv.svinst->event);
+ event_set_append_log_prefix(nenv.event,
+ "valid_notify_method test: ");
+
+ /* Use the method check function to validate the URI */
+ result = method->def->runtime_check_uri(
+ &nenv, str_c(method_uri), uri);
+
+ event_unref(&nenv.event);
+ }
+
+ return result;
+}
+
+static const struct
+sieve_enotify_method *ext_enotify_get_method(
+ const struct sieve_runtime_env *renv, string_t *method_uri,
+ const char **uri_body_r)
+{
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ const struct sieve_enotify_method *method;
+ const char *uri = str_c(method_uri);
+ const char *scheme;
+
+ /* Parse part before ':' of the uri (the scheme) and use it to identify
+ notify method.
+ */
+ if ((scheme = ext_enotify_uri_scheme_parse(&uri)) == NULL) {
+ sieve_runtime_error(
+ renv, NULL, "invalid scheme part for method URI '%s'",
+ str_sanitize(str_c(method_uri), 80));
+ return NULL;
+ }
+
+ /* Find the notify method */
+ if ((method = ext_enotify_method_find(this_ext, scheme)) == NULL) {
+ sieve_runtime_error(renv, NULL, "invalid notify method '%s'",
+ scheme);
+ return NULL;
+ }
+
+ /* Return the parse pointer and the found method */
+ *uri_body_r = uri;
+ return method;
+}
+
+const char *
+ext_enotify_runtime_get_method_capability(const struct sieve_runtime_env *renv,
+ string_t *method_uri,
+ const char *capability)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_enotify_method *method;
+ const char *uri_body;
+ const char *result = NULL;
+
+ /* Get method */
+ method = ext_enotify_get_method(renv, method_uri, &uri_body);
+ if ( method == NULL ) return NULL;
+
+ /* Get requested capability */
+ if (method->def != NULL &&
+ method->def->runtime_get_method_capability != NULL) {
+ struct sieve_enotify_env nenv;
+
+ i_zero(&nenv);
+ nenv.svinst = eenv->svinst;
+ nenv.method = method;
+ nenv.ehandler = renv->ehandler;
+ nenv.location = sieve_runtime_get_full_command_location(renv),
+ nenv.event = event_create(nenv.svinst->event);
+ event_set_append_log_prefix(nenv.event,
+ "notify_method_capability test: ");
+
+ /* Execute method function to acquire capability value */
+ result = method->def->runtime_get_method_capability(
+ &nenv, str_c(method_uri), uri_body, capability);
+
+ event_unref(&nenv.event);
+ }
+
+ return result;
+}
+
+int ext_enotify_runtime_check_operands(
+ const struct sieve_runtime_env *renv, string_t *method_uri,
+ string_t *message, string_t *from, struct sieve_stringlist *options,
+ const struct sieve_enotify_method **method_r, void **method_context)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_enotify_method *method;
+ const char *uri_body;
+
+ /* Get method */
+ method = ext_enotify_get_method(renv, method_uri, &uri_body);
+ if (method == NULL)
+ return SIEVE_EXEC_FAILURE;
+
+ /* Check provided operands */
+ if (method->def != NULL &&
+ method->def->runtime_check_operands != NULL) {
+ struct sieve_enotify_env nenv;
+ int result = SIEVE_EXEC_OK;
+
+ i_zero(&nenv);
+ nenv.svinst = eenv->svinst;
+ nenv.method = method;
+ nenv.ehandler = renv->ehandler;
+ nenv.location = sieve_runtime_get_full_command_location(renv),
+ nenv.event = event_create(nenv.svinst->event);
+ event_set_append_log_prefix(nenv.event, "notify_action: ");
+
+ /* Execute check function */
+ if (method->def->runtime_check_operands(
+ &nenv, str_c(method_uri), uri_body, message, from,
+ sieve_result_pool(renv->result), method_context)) {
+
+ /* Check any provided options */
+ if (options != NULL) {
+ string_t *option = NULL;
+ int ret;
+
+ /* Iterate through all provided options */
+ while ((ret = sieve_stringlist_next_item(
+ options, &option)) > 0) {
+ const char *opt_name = NULL;
+ const char *opt_value = NULL;
+
+ /* Parse option into <optionname> and
+ <value> */
+ if (ext_enotify_option_parse(
+ &nenv, str_c(option), FALSE,
+ &opt_name, &opt_value)) {
+
+ /* Set option */
+ if (method->def->runtime_set_option != NULL) {
+ (void)method->def->runtime_set_option(
+ &nenv, *method_context,
+ opt_name, opt_value);
+ }
+ }
+ }
+
+ /* Check for binary corruptions encountered
+ during string list iteration */
+ if (ret >= 0) {
+ *method_r = method;
+ } else {
+ /* Binary corrupt */
+ sieve_runtime_trace_error(
+ renv, "invalid item in options string list");
+ result = SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ } else {
+ /* No options */
+ *method_r = method;
+ }
+
+ } else {
+ /* Operand check failed */
+ result = SIEVE_EXEC_FAILURE;
+ }
+
+ event_unref(&nenv.event);
+ return result;
+ }
+
+ /* No check function defined: a most unlikely situation */
+ *method_context = NULL;
+ *method_r = method;
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Notify method printing
+ */
+
+void sieve_enotify_method_printf(const struct sieve_enotify_print_env *penv,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ sieve_result_vprintf(penv->result_penv, fmt, args);
+ va_end(args);
+}
+
+/*
+ * Action execution
+ */
+
+struct event_passthrough *
+sieve_enotify_create_finish_event(const struct sieve_enotify_exec_env *nenv)
+{
+ struct event_passthrough *e =
+ event_create_passthrough(nenv->event)->
+ set_name("sieve_action_finished");
+
+ return e;
+}
+
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-common.h b/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-common.h
new file mode 100644
index 0000000..ec43202
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-common.h
@@ -0,0 +1,122 @@
+#ifndef EXT_ENOTIFY_COMMON_H
+#define EXT_ENOTIFY_COMMON_H
+
+#include "lib.h"
+#include "array.h"
+
+#include "sieve-common.h"
+
+#include "sieve-ext-variables.h"
+
+#include "sieve-ext-enotify.h"
+
+/*
+ * Extension
+ */
+
+extern const struct sieve_extension_def enotify_extension;
+extern const struct sieve_extension_capabilities notify_capabilities;
+
+struct ext_enotify_context {
+ const struct sieve_extension *var_ext;
+ ARRAY(struct sieve_enotify_method) notify_methods;
+};
+
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def notify_command;
+
+/* Codes for optional arguments */
+
+enum cmd_notify_optional {
+ CMD_NOTIFY_OPT_END,
+ CMD_NOTIFY_OPT_FROM,
+ CMD_NOTIFY_OPT_OPTIONS,
+ CMD_NOTIFY_OPT_MESSAGE,
+ CMD_NOTIFY_OPT_IMPORTANCE
+};
+
+/*
+ * Tests
+ */
+
+extern const struct sieve_command_def valid_notify_method_test;
+extern const struct sieve_command_def notify_method_capability_test;
+
+/*
+ * Operations
+ */
+
+extern const struct sieve_operation_def notify_operation;
+extern const struct sieve_operation_def valid_notify_method_operation;
+extern const struct sieve_operation_def notify_method_capability_operation;
+
+enum ext_variables_opcode {
+ EXT_ENOTIFY_OPERATION_NOTIFY,
+ EXT_ENOTIFY_OPERATION_VALID_NOTIFY_METHOD,
+ EXT_ENOTIFY_OPERATION_NOTIFY_METHOD_CAPABILITY
+};
+
+/*
+ * Operands
+ */
+
+extern const struct sieve_operand_def encodeurl_operand;
+
+/*
+ * Modifiers
+ */
+
+extern const struct sieve_variables_modifier_def encodeurl_modifier;
+
+/*
+ * Notify methods
+ */
+
+void ext_enotify_methods_init(struct sieve_instance *svinst,
+ struct ext_enotify_context *ectx);
+void ext_enotify_methods_deinit(struct ext_enotify_context *ectx);
+
+const struct sieve_enotify_method *
+ext_enotify_method_find(const struct sieve_extension *ntfy_ext,
+ const char *identifier);
+
+/*
+ * Validation
+ */
+
+bool ext_enotify_compile_check_arguments(
+ struct sieve_validator *valdtr, struct sieve_command *cmd,
+ struct sieve_ast_argument *uri_arg, struct sieve_ast_argument *msg_arg,
+ struct sieve_ast_argument *from_arg,
+ struct sieve_ast_argument *options_arg);
+
+/*
+ * Runtime
+ */
+
+bool ext_enotify_runtime_method_validate(const struct sieve_runtime_env *renv,
+ string_t *method_uri);
+
+const char *
+ext_enotify_runtime_get_method_capability(const struct sieve_runtime_env *renv,
+ string_t *method_uri,
+ const char *capability);
+
+int ext_enotify_runtime_check_operands(
+ const struct sieve_runtime_env *renv, string_t *method_uri,
+ string_t *message, string_t *from, struct sieve_stringlist *options,
+ const struct sieve_enotify_method **method_r, void **method_context);
+
+/*
+ * Method printing
+ */
+
+struct sieve_enotify_print_env {
+ const struct sieve_result_print_env *result_penv;
+};
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-limits.h b/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-limits.h
new file mode 100644
index 0000000..aac48df
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-limits.h
@@ -0,0 +1,6 @@
+#ifndef EXT_ENOTIFY_LIMITS_H
+#define EXT_ENOTIFY_LIMITS_H
+
+#define EXT_ENOTIFY_MAX_SCHEME_LEN 32
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify.c b/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify.c
new file mode 100644
index 0000000..df479b3
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify.c
@@ -0,0 +1,103 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension enotify
+ * ------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5435
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "sieve-common.h"
+
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-actions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-result.h"
+
+#include "sieve-ext-variables.h"
+
+#include "ext-enotify-common.h"
+
+/*
+ * Operations
+ */
+
+const struct sieve_operation_def *ext_enotify_operations[] = {
+ &notify_operation,
+ &valid_notify_method_operation,
+ &notify_method_capability_operation
+};
+
+/*
+ * Extension
+ */
+
+static bool ext_enotify_load(const struct sieve_extension *ext, void **context);
+static void ext_enotify_unload(const struct sieve_extension *ext);
+static bool ext_enotify_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def enotify_extension = {
+ .name = "enotify",
+ .load = ext_enotify_load,
+ .unload = ext_enotify_unload,
+ .validator_load = ext_enotify_validator_load,
+ SIEVE_EXT_DEFINE_OPERATIONS(ext_enotify_operations),
+ SIEVE_EXT_DEFINE_OPERAND(encodeurl_operand)
+};
+
+static bool ext_enotify_load(const struct sieve_extension *ext, void **context)
+{
+ struct ext_enotify_context *ectx;
+
+ if ( *context != NULL ) {
+ ext_enotify_unload(ext);
+ }
+
+ ectx = i_new(struct ext_enotify_context, 1);
+ ectx->var_ext = sieve_ext_variables_get_extension(ext->svinst);
+ *context = (void *) ectx;
+
+ ext_enotify_methods_init(ext->svinst, ectx);
+
+ sieve_extension_capabilities_register(ext, &notify_capabilities);
+
+ return TRUE;
+}
+
+static void ext_enotify_unload(const struct sieve_extension *ext)
+{
+ struct ext_enotify_context *ectx =
+ (struct ext_enotify_context *) ext->context;
+
+ ext_enotify_methods_deinit(ectx);
+
+ i_free(ectx);
+}
+
+static bool ext_enotify_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ struct ext_enotify_context *ectx =
+ (struct ext_enotify_context *) ext->context;
+
+ /* Register new commands */
+ sieve_validator_register_command(valdtr, ext, &notify_command);
+ sieve_validator_register_command(valdtr, ext, &valid_notify_method_test);
+ sieve_validator_register_command(valdtr, ext, &notify_method_capability_test);
+
+ /* Register new set modifier for variables extension */
+ sieve_variables_modifier_register
+ (ectx->var_ext, valdtr, ext, &encodeurl_modifier);
+
+ return TRUE;
+}
+
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/mailto/Makefile.am b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/Makefile.am
new file mode 100644
index 0000000..83f129c
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/Makefile.am
@@ -0,0 +1,16 @@
+noinst_LTLIBRARIES = libsieve_ext_enotify_mailto.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/.. \
+ -I$(srcdir)/../../.. \
+ -I$(srcdir)/../../../util \
+ $(LIBDOVECOT_INCLUDE)
+
+libsieve_ext_enotify_mailto_la_SOURCES = \
+ uri-mailto.c \
+ ntfy-mailto.c
+
+noinst_HEADERS = \
+ uri-mailto.h
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/mailto/Makefile.in b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/Makefile.in
new file mode 100644
index 0000000..49aa41a
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/Makefile.in
@@ -0,0 +1,687 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/enotify/mailto
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_enotify_mailto_la_LIBADD =
+am_libsieve_ext_enotify_mailto_la_OBJECTS = uri-mailto.lo \
+ ntfy-mailto.lo
+libsieve_ext_enotify_mailto_la_OBJECTS = \
+ $(am_libsieve_ext_enotify_mailto_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ntfy-mailto.Plo \
+ ./$(DEPDIR)/uri-mailto.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_enotify_mailto_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_enotify_mailto_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_enotify_mailto.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/.. \
+ -I$(srcdir)/../../.. \
+ -I$(srcdir)/../../../util \
+ $(LIBDOVECOT_INCLUDE)
+
+libsieve_ext_enotify_mailto_la_SOURCES = \
+ uri-mailto.c \
+ ntfy-mailto.c
+
+noinst_HEADERS = \
+ uri-mailto.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/enotify/mailto/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/enotify/mailto/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_enotify_mailto.la: $(libsieve_ext_enotify_mailto_la_OBJECTS) $(libsieve_ext_enotify_mailto_la_DEPENDENCIES) $(EXTRA_libsieve_ext_enotify_mailto_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_enotify_mailto_la_OBJECTS) $(libsieve_ext_enotify_mailto_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntfy-mailto.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uri-mailto.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ntfy-mailto.Plo
+ -rm -f ./$(DEPDIR)/uri-mailto.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ntfy-mailto.Plo
+ -rm -f ./$(DEPDIR)/uri-mailto.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
new file mode 100644
index 0000000..4e104d1
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
@@ -0,0 +1,794 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Notify method mailto
+ * --------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5436
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+/* FIXME: URI syntax conforms to something somewhere in between RFC 2368 and
+ * draft-duerst-mailto-bis-05.txt. Should fully migrate to new specification
+ * when it matures. This requires modifications to the address parser (no
+ * whitespace allowed within the address itself) and UTF-8 support will be
+ * required in the URL.
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "ioloop.h"
+#include "str-sanitize.h"
+#include "ostream.h"
+#include "message-date.h"
+#include "mail-storage.h"
+
+#include "sieve-common.h"
+#include "sieve-address.h"
+#include "sieve-address-source.h"
+#include "sieve-message.h"
+#include "sieve-smtp.h"
+#include "sieve-settings.h"
+
+#include "sieve-ext-enotify.h"
+
+#include "rfc2822.h"
+
+#include "uri-mailto.h"
+
+/*
+ * Configuration
+ */
+
+#define NTFY_MAILTO_MAX_RECIPIENTS 8
+#define NTFY_MAILTO_MAX_HEADERS 16
+#define NTFY_MAILTO_MAX_SUBJECT 256
+
+/*
+ * Mailto notification configuration
+ */
+
+struct ntfy_mailto_config {
+ pool_t pool;
+ struct sieve_address_source envelope_from;
+};
+
+/*
+ * Mailto notification method
+ */
+
+static bool ntfy_mailto_load
+ (const struct sieve_enotify_method *nmth, void **context);
+static void ntfy_mailto_unload
+ (const struct sieve_enotify_method *nmth);
+
+static bool ntfy_mailto_compile_check_uri
+ (const struct sieve_enotify_env *nenv, const char *uri, const char *uri_body);
+static bool ntfy_mailto_compile_check_from
+ (const struct sieve_enotify_env *nenv, string_t *from);
+
+static const char *ntfy_mailto_runtime_get_notify_capability
+ (const struct sieve_enotify_env *nenv, const char *uri, const char *uri_body,
+ const char *capability);
+static bool ntfy_mailto_runtime_check_uri
+ (const struct sieve_enotify_env *nenv, const char *uri, const char *uri_body);
+static bool ntfy_mailto_runtime_check_operands
+ (const struct sieve_enotify_env *nenv, const char *uri,const char *uri_body,
+ string_t *message, string_t *from, pool_t context_pool,
+ void **method_context);
+
+static int ntfy_mailto_action_check_duplicates
+ (const struct sieve_enotify_env *nenv,
+ const struct sieve_enotify_action *nact,
+ const struct sieve_enotify_action *nact_other);
+
+static void ntfy_mailto_action_print
+ (const struct sieve_enotify_print_env *penv,
+ const struct sieve_enotify_action *nact);
+
+static int ntfy_mailto_action_execute
+ (const struct sieve_enotify_exec_env *nenv,
+ const struct sieve_enotify_action *nact);
+
+const struct sieve_enotify_method_def mailto_notify = {
+ "mailto",
+ ntfy_mailto_load,
+ ntfy_mailto_unload,
+ ntfy_mailto_compile_check_uri,
+ NULL,
+ ntfy_mailto_compile_check_from,
+ NULL,
+ ntfy_mailto_runtime_check_uri,
+ ntfy_mailto_runtime_get_notify_capability,
+ ntfy_mailto_runtime_check_operands,
+ NULL,
+ ntfy_mailto_action_check_duplicates,
+ ntfy_mailto_action_print,
+ ntfy_mailto_action_execute
+};
+
+/*
+ * Reserved and unique headers
+ */
+
+static const char *_reserved_headers[] = {
+ "auto-submitted",
+ "received",
+ "message-id",
+ "data",
+ "bcc",
+ "in-reply-to",
+ "references",
+ "resent-date",
+ "resent-from",
+ "resent-sender",
+ "resent-to",
+ "resent-cc",
+ "resent-bcc",
+ "resent-msg-id",
+ "from",
+ "sender",
+ NULL
+};
+
+static const char *_unique_headers[] = {
+ "reply-to",
+ NULL
+};
+
+/*
+ * Method context data
+ */
+
+struct ntfy_mailto_context {
+ struct uri_mailto *uri;
+ const struct smtp_address *from_address;
+};
+
+/*
+ * Method registration
+ */
+
+static bool ntfy_mailto_load
+(const struct sieve_enotify_method *nmth, void **context)
+{
+ struct sieve_instance *svinst = nmth->svinst;
+ struct ntfy_mailto_config *config;
+ pool_t pool;
+
+ if ( *context != NULL ) {
+ ntfy_mailto_unload(nmth);
+ }
+
+ pool = pool_alloconly_create("ntfy_mailto_config", 256);
+ config = p_new(pool, struct ntfy_mailto_config, 1);
+ config->pool = pool;
+
+ (void)sieve_address_source_parse_from_setting (svinst,
+ config->pool, "sieve_notify_mailto_envelope_from",
+ &config->envelope_from);
+
+ *context = (void *) config;
+
+ return TRUE;
+}
+
+static void ntfy_mailto_unload
+(const struct sieve_enotify_method *nmth)
+{
+ struct ntfy_mailto_config *config =
+ (struct ntfy_mailto_config *) nmth->context;
+
+ pool_unref(&config->pool);
+}
+
+/*
+ * URI parsing
+ */
+
+struct ntfy_mailto_uri_env {
+ const struct sieve_enotify_env *nenv;
+
+ struct event *event;
+
+ struct uri_mailto_log uri_log;
+};
+
+static void ATTR_FORMAT(5, 0)
+ntfy_mailto_uri_logv(void *context, enum log_type log_type,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *fmt, va_list args)
+{
+ struct ntfy_mailto_uri_env *nmuenv = context;
+ const struct sieve_enotify_env *nenv = nmuenv->nenv;
+
+ sieve_event_logv(nenv->svinst, nenv->ehandler, nmuenv->event,
+ log_type, csrc_filename, csrc_linenum,
+ nenv->location, 0, fmt, args);
+}
+
+static void
+ntfy_mailto_uri_env_init(struct ntfy_mailto_uri_env *nmuenv,
+ const struct sieve_enotify_env *nenv)
+{
+ i_zero(nmuenv);
+ nmuenv->nenv = nenv;
+ nmuenv->event = event_create(nenv->event);
+ event_set_append_log_prefix(nmuenv->event, "mailto URI: ");
+
+ nmuenv->uri_log.context = nmuenv;
+ nmuenv->uri_log.logv = ntfy_mailto_uri_logv;
+}
+
+static void
+ntfy_mailto_uri_env_deinit(struct ntfy_mailto_uri_env *nmuenv)
+{
+ event_unref(&nmuenv->event);
+}
+
+/*
+ * Validation
+ */
+
+
+static bool ntfy_mailto_compile_check_uri
+(const struct sieve_enotify_env *nenv, const char *uri ATTR_UNUSED,
+ const char *uri_body)
+{
+ struct ntfy_mailto_uri_env nmuenv;
+ bool result;
+
+ ntfy_mailto_uri_env_init(&nmuenv, nenv);
+ result = uri_mailto_validate(
+ uri_body, _reserved_headers, _unique_headers,
+ NTFY_MAILTO_MAX_RECIPIENTS, NTFY_MAILTO_MAX_HEADERS,
+ &nmuenv.uri_log);
+ ntfy_mailto_uri_env_deinit(&nmuenv);
+
+ return result;
+}
+
+static bool ntfy_mailto_compile_check_from
+(const struct sieve_enotify_env *nenv, string_t *from)
+{
+ const char *error;
+ bool result = FALSE;
+
+ T_BEGIN {
+ result = sieve_address_validate_str(from, &error);
+ if ( !result ) {
+ sieve_enotify_error(nenv,
+ "specified :from address '%s' is invalid for "
+ "the mailto method: %s",
+ str_sanitize(str_c(from), 128), error);
+ }
+ } T_END;
+
+ return result;
+}
+
+/*
+ * Runtime
+ */
+
+struct ntfy_mailto_runtime_env {
+ const struct sieve_enotify_env *nenv;
+
+ struct event *event;
+};
+
+static const char *ntfy_mailto_runtime_get_notify_capability
+(const struct sieve_enotify_env *nenv ATTR_UNUSED, const char *uri ATTR_UNUSED,
+ const char *uri_body, const char *capability)
+{
+ if ( !uri_mailto_validate(uri_body, _reserved_headers, _unique_headers,
+ NTFY_MAILTO_MAX_RECIPIENTS, NTFY_MAILTO_MAX_HEADERS, NULL) ) {
+ return NULL;
+ }
+
+ if ( strcasecmp(capability, "online") == 0 )
+ return "maybe";
+
+ return NULL;
+}
+
+static bool ntfy_mailto_runtime_check_uri
+(const struct sieve_enotify_env *nenv ATTR_UNUSED, const char *uri ATTR_UNUSED,
+ const char *uri_body)
+{
+ return uri_mailto_validate
+ (uri_body, _reserved_headers, _unique_headers,
+ NTFY_MAILTO_MAX_RECIPIENTS, NTFY_MAILTO_MAX_HEADERS, NULL);
+}
+
+static bool ntfy_mailto_runtime_check_operands
+(const struct sieve_enotify_env *nenv, const char *uri ATTR_UNUSED,
+ const char *uri_body, string_t *message ATTR_UNUSED, string_t *from,
+ pool_t context_pool, void **method_context)
+{
+ struct ntfy_mailto_context *mtctx;
+ struct uri_mailto *parsed_uri;
+ const struct smtp_address *address;
+ struct ntfy_mailto_uri_env nmuenv;
+ const char *error;
+
+ /* Need to create context before validation to have arrays present */
+ mtctx = p_new(context_pool, struct ntfy_mailto_context, 1);
+
+ /* Validate :from */
+ if ( from != NULL ) {
+ T_BEGIN {
+ address = sieve_address_parse_str(from, &error);
+ if ( address == NULL ) {
+ sieve_enotify_error(nenv,
+ "specified :from address '%s' is invalid for "
+ "the mailto method: %s",
+ str_sanitize(str_c(from), 128), error);
+ } else
+ mtctx->from_address =
+ smtp_address_clone(context_pool, address);
+ } T_END;
+
+ if ( address == NULL ) return FALSE;
+ }
+
+ ntfy_mailto_uri_env_init(&nmuenv, nenv);
+ parsed_uri = uri_mailto_parse(uri_body, context_pool,
+ _reserved_headers, _unique_headers,
+ NTFY_MAILTO_MAX_RECIPIENTS,
+ NTFY_MAILTO_MAX_HEADERS,
+ &nmuenv.uri_log);
+ ntfy_mailto_uri_env_deinit(&nmuenv);
+
+ if (parsed_uri == NULL)
+ return FALSE;
+
+ mtctx->uri = parsed_uri;
+ *method_context = (void *) mtctx;
+ return TRUE;
+}
+
+/*
+ * Action duplicates
+ */
+
+static int ntfy_mailto_action_check_duplicates
+(const struct sieve_enotify_env *nenv ATTR_UNUSED,
+ const struct sieve_enotify_action *nact,
+ const struct sieve_enotify_action *nact_other)
+{
+ struct ntfy_mailto_context *mtctx =
+ (struct ntfy_mailto_context *) nact->method_context;
+ struct ntfy_mailto_context *mtctx_other =
+ (struct ntfy_mailto_context *) nact_other->method_context;
+ const struct uri_mailto_recipient *new_rcpts, *old_rcpts;
+ unsigned int new_count, old_count, i, j;
+ unsigned int del_start = 0, del_len = 0;
+
+ new_rcpts = array_get(&mtctx->uri->recipients, &new_count);
+ old_rcpts = array_get(&mtctx_other->uri->recipients, &old_count);
+
+ for ( i = 0; i < new_count; i++ ) {
+ for ( j = 0; j < old_count; j++ ) {
+ if ( smtp_address_equals
+ (new_rcpts[i].address, old_rcpts[j].address) )
+ break;
+ }
+
+ if ( j == old_count ) {
+ /* Not duplicate */
+ if ( del_len > 0 ) {
+ /* Perform pending deletion */
+ array_delete(&mtctx->uri->recipients, del_start, del_len);
+
+ /* Make sure the loop integrity is maintained */
+ i -= del_len;
+ new_rcpts = array_get(&mtctx->uri->recipients, &new_count);
+ }
+ del_len = 0;
+ } else {
+ /* Mark deletion */
+ if ( del_len == 0 )
+ del_start = i;
+ del_len++;
+ }
+ }
+
+ /* Perform pending deletion */
+ if ( del_len > 0 ) {
+ array_delete(&mtctx->uri->recipients, del_start, del_len);
+ }
+
+ return ( array_count(&mtctx->uri->recipients) > 0 ? 0 : 1 );
+}
+
+/*
+ * Action printing
+ */
+
+static void ntfy_mailto_action_print
+(const struct sieve_enotify_print_env *penv,
+ const struct sieve_enotify_action *nact)
+{
+ unsigned int count, i;
+ const struct uri_mailto_recipient *recipients;
+ const struct uri_mailto_header_field *headers;
+ struct ntfy_mailto_context *mtctx =
+ (struct ntfy_mailto_context *) nact->method_context;
+
+ /* Print main method parameters */
+
+ sieve_enotify_method_printf
+ (penv, " => importance : %llu\n",
+ (unsigned long long)nact->importance);
+
+ if ( nact->message != NULL )
+ sieve_enotify_method_printf
+ (penv, " => subject : %s\n", nact->message);
+ else if ( mtctx->uri->subject != NULL )
+ sieve_enotify_method_printf
+ (penv, " => subject : %s\n", mtctx->uri->subject);
+
+ if ( nact->from != NULL )
+ sieve_enotify_method_printf
+ (penv, " => from : %s\n", nact->from);
+
+ /* Print mailto: recipients */
+
+ sieve_enotify_method_printf(penv, " => recipients :\n" );
+
+ recipients = array_get(&mtctx->uri->recipients, &count);
+ if ( count == 0 ) {
+ sieve_enotify_method_printf(penv, " NONE, action has no effect\n");
+ } else {
+ for ( i = 0; i < count; i++ ) {
+ if ( recipients[i].carbon_copy )
+ sieve_enotify_method_printf
+ (penv, " + Cc: %s\n", recipients[i].full);
+ else
+ sieve_enotify_method_printf
+ (penv, " + To: %s\n", recipients[i].full);
+ }
+ }
+
+ /* Print accepted headers for notification message */
+
+ headers = array_get(&mtctx->uri->headers, &count);
+ if ( count > 0 ) {
+ sieve_enotify_method_printf(penv, " => headers :\n" );
+ for ( i = 0; i < count; i++ ) {
+ sieve_enotify_method_printf(penv, " + %s: %s\n",
+ headers[i].name, headers[i].body);
+ }
+ }
+
+ /* Print body for notification message */
+
+ if ( mtctx->uri->body != NULL )
+ sieve_enotify_method_printf
+ (penv, " => body : \n--\n%s\n--\n", mtctx->uri->body);
+
+ /* Finish output with an empty line */
+
+ sieve_enotify_method_printf(penv, "\n");
+}
+
+/*
+ * Action execution
+ */
+
+static bool _contains_8bit(const char *msg)
+{
+ const unsigned char *s = (const unsigned char *)msg;
+
+ for (; *s != '\0'; s++) {
+ if ((*s & 0x80) != 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int ntfy_mailto_send
+(const struct sieve_enotify_exec_env *nenv,
+ const struct sieve_enotify_action *nact,
+ const struct smtp_address *owner_email)
+{
+ struct sieve_instance *svinst = nenv->svinst;
+ const struct sieve_message_data *msgdata = nenv->msgdata;
+ const struct sieve_script_env *senv = nenv->scriptenv;
+ struct ntfy_mailto_context *mtctx =
+ (struct ntfy_mailto_context *) nact->method_context;
+ struct ntfy_mailto_config *mth_config =
+ (struct ntfy_mailto_config *)nenv->method->context;
+ struct sieve_address_source env_from =
+ mth_config->envelope_from;
+ const char *from = NULL;
+ const struct smtp_address *from_smtp = NULL;
+ const char *subject = mtctx->uri->subject;
+ const char *body = mtctx->uri->body;
+ string_t *to, *cc, *all;
+ const struct uri_mailto_recipient *recipients;
+ const struct uri_mailto_header_field *headers;
+ struct sieve_smtp_context *sctx;
+ struct ostream *output;
+ string_t *msg;
+ unsigned int count, i, hcount, h;
+ const char *outmsgid, *error;
+ int ret;
+
+ /* Get recipients */
+ recipients = array_get(&mtctx->uri->recipients, &count);
+ if ( count == 0 ) {
+ sieve_enotify_warning(nenv,
+ "notify mailto uri specifies no recipients; action has no effect");
+ return 0;
+ }
+
+ /* Just to be sure */
+ if ( !sieve_smtp_available(senv) ) {
+ sieve_enotify_global_warning(nenv,
+ "notify mailto method has no means to send mail");
+ return 0;
+ }
+
+ /* Determine which sender to use
+
+ From RFC 5436, Section 2.3:
+
+ The ":from" tag overrides the default sender of the notification
+ message. "Sender", here, refers to the value used in the [RFC5322]
+ "From" header. Implementations MAY also use this value in the
+ [RFC5321] "MAIL FROM" command (the "envelope sender"), or they may
+ prefer to establish a mailbox that receives bounces from notification
+ messages.
+ */
+ if ( (nenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0 ) {
+ from_smtp = sieve_message_get_sender(nenv->msgctx);
+ if ( from_smtp == NULL ) {
+ /* "<>" */
+ i_zero(&env_from);
+ env_from.type = SIEVE_ADDRESS_SOURCE_EXPLICIT;
+ }
+ }
+ from = nact->from;
+ if ( (ret=sieve_address_source_get_address(&env_from, svinst,
+ senv, nenv->msgctx, nenv->flags, &from_smtp)) < 0 ) {
+ from_smtp = NULL;
+ } else if ( ret == 0 ) {
+ if ( mtctx->from_address != NULL )
+ from_smtp = mtctx->from_address;
+ else if ( svinst->user_email != NULL )
+ from_smtp = svinst->user_email;
+ else {
+ from_smtp = sieve_get_postmaster_smtp(senv);
+ if (from == NULL)
+ from = sieve_get_postmaster_address(senv);
+ }
+ }
+
+ /* Determine message from address */
+ if ( from == NULL ) {
+ if ( from_smtp == NULL )
+ from = sieve_get_postmaster_address(senv);
+ else {
+ from = t_strdup_printf("<%s>",
+ smtp_address_encode(from_smtp));
+ }
+ }
+
+ /* Determine subject */
+ if ( nact->message != NULL ) {
+ /* FIXME: handle UTF-8 */
+ subject = str_sanitize(nact->message, NTFY_MAILTO_MAX_SUBJECT);
+ } else if ( subject == NULL ) {
+ const char *const *hsubject;
+
+ /* Fetch subject from original message */
+ if ( mail_get_headers_utf8
+ (msgdata->mail, "subject", &hsubject) > 0 )
+ subject = str_sanitize(t_strdup_printf("Notification: %s", hsubject[0]),
+ NTFY_MAILTO_MAX_SUBJECT);
+ else
+ subject = "Notification: (no subject)";
+ }
+
+ /* Compose To and Cc headers */
+ to = NULL;
+ cc = NULL;
+ all = t_str_new(256);
+ for ( i = 0; i < count; i++ ) {
+ if ( recipients[i].carbon_copy ) {
+ if ( cc == NULL ) {
+ cc = t_str_new(256);
+ str_append(cc, recipients[i].full);
+ } else {
+ str_append(cc, ", ");
+ str_append(cc, recipients[i].full);
+ }
+ } else {
+ if ( to == NULL ) {
+ to = t_str_new(256);
+ str_append(to, recipients[i].full);
+ } else {
+ str_append(to, ", ");
+ str_append(to, recipients[i].full);
+ }
+ }
+ if ( i < 3) {
+ if ( i > 0 )
+ str_append(all, ", ");
+ str_append(all,
+ smtp_address_encode_path(recipients[i].address));
+ } else if (i == 3) {
+ str_printfa(all, ", ... (%u total)", count);
+ }
+ }
+
+ msg = t_str_new(512);
+ outmsgid = sieve_message_get_new_id(svinst);
+
+ rfc2822_header_write(msg, "X-Sieve", SIEVE_IMPLEMENTATION);
+ rfc2822_header_write(msg, "Message-ID", outmsgid);
+ rfc2822_header_write(msg, "Date", message_date_create(ioloop_time));
+ rfc2822_header_utf8_printf(msg, "Subject", "%s", subject);
+
+ rfc2822_header_write_address(msg, "From", from);
+
+ if ( to != NULL )
+ rfc2822_header_write_address(msg, "To", str_c(to));
+ if ( cc != NULL )
+ rfc2822_header_write_address(msg, "Cc", str_c(cc));
+
+ rfc2822_header_printf(msg, "Auto-Submitted",
+ "auto-notified; owner-email=\"%s\"",
+ smtp_address_encode(owner_email));
+ rfc2822_header_write(msg, "Precedence", "bulk");
+
+ /* Set importance */
+ switch ( nact->importance ) {
+ case 1:
+ rfc2822_header_write(msg, "X-Priority", "1 (Highest)");
+ rfc2822_header_write(msg, "Importance", "High");
+ break;
+ case 3:
+ rfc2822_header_write(msg, "X-Priority", "5 (Lowest)");
+ rfc2822_header_write(msg, "Importance", "Low");
+ break;
+ case 2:
+ default:
+ rfc2822_header_write(msg, "X-Priority", "3 (Normal)");
+ rfc2822_header_write(msg, "Importance", "Normal");
+ break;
+ }
+
+ /* Add custom headers */
+
+ headers = array_get(&mtctx->uri->headers, &hcount);
+ for ( h = 0; h < hcount; h++ ) {
+ const char *name = rfc2822_header_field_name_sanitize(headers[h].name);
+
+ rfc2822_header_write(msg, name, headers[h].body);
+ }
+
+ /* Generate message body */
+
+ rfc2822_header_write(msg, "MIME-Version", "1.0");
+ if ( body != NULL ) {
+ if (_contains_8bit(body)) {
+ rfc2822_header_write
+ (msg, "Content-Type", "text/plain; charset=utf-8");
+ rfc2822_header_write(msg, "Content-Transfer-Encoding", "8bit");
+ } else {
+ rfc2822_header_write
+ (msg, "Content-Type", "text/plain; charset=us-ascii");
+ rfc2822_header_write(msg, "Content-Transfer-Encoding", "7bit");
+ }
+ str_printfa(msg, "\r\n%s\r\n", body);
+
+ } else {
+ rfc2822_header_write
+ (msg, "Content-Type", "text/plain; charset=US-ASCII");
+ rfc2822_header_write(msg, "Content-Transfer-Encoding", "7bit");
+
+ str_append(msg, "\r\nNotification of new message.\r\n");
+ }
+
+ sctx = sieve_smtp_start(senv, from_smtp);
+
+ /* Send message to all recipients */
+ for ( i = 0; i < count; i++ )
+ sieve_smtp_add_rcpt(sctx, recipients[i].address);
+
+ output = sieve_smtp_send(sctx);
+ o_stream_nsend(output, str_data(msg), str_len(msg));
+
+ if ( (ret=sieve_smtp_finish(sctx, &error)) <= 0 ) {
+ if (ret < 0) {
+ sieve_enotify_global_error(nenv,
+ "failed to send mail notification to %s: %s (temporary failure)",
+ str_c(all), str_sanitize(error, 512));
+ } else {
+ sieve_enotify_global_log_error(nenv,
+ "failed to send mail notification to %s: %s (permanent failure)",
+ str_c(all), str_sanitize(error, 512));
+ }
+ } else {
+ struct event_passthrough *e =
+ sieve_enotify_create_finish_event(nenv)->
+ add_str("notify_target", str_c(all));
+
+ sieve_enotify_event_log(nenv, e->event(),
+ "sent mail notification to %s",
+ str_c(all));
+ }
+
+ return 0;
+}
+
+static int ntfy_mailto_action_execute
+(const struct sieve_enotify_exec_env *nenv,
+ const struct sieve_enotify_action *nact)
+{
+ struct sieve_instance *svinst = nenv->svinst;
+ const struct sieve_script_env *senv = nenv->scriptenv;
+ struct mail *mail = nenv->msgdata->mail;
+ const struct smtp_address *owner_email;
+ const char *const *hdsp;
+ int ret;
+
+ owner_email = svinst->user_email;
+ if ( owner_email == NULL &&
+ (nenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0 )
+ owner_email = sieve_message_get_final_recipient(nenv->msgctx);
+ if ( owner_email == NULL ) {
+ owner_email = sieve_get_postmaster_smtp(senv);
+ }
+ i_assert( owner_email != NULL );
+
+ /* Is the message an automatic reply ? */
+ if ( (ret=mail_get_headers(mail, "auto-submitted", &hdsp)) < 0 ) {
+ sieve_enotify_critical(nenv,
+ "mailto notification: "
+ "failed to read `auto-submitted' header field",
+ "mailto notification: "
+ "failed to read `auto-submitted' header field: %s",
+ mailbox_get_last_internal_error(mail->box, NULL));
+ return -1;
+ }
+
+ /* Theoretically multiple headers could exist, so lets make sure */
+ if ( ret > 0 ) {
+ while ( *hdsp != NULL ) {
+ if ( strcasecmp(*hdsp, "no") != 0 ) {
+ const struct smtp_address *sender = NULL;
+ const char *from;
+
+ if ( (nenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0 )
+ sender = sieve_message_get_sender(nenv->msgctx);
+ from = (sender == NULL ? "" : t_strdup_printf
+ (" from <%s>", smtp_address_encode(sender)));
+
+ sieve_enotify_global_info(nenv,
+ "not sending notification "
+ "for auto-submitted message%s", from);
+ return 0;
+ }
+ hdsp++;
+ }
+ }
+
+ T_BEGIN {
+ ret = ntfy_mailto_send(nenv, nact, owner_email);
+ } T_END;
+
+ return ret;
+}
+
+
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/mailto/uri-mailto.c b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
new file mode 100644
index 0000000..c5a0953
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/uri-mailto.c
@@ -0,0 +1,683 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* FIXME: URI syntax conforms to something somewhere in between RFC 2368 and
+ draft-duerst-mailto-bis-05.txt. Should fully migrate to new
+ specification when it matures. This requires modifications to the
+ address parser (no whitespace allowed within the address itself) and
+ UTF-8 support will be required in the URL.
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "str-sanitize.h"
+
+#include "rfc2822.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-address.h"
+#include "sieve-message.h"
+
+#include "uri-mailto.h"
+
+/* Parser object */
+
+struct uri_mailto_parser {
+ pool_t pool;
+ const struct uri_mailto_log *log;
+
+ struct uri_mailto *uri;
+
+ const char **reserved_headers;
+ const char **unique_headers;
+
+ int max_recipients;
+ int max_headers;
+};
+
+/* Error handling */
+
+#define uri_mailto_error(PARSER, ...) \
+ uri_mailto_log((PARSER), LOG_TYPE_ERROR, \
+ __FILE__, __LINE__, __VA_ARGS__)
+#define uri_mailto_warning(PARSER, ...) \
+ uri_mailto_log((PARSER), LOG_TYPE_WARNING, \
+ __FILE__, __LINE__, __VA_ARGS__)
+
+static inline void ATTR_FORMAT(5, 6)
+uri_mailto_log(struct uri_mailto_parser *parser, enum log_type log_type,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ if (parser->log == NULL || parser->log->logv == NULL)
+ return;
+
+ va_start(args, fmt);
+ parser->log->logv(parser->log->context, log_type,
+ csrc_filename, csrc_linenum, fmt, args);
+ va_end(args);
+}
+
+
+/*
+ * Error handling
+ */
+
+/*
+ * Reserved and unique headers
+ */
+
+static inline bool
+uri_mailto_header_is_reserved(struct uri_mailto_parser *parser,
+ const char *field_name)
+{
+ const char **hdr = parser->reserved_headers;
+
+ if (hdr == NULL)
+ return FALSE;
+
+ /* Check whether it is reserved */
+ while (*hdr != NULL) {
+ if (strcasecmp(field_name, *hdr) == 0)
+ return TRUE;
+ hdr++;
+ }
+ return FALSE;
+}
+
+static inline bool
+uri_mailto_header_is_unique(struct uri_mailto_parser *parser,
+ const char *field_name)
+{
+ const char **hdr = parser->unique_headers;
+
+ if (hdr == NULL)
+ return FALSE;
+
+ /* Check whether it is supposed to be unique */
+ while (*hdr != NULL) {
+ if (strcasecmp(field_name, *hdr) == 0)
+ return TRUE;
+ hdr++;
+ }
+ return FALSE;
+}
+
+/*
+ * Low-level URI parsing.
+ *
+ * FIXME: much of this implementation will be common to other URI schemes. This
+ * should be merged into a common implementation.
+ */
+
+static const char _qchar_lookup[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10
+ 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 20
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 30
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 50
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, // 70
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 90
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F0
+};
+
+static inline bool _is_qchar(char c)
+{
+ return ((_qchar_lookup[(unsigned char)c] & 0x01) != 0);
+}
+
+static inline int _decode_hex_digit(unsigned char digit)
+{
+ switch (digit) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ return (int) digit - '0';
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ return (int) digit - 'a' + 0x0a;
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ return (int) digit - 'A' + 0x0A;
+ }
+ return -1;
+}
+
+static bool _parse_hex_value(const char **in, char *out)
+{
+ int value, digit;
+
+ if ((digit = _decode_hex_digit((unsigned char)**in)) < 0)
+ return FALSE;
+
+ value = digit << 4;
+ (*in)++;
+
+ if ((digit = _decode_hex_digit((unsigned char)**in)) < 0)
+ return FALSE;
+
+ value |= digit;
+ (*in)++;
+
+ if (value == 0)
+ return FALSE;
+
+ *out = (char)value;
+ return TRUE;
+}
+
+/*
+ * URI recipient parsing
+ */
+
+static bool
+uri_mailto_add_valid_recipient(struct uri_mailto_parser *parser,
+ string_t *recipient, bool cc)
+{
+ struct uri_mailto *uri = parser->uri;
+ struct uri_mailto_recipient *new_recipient;
+ struct uri_mailto_recipient *rcpts;
+ unsigned int count, i;
+ const char *error;
+ const struct smtp_address *address;
+
+ /* Verify recipient */
+ if ((address = sieve_address_parse_str(recipient, &error)) == NULL) {
+ uri_mailto_error(parser, "invalid recipient '%s': %s",
+ str_sanitize(str_c(recipient), 80), error);
+ return FALSE;
+ }
+
+ /* Add recipient to the uri */
+ if (uri != NULL) {
+ /* Get current recipients */
+ rcpts = array_get_modifiable(&uri->recipients, &count);
+
+ /* Enforce limits */
+ if (parser->max_recipients > 0 &&
+ (int)count >= parser->max_recipients) {
+ if ((int)count == parser->max_recipients) {
+ uri_mailto_warning(
+ parser,
+ "more than the maximum %u recipients specified; "
+ "rest is discarded",
+ parser->max_recipients);
+ }
+ return TRUE;
+ }
+
+ /* Check for duplicate first */
+ for (i = 0; i < count; i++) {
+ if (smtp_address_equals(rcpts[i].address, address)) {
+ /* Upgrade existing Cc: recipient to a To:
+ recipient if possible */
+ rcpts[i].carbon_copy =
+ (rcpts[i].carbon_copy && cc);
+
+ uri_mailto_warning(
+ parser,
+ "ignored duplicate recipient '%s'",
+ str_sanitize(str_c(recipient), 80));
+ return TRUE;
+ }
+ }
+
+ /* Add */
+ new_recipient = array_append_space(&uri->recipients);
+ new_recipient->carbon_copy = cc;
+ new_recipient->full = p_strdup(parser->pool, str_c(recipient));
+ new_recipient->address =
+ smtp_address_clone(parser->pool, address);
+ }
+
+ return TRUE;
+}
+
+static bool
+uri_mailto_parse_recipients(struct uri_mailto_parser *parser,
+ const char **uri_p)
+{
+ string_t *to = t_str_new(128);
+ const char *p = *uri_p;
+
+ if (*p == '\0' || *p == '?')
+ return TRUE;
+
+ while (*p != '\0' && *p != '?') {
+ if (*p == '%') {
+ /* % encoded character */
+ char ch;
+
+ p++;
+
+ /* Parse 2-digit hex value */
+ if (!_parse_hex_value(&p, &ch)) {
+ uri_mailto_error(parser, "invalid %% encoding");
+ return FALSE;
+ }
+
+ /* Check for delimiter */
+ if (ch == ',') {
+ /* Verify and add recipient */
+ if (!uri_mailto_add_valid_recipient(
+ parser, to, FALSE))
+ return FALSE;
+
+ /* Reset for next recipient */
+ str_truncate(to, 0);
+ } else {
+ /* Content character */
+ str_append_c(to, ch);
+ }
+ } else {
+ if (*p == ':' || *p == ';' || *p == ',' ||
+ !_is_qchar(*p)) {
+ uri_mailto_error(
+ parser,
+ "invalid character '%c' in 'to' part", *p);
+ return FALSE;
+ }
+
+ /* Content character */
+ str_append_c(to, *p);
+ p++;
+ }
+ }
+
+ i_assert(*p == '\0' || *p == '?');
+
+ /* Verify and add recipient */
+ if (!uri_mailto_add_valid_recipient(parser, to, FALSE))
+ return FALSE;
+
+ *uri_p = p;
+ return TRUE;
+}
+
+static bool
+uri_mailto_parse_header_recipients(struct uri_mailto_parser *parser,
+ string_t *rcpt_header, bool cc)
+{
+ string_t *to = t_str_new(128);
+ const char *p = (const char *)str_data(rcpt_header);
+ const char *pend = p + str_len(rcpt_header);
+
+ while (p < pend) {
+ if (*p == ',') {
+ /* Verify and add recipient */
+ if (!uri_mailto_add_valid_recipient(parser, to, cc))
+ return FALSE;
+
+ /* Reset for next recipient */
+ str_truncate(to, 0);
+ } else {
+ /* Content character */
+ str_append_c(to, *p);
+ }
+ p++;
+ }
+
+ /* Verify and add recipient */
+ if (!uri_mailto_add_valid_recipient(parser, to, cc))
+ return FALSE;
+
+ return TRUE;
+}
+
+/* URI header parsing */
+
+static bool
+uri_mailto_header_is_duplicate(struct uri_mailto_parser *parser,
+ const char *field_name)
+{
+ struct uri_mailto *uri = parser->uri;
+
+ if (uri == NULL)
+ return FALSE;
+
+ if (uri_mailto_header_is_unique(parser, field_name)) {
+ const struct uri_mailto_header_field *hdrs;
+ unsigned int count, i;
+
+ hdrs = array_get(&uri->headers, &count);
+ for (i = 0; i < count; i++) {
+ if (strcasecmp(hdrs[i].name, field_name) == 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static bool
+uri_mailto_parse_headers(struct uri_mailto_parser *parser, const char **uri_p)
+{
+ struct uri_mailto *uri = parser->uri;
+ unsigned int header_count = 0;
+ string_t *field = t_str_new(128);
+ const char *p = *uri_p;
+
+ while (*p != '\0') {
+ enum {
+ _HNAME_IGNORED,
+ _HNAME_GENERIC,
+ _HNAME_TO,
+ _HNAME_CC,
+ _HNAME_SUBJECT,
+ _HNAME_BODY,
+ } hname_type = _HNAME_GENERIC;
+ struct uri_mailto_header_field *hdrf = NULL;
+ const char *field_name;
+
+ /* Parse field name */
+ while (*p != '\0' && *p != '=') {
+ char ch = *p;
+ p++;
+
+ if (ch == '%') {
+ /* Encoded, parse 2-digit hex value */
+ if (!_parse_hex_value(&p, &ch)) {
+ uri_mailto_error(parser,
+ "invalid %% encoding");
+ return FALSE;
+ }
+ } else if (ch != '=' && !_is_qchar(ch)) {
+ uri_mailto_error(
+ parser,
+ "invalid character '%c' in header field name part",
+ ch);
+ return FALSE;
+ }
+
+ str_append_c(field, ch);
+ }
+ if (*p != '\0')
+ p++;
+
+ /* Verify field name */
+ if (!rfc2822_header_field_name_verify(str_c(field),
+ str_len(field))) {
+ uri_mailto_error(parser, "invalid header field name");
+ return FALSE;
+ }
+
+ if (parser->max_headers > -1 &&
+ (int)header_count >= parser->max_headers) {
+ /* Refuse to accept more headers than allowed by policy
+ */
+ if ((int)header_count == parser->max_headers) {
+ uri_mailto_warning(
+ parser,
+ "more than the maximum %u headers specified; "
+ "rest is discarded",
+ parser->max_headers);
+ }
+
+ hname_type = _HNAME_IGNORED;
+ } else {
+ /* Add new header field to array and assign its name */
+
+ field_name = str_c(field);
+ if (strcasecmp(field_name, "to") == 0)
+ hname_type = _HNAME_TO;
+ else if (strcasecmp(field_name, "cc") == 0)
+ hname_type = _HNAME_CC;
+ else if (strcasecmp(field_name, "subject") == 0)
+ hname_type = _HNAME_SUBJECT;
+ else if (strcasecmp(field_name, "body") == 0)
+ hname_type = _HNAME_BODY;
+ else if (!uri_mailto_header_is_reserved(parser, field_name)) {
+ if (uri != NULL) {
+ if (!uri_mailto_header_is_duplicate(parser, field_name)) {
+ hdrf = array_append_space(&uri->headers);
+ hdrf->name = p_strdup(parser->pool, field_name);
+ } else {
+ uri_mailto_warning(
+ parser,
+ "ignored duplicate for unique header field '%s'",
+ str_sanitize(field_name, 32));
+ hname_type = _HNAME_IGNORED;
+ }
+ } else {
+ hname_type = _HNAME_IGNORED;
+ }
+ } else {
+ uri_mailto_warning(
+ parser,
+ "ignored reserved header field '%s'",
+ str_sanitize(field_name, 32));
+ hname_type = _HNAME_IGNORED;
+ }
+ }
+
+ header_count++;
+
+ /* Reset for field body */
+ str_truncate(field, 0);
+
+ /* Parse field body */
+ while (*p != '\0' && *p != '&') {
+ char ch = *p;
+ p++;
+
+ if (ch == '%') {
+ /* Encoded, parse 2-digit hex value */
+ if (!_parse_hex_value(&p, &ch)) {
+ uri_mailto_error(parser,
+ "invalid %% encoding");
+ return FALSE;
+ }
+ } else if (ch != '=' && !_is_qchar(ch)) {
+ uri_mailto_error(
+ parser,
+ "invalid character '%c' in header field value part",
+ ch);
+ return FALSE;
+ }
+ str_append_c(field, ch);
+ }
+ if (*p != '\0')
+ p++;
+
+ /* Verify field body */
+ if (hname_type == _HNAME_BODY) {
+ // FIXME: verify body ...
+ } else {
+ if (!rfc2822_header_field_body_verify(
+ str_c(field), str_len(field), FALSE, FALSE)) {
+ uri_mailto_error(parser,
+ "invalid header field body");
+ return FALSE;
+ }
+ }
+
+ /* Assign field body */
+
+ switch (hname_type) {
+ case _HNAME_IGNORED:
+ break;
+ case _HNAME_TO:
+ /* Gracefully allow duplicate To fields */
+ if (!uri_mailto_parse_header_recipients(
+ parser, field, FALSE))
+ return FALSE;
+ break;
+ case _HNAME_CC:
+ /* Gracefully allow duplicate Cc fields */
+ if (!uri_mailto_parse_header_recipients(
+ parser, field, TRUE))
+ return FALSE;
+ break;
+ case _HNAME_SUBJECT:
+ /* Ignore duplicate subject field */
+ if (uri != NULL) {
+ if (uri->subject == NULL) {
+ uri->subject =
+ p_strdup(parser->pool, str_c(field));
+ } else {
+ uri_mailto_warning(
+ parser,
+ "ignored duplicate subject field");
+ }
+ }
+ break;
+ case _HNAME_BODY:
+ /* Ignore duplicate body field */
+ if (uri != NULL) {
+ if (uri->body == NULL) {
+ uri->body = p_strdup(
+ parser->pool, str_c(field));
+ } else {
+ uri_mailto_warning(
+ parser, "ignored duplicate body field");
+ }
+ }
+ break;
+ case _HNAME_GENERIC:
+ if (uri != NULL && hdrf != NULL)
+ hdrf->body = p_strdup(parser->pool, str_c(field));
+ break;
+ }
+
+ /* Reset for next name */
+ str_truncate(field, 0);
+ }
+
+ /* Skip '&' */
+ if (*p != '\0')
+ p++;
+
+ *uri_p = p;
+ return TRUE;
+}
+
+static bool
+uri_mailto_parse_uri(struct uri_mailto_parser *parser, const char *uri_body)
+{
+ const char *p = uri_body;
+
+ /*
+ * mailtoURI = "mailto:" [ to ] [ hfields ]
+ * to = [ addr-spec *("%2C" addr-spec ) ]
+ * hfields = "?" hfield *( "&" hfield )
+ * hfield = hfname "=" hfvalue
+ * hfname = *qchar
+ * hfvalue = *qchar
+ * addr-spec = local-part "@" domain
+ * local-part = dot-atom / quoted-string
+ * qchar = unreserved / pct-encoded / some-delims
+ * some-delims = "!" / "$" / "'" / "(" / ")" / "*"
+ * / "+" / "," / ";" / ":" / "@"
+ *
+ * to ~= *tqchar
+ * tqchar ~= <qchar> without ";" and ":"
+ *
+ * Scheme 'mailto:' already parsed, starting parse after colon
+ */
+
+ /* First extract to-part by searching for '?' and decoding % items
+ */
+
+ if (!uri_mailto_parse_recipients(parser, &p))
+ return FALSE;
+
+ if (*p == '\0')
+ return TRUE;
+ i_assert(*p == '?');
+ p++;
+
+ /* Extract hfield items */
+
+ while (*p != '\0') {
+ /* Extract hfield item by searching for '&' and decoding '%'
+ items */
+ if (!uri_mailto_parse_headers(parser, &p))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Validation
+ */
+
+bool uri_mailto_validate(const char *uri_body,
+ const char **reserved_headers,
+ const char **unique_headers, int max_recipients,
+ int max_headers, const struct uri_mailto_log *log)
+{
+ struct uri_mailto_parser parser;
+
+ i_zero(&parser);
+ parser.log = log;
+ parser.max_recipients = max_recipients;
+ parser.max_headers = max_headers;
+ parser.reserved_headers = reserved_headers;
+ parser.unique_headers = unique_headers;
+
+ /* If no errors are reported, we don't need to record any data */
+ if (log != NULL) {
+ parser.pool = pool_datastack_create();
+
+ parser.uri = p_new(parser.pool, struct uri_mailto, 1);
+ p_array_init(&parser.uri->recipients, parser.pool, max_recipients);
+ p_array_init(&parser.uri->headers, parser.pool, max_headers);
+ }
+
+ if (!uri_mailto_parse_uri(&parser, uri_body))
+ return FALSE;
+
+ if (log != NULL) {
+ if (array_count(&parser.uri->recipients) == 0) {
+ uri_mailto_warning(
+ &parser,
+ "notification URI specifies no recipients");
+ }
+ }
+ return TRUE;
+}
+
+/*
+ * Parsing
+ */
+
+struct uri_mailto *
+uri_mailto_parse(const char *uri_body, pool_t pool,
+ const char **reserved_headers, const char **unique_headers,
+ int max_recipients, int max_headers,
+ const struct uri_mailto_log *log)
+{
+ struct uri_mailto_parser parser;
+
+ parser.pool = pool;
+ parser.log = log;
+ parser.max_recipients = max_recipients;
+ parser.max_headers = max_headers;
+ parser.reserved_headers = reserved_headers;
+ parser.unique_headers = unique_headers;
+
+ parser.uri = p_new(pool, struct uri_mailto, 1);
+ p_array_init(&parser.uri->recipients, pool, max_recipients);
+ p_array_init(&parser.uri->headers, pool, max_headers);
+
+ if (!uri_mailto_parse_uri(&parser, uri_body))
+ return NULL;
+
+ if (log != NULL) {
+ if (array_count(&parser.uri->recipients) == 0) {
+ uri_mailto_warning(
+ &parser,
+ "notification URI specifies no recipients");
+ }
+ }
+ return parser.uri;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/mailto/uri-mailto.h b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
new file mode 100644
index 0000000..8e9e057
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/uri-mailto.h
@@ -0,0 +1,49 @@
+#ifndef URI_MAILTO_H
+#define URI_MAILTO_H
+
+/*
+ * Types
+ */
+
+struct uri_mailto_header_field {
+ const char *name;
+ const char *body;
+};
+
+struct uri_mailto_recipient {
+ const char *full;
+ const struct smtp_address *address;
+ bool carbon_copy;
+};
+
+ARRAY_DEFINE_TYPE(recipients, struct uri_mailto_recipient);
+ARRAY_DEFINE_TYPE(headers, struct uri_mailto_header_field);
+
+struct uri_mailto_log {
+ void *context;
+
+ void (*logv)(void *context, enum log_type log_type,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *fmt, va_list args) ATTR_FORMAT(5, 0);
+};
+
+struct uri_mailto {
+ ARRAY_TYPE(recipients) recipients;
+ ARRAY_TYPE(headers) headers;
+ const char *subject;
+ const char *body;
+};
+
+bool uri_mailto_validate
+ (const char *uri_body, const char **reserved_headers,
+ const char **unique_headers, int max_recipients, int max_headers,
+ const struct uri_mailto_log *log);
+
+struct uri_mailto *uri_mailto_parse
+(const char *uri_body, pool_t pool, const char **reserved_headers,
+ const char **unique_headers, int max_recipients, int max_headers,
+ const struct uri_mailto_log *log);
+
+#endif
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/sieve-ext-enotify.h b/pigeonhole/src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
new file mode 100644
index 0000000..fd8b574
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/enotify/sieve-ext-enotify.h
@@ -0,0 +1,197 @@
+#ifndef SIEVE_EXT_ENOTIFY_H
+#define SIEVE_EXT_ENOTIFY_H
+
+#include "lib.h"
+#include "compat.h"
+#include <stdarg.h>
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+
+/*
+ * Forward declarations
+ */
+
+struct sieve_enotify_method;
+struct sieve_enotify_env;
+struct sieve_enotify_action;
+struct sieve_enotify_print_env;
+struct sieve_enotify_exec_env;
+
+/*
+ * Notify method definition
+ */
+
+struct sieve_enotify_method_def {
+ const char *identifier;
+
+ /* Registration */
+ bool (*load)
+ (const struct sieve_enotify_method *nmth, void **context);
+ void (*unload)
+ (const struct sieve_enotify_method *nmth);
+
+ /* Validation */
+ bool (*compile_check_uri)
+ (const struct sieve_enotify_env *nenv, const char *uri,
+ const char *uri_body);
+ bool (*compile_check_message)
+ (const struct sieve_enotify_env *nenv, string_t *message);
+ bool (*compile_check_from)
+ (const struct sieve_enotify_env *nenv, string_t *from);
+ bool (*compile_check_option)
+ (const struct sieve_enotify_env *nenv, const char *option,
+ const char *value);
+
+ /* Runtime */
+ bool (*runtime_check_uri)
+ (const struct sieve_enotify_env *nenv, const char *uri,
+ const char *uri_body);
+ const char *(*runtime_get_method_capability)
+ (const struct sieve_enotify_env *nenv, const char *uri,
+ const char *uri_body, const char *capability);
+ bool (*runtime_check_operands)
+ (const struct sieve_enotify_env *nenv, const char *uri,
+ const char *uri_body, string_t *message, string_t *from,
+ pool_t context_pool, void **method_context);
+ bool (*runtime_set_option)
+ (const struct sieve_enotify_env *nenv, void *method_context,
+ const char *option, const char *value);
+
+ /* Action duplicates */
+ int (*action_check_duplicates)
+ (const struct sieve_enotify_env *nenv,
+ const struct sieve_enotify_action *nact,
+ const struct sieve_enotify_action *nact_other);
+
+ /* Action print */
+ void (*action_print)
+ (const struct sieve_enotify_print_env *penv,
+ const struct sieve_enotify_action *nact);
+
+ /* Action execution
+ (returns 0 if all is ok and -1 for temporary error)
+ */
+ int (*action_execute)
+ (const struct sieve_enotify_exec_env *nenv,
+ const struct sieve_enotify_action *nact);
+};
+
+/*
+ * Notify method instance
+ */
+
+struct sieve_enotify_method {
+ const struct sieve_enotify_method_def *def;
+ int id;
+
+ struct sieve_instance *svinst;
+ void *context;
+};
+
+const struct sieve_enotify_method *sieve_enotify_method_register
+ (struct sieve_instance *svinst,
+ const struct sieve_enotify_method_def *nmth_def);
+void sieve_enotify_method_unregister
+ (const struct sieve_enotify_method *nmth);
+
+/*
+ * Notify method environment
+ */
+
+struct sieve_enotify_env {
+ struct sieve_instance *svinst;
+
+ const struct sieve_enotify_method *method;
+
+ struct sieve_error_handler *ehandler;
+ const char *location;
+ struct event *event;
+};
+
+/*
+ * Notify method printing
+ */
+
+void sieve_enotify_method_printf
+ (const struct sieve_enotify_print_env *penv, const char *fmt, ...)
+ ATTR_FORMAT(2, 3);
+
+/*
+ * Notify execution environment
+ */
+
+struct sieve_enotify_exec_env {
+ struct sieve_instance *svinst;
+ enum sieve_execute_flags flags;
+
+ const struct sieve_enotify_method *method;
+
+ const struct sieve_script_env *scriptenv;
+ const struct sieve_message_data *msgdata;
+ struct sieve_message_context *msgctx;
+
+ struct sieve_error_handler *ehandler;
+ const char *location;
+ struct event *event;
+};
+
+struct event_passthrough *
+sieve_enotify_create_finish_event(const struct sieve_enotify_exec_env *nenv);
+
+/*
+ * Notify action
+ */
+
+struct sieve_enotify_action {
+ const struct sieve_enotify_method *method;
+ void *method_context;
+
+ sieve_number_t importance;
+ const char *message;
+ const char *from;
+};
+
+/*
+ * Error handling
+ */
+
+#define sieve_enotify_error(ENV, ...) \
+ sieve_event_log((ENV)->svinst, (ENV)->ehandler, (ENV)->event, \
+ LOG_TYPE_ERROR, (ENV)->location, 0, __VA_ARGS__ )
+#define sieve_enotify_warning(ENV, ...) \
+ sieve_event_log((ENV)->svinst, (ENV)->ehandler, (ENV)->event, \
+ LOG_TYPE_WARNING, \
+ (ENV)->location, 0, __VA_ARGS__ )
+#define sieve_enotify_info(ENV, ...) \
+ sieve_event_log((ENV)->svinst, (ENV)->ehandler, (ENV)->event, \
+ LOG_TYPE_INFO, \
+ (ENV)->location, 0, __VA_ARGS__ )
+#define sieve_enotify_critical(ENV, ...) \
+ sieve_critical((ENV)->svinst, (ENV)->ehandler, NULL, __VA_ARGS__ )
+
+#define sieve_enotify_global_error(ENV, ...) \
+ sieve_event_log((ENV)->svinst, (ENV)->ehandler, (ENV)->event, \
+ LOG_TYPE_ERROR, (ENV)->location, \
+ SIEVE_ERROR_FLAG_GLOBAL, __VA_ARGS__ )
+#define sieve_enotify_global_warning(ENV, ...) \
+ sieve_event_log((ENV)->svinst, (ENV)->ehandler, (ENV)->event, \
+ LOG_TYPE_WARNING, (ENV)->location, \
+ SIEVE_ERROR_FLAG_GLOBAL, __VA_ARGS__ )
+#define sieve_enotify_global_info(ENV, ...) \
+ sieve_event_log((ENV)->svinst, (ENV)->ehandler, (ENV)->event, \
+ LOG_TYPE_INFO, (ENV)->location, \
+ SIEVE_ERROR_FLAG_GLOBAL, __VA_ARGS__ )
+
+#define sieve_enotify_event_log(ENV, EVENT, ...) \
+ sieve_event_log((ENV)->svinst, (ENV)->ehandler, (EVENT), \
+ LOG_TYPE_INFO, (ENV)->location, \
+ SIEVE_ERROR_FLAG_GLOBAL, __VA_ARGS__ )
+
+#define sieve_enotify_global_log_error(ENV, ...) \
+ sieve_event_log((ENV)->svinst, (ENV)->ehandler, (ENV)->event, \
+ LOG_TYPE_ERROR, (ENV)->location, \
+ (SIEVE_ERROR_FLAG_GLOBAL | \
+ SIEVE_ERROR_FLAG_GLOBAL_MAX_INFO), __VA_ARGS__ )
+#endif
+
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/tst-notify-method-capability.c b/pigeonhole/src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
new file mode 100644
index 0000000..8a6c071
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/enotify/tst-notify-method-capability.c
@@ -0,0 +1,233 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-match.h"
+
+#include "ext-enotify-common.h"
+
+/*
+ * String test
+ *
+ * Syntax:
+ * notify_method_capability [COMPARATOR] [MATCH-TYPE]
+ * <notification-uri: string>
+ * <notification-capability: string>
+ * <key-list: string-list>
+ */
+
+static bool tst_notifymc_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool tst_notifymc_validate
+ (struct sieve_validator *valdtr, struct sieve_command *tst);
+static bool tst_notifymc_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+const struct sieve_command_def notify_method_capability_test = {
+ .identifier = "notify_method_capability",
+ .type = SCT_TEST,
+ .positional_args = 3,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_notifymc_registered,
+ .validate = tst_notifymc_validate,
+ .generate = tst_notifymc_generate
+};
+
+/*
+ * String operation
+ */
+
+static bool tst_notifymc_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int tst_notifymc_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def notify_method_capability_operation = {
+ .mnemonic = "NOTIFY_METHOD_CAPABILITY",
+ .ext_def = &enotify_extension,
+ .code = EXT_ENOTIFY_OPERATION_NOTIFY_METHOD_CAPABILITY,
+ .dump = tst_notifymc_operation_dump,
+ .execute = tst_notifymc_operation_execute
+};
+
+/*
+ * Optional arguments
+ */
+
+enum tst_notifymc_optional {
+ OPT_END,
+ OPT_COMPARATOR,
+ OPT_MATCH_TYPE
+};
+
+/*
+ * Test registration
+ */
+
+static bool tst_notifymc_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_command_registration *cmd_reg)
+{
+ /* The order of these is not significant */
+ sieve_comparators_link_tag(valdtr, cmd_reg, OPT_COMPARATOR);
+ sieve_match_types_link_tags(valdtr, cmd_reg, OPT_MATCH_TYPE);
+
+ return TRUE;
+}
+
+/*
+ * Test validation
+ */
+
+static bool tst_notifymc_validate
+(struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+ const struct sieve_match_type mcht_default =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ const struct sieve_comparator cmp_default =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "notification-uri", 1, SAAT_STRING) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ arg = sieve_ast_argument_next(arg);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "notification-capability", 2, SAAT_STRING) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ arg = sieve_ast_argument_next(arg);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "key-list", 3, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ /* Validate the key argument to a specified match type */
+ return sieve_match_type_validate
+ (valdtr, tst, arg, &mcht_default, &cmp_default);
+}
+
+/*
+ * Test generation
+ */
+
+static bool tst_notifymc_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ sieve_operation_emit
+ (cgenv->sblock, cmd->ext, &notify_method_capability_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, cmd, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool tst_notifymc_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "NOTIFY_METHOD_CAPABILITY");
+ sieve_code_descend(denv);
+
+ /* Handle any optional arguments */
+ if ( sieve_match_opr_optional_dump(denv, address, NULL) != 0 )
+ return FALSE;
+
+ return
+ sieve_opr_string_dump(denv, address, "notify uri") &&
+ sieve_opr_string_dump(denv, address, "notify capability") &&
+ sieve_opr_stringlist_dump(denv, address, "key list");
+}
+
+/*
+ * Code execution
+ */
+
+static int tst_notifymc_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ struct sieve_match_type mcht =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ struct sieve_comparator cmp =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+ string_t *notify_uri, *notify_capability;
+ struct sieve_stringlist *value_list, *key_list;
+ const char *cap_value;
+ int match, ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Handle match-type and comparator operands */
+ if ( sieve_match_opr_optional_read
+ (renv, address, NULL, &ret, &cmp, &mcht) < 0 )
+ return ret;
+
+ /* Read notify uri */
+ if ( (ret=sieve_opr_string_read(renv, address, "notify-uri", &notify_uri))
+ <= 0 )
+ return ret;
+
+ /* Read notify capability */
+ if ( (ret=sieve_opr_string_read
+ (renv, address, "notify-capability", &notify_capability)) <= 0 )
+ return ret;
+
+ /* Read key-list */
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "key-list", &key_list))
+ <= 0)
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "notify_method_capability test");
+
+ cap_value = ext_enotify_runtime_get_method_capability
+ (renv, notify_uri, str_c(notify_capability));
+
+ if ( cap_value != NULL ) {
+ value_list = sieve_single_stringlist_create_cstr(renv, cap_value, TRUE);
+
+ /* Perform match */
+ if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret))
+ < 0 )
+ return ret;
+ } else {
+ match = 0;
+ }
+
+ /* Set test result for subsequent conditional jump */
+ sieve_interpreter_set_test_result(renv->interp, match > 0);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c b/pigeonhole/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
new file mode 100644
index 0000000..becc41c
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c
@@ -0,0 +1,144 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-match.h"
+
+#include "ext-enotify-common.h"
+
+/*
+ * Valid_notify_method test
+ *
+ * Syntax:
+ * valid_notify_method <notification-uris: string-list>
+ */
+
+static bool tst_vnotifym_validate
+ (struct sieve_validator *valdtr, struct sieve_command *tst);
+static bool tst_vnotifym_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+const struct sieve_command_def valid_notify_method_test = {
+ .identifier = "valid_notify_method",
+ .type = SCT_TEST,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = tst_vnotifym_validate,
+ .generate = tst_vnotifym_generate
+};
+
+/*
+ * Valid_notify_method operation
+ */
+
+static bool tst_vnotifym_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int tst_vnotifym_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def valid_notify_method_operation = {
+ .mnemonic = "VALID_NOTIFY_METHOD",
+ .ext_def = &enotify_extension,
+ .code = EXT_ENOTIFY_OPERATION_VALID_NOTIFY_METHOD,
+ .dump = tst_vnotifym_operation_dump,
+ .execute = tst_vnotifym_operation_execute
+};
+
+/*
+ * Test validation
+ */
+
+static bool tst_vnotifym_validate
+ (struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "notification-uris", 1, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ return sieve_validator_argument_activate(valdtr, tst, arg, FALSE);
+}
+
+/*
+ * Test generation
+ */
+
+static bool tst_vnotifym_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &valid_notify_method_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, cmd, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool tst_vnotifym_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "VALID_NOTIFY_METHOD");
+ sieve_code_descend(denv);
+
+ return
+ sieve_opr_stringlist_dump(denv, address, "notify-uris");
+}
+
+/*
+ * Code execution
+ */
+
+static int tst_vnotifym_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ struct sieve_stringlist *notify_uris;
+ string_t *uri_item;
+ bool all_valid = TRUE;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Read notify uris */
+ if ( (ret=sieve_opr_stringlist_read
+ (renv, address, "notify-uris", &notify_uris)) <= 0 )
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "valid_notify_method test");
+
+ uri_item = NULL;
+ while ( (ret=sieve_stringlist_next_item(notify_uris, &uri_item)) > 0 ) {
+ if ( !ext_enotify_runtime_method_validate(renv, uri_item) ) {
+ all_valid = FALSE;
+ break;
+ }
+ }
+
+ if ( ret < 0 ) {
+ sieve_runtime_trace_error(renv, "invalid method uri item");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ sieve_interpreter_set_test_result(renv->interp, all_valid);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/vmodf-encodeurl.c b/pigeonhole/src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
new file mode 100644
index 0000000..801f882
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/enotify/vmodf-encodeurl.c
@@ -0,0 +1,119 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "unichar.h"
+#include "str.h"
+
+#include "sieve-common.h"
+#include "sieve-code.h"
+
+#include "sieve-ext-variables.h"
+
+#include "ext-enotify-common.h"
+
+/*
+ * Encodeurl modifier
+ */
+
+static bool
+mod_encodeurl_modify(const struct sieve_variables_modifier *modf,
+ string_t *in, string_t **result);
+
+const struct sieve_variables_modifier_def encodeurl_modifier = {
+ SIEVE_OBJECT("encodeurl", &encodeurl_operand, 0),
+ 15,
+ mod_encodeurl_modify
+};
+
+/*
+ * Modifier operand
+ */
+
+static const struct sieve_extension_objects ext_enotify_modifiers =
+ SIEVE_VARIABLES_DEFINE_MODIFIER(encodeurl_modifier);
+
+const struct sieve_operand_def encodeurl_operand = {
+ .name = "modifier",
+ .ext_def = &enotify_extension,
+ .class = &sieve_variables_modifier_operand_class,
+ .interface = &ext_enotify_modifiers
+};
+
+/*
+ * Modifier implementation
+ */
+
+static const char _uri_reserved_lookup[256] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 00
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, // 20
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, // 30
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, // 50
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, // 70
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 90
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // F0
+};
+
+static bool
+mod_encodeurl_modify(const struct sieve_variables_modifier *modf,
+ string_t *in, string_t **result)
+{
+ size_t max_var_size =
+ sieve_variables_get_max_variable_size(modf->var_ext);
+ const unsigned char *p, *poff, *pend;
+ size_t new_size;
+
+ if ( str_len(in) == 0 ) {
+ *result = in;
+ return TRUE;
+ }
+
+ /* allocate new string */
+ new_size = str_len(in) + 32;
+ if (new_size > max_var_size)
+ new_size = max_var_size;
+ *result = t_str_new(new_size + 1);
+
+ /* escape string */
+ p = str_data(in);
+ pend = p + str_len(in);
+ poff = p;
+ while (p < pend) {
+ unsigned int i, n = uni_utf8_char_bytes(*p);
+
+ if (n > 1 || (_uri_reserved_lookup[*p] & 0x01) != 0) {
+ str_append_data(*result, poff, p - poff);
+ poff = p;
+
+ if (str_len(*result) + 3 * n > max_var_size)
+ break;
+
+ str_printfa(*result, "%%%02X", *p);
+ for (i = 1; i < n && p < pend; i++) {
+ p++;
+ poff++;
+ str_printfa(*result, "%%%02X", *p);
+ }
+
+ poff++;
+ } else if ((str_len(*result) + (p - poff) + 1) > max_var_size) {
+ break;
+ }
+ p++;
+ }
+
+ str_append_data(*result, poff, p - poff);
+ return TRUE;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/environment/Makefile.am b/pigeonhole/src/lib-sieve/plugins/environment/Makefile.am
new file mode 100644
index 0000000..916362e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/environment/Makefile.am
@@ -0,0 +1,24 @@
+noinst_LTLIBRARIES = libsieve_ext_environment.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+tests = \
+ tst-environment.c
+
+libsieve_ext_environment_la_SOURCES = \
+ $(tests) \
+ ext-environment-common.c \
+ ext-environment.c
+
+public_headers = \
+ sieve-ext-environment.h
+
+headers = \
+ ext-environment-common.h
+
+pkginc_libdir=$(dovecot_pkgincludedir)/sieve
+pkginc_lib_HEADERS = $(public_headers)
+noinst_HEADERS = $(headers)
+
diff --git a/pigeonhole/src/lib-sieve/plugins/environment/Makefile.in b/pigeonhole/src/lib-sieve/plugins/environment/Makefile.in
new file mode 100644
index 0000000..68424f4
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/environment/Makefile.in
@@ -0,0 +1,753 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/environment
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(pkginc_lib_HEADERS) $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_environment_la_LIBADD =
+am__objects_1 = tst-environment.lo
+am_libsieve_ext_environment_la_OBJECTS = $(am__objects_1) \
+ ext-environment-common.lo ext-environment.lo
+libsieve_ext_environment_la_OBJECTS = \
+ $(am_libsieve_ext_environment_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ext-environment-common.Plo \
+ ./$(DEPDIR)/ext-environment.Plo \
+ ./$(DEPDIR)/tst-environment.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_environment_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_environment_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkginc_libdir)"
+HEADERS = $(noinst_HEADERS) $(pkginc_lib_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_environment.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+tests = \
+ tst-environment.c
+
+libsieve_ext_environment_la_SOURCES = \
+ $(tests) \
+ ext-environment-common.c \
+ ext-environment.c
+
+public_headers = \
+ sieve-ext-environment.h
+
+headers = \
+ ext-environment-common.h
+
+pkginc_libdir = $(dovecot_pkgincludedir)/sieve
+pkginc_lib_HEADERS = $(public_headers)
+noinst_HEADERS = $(headers)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/environment/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/environment/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_environment.la: $(libsieve_ext_environment_la_OBJECTS) $(libsieve_ext_environment_la_DEPENDENCIES) $(EXTRA_libsieve_ext_environment_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_environment_la_OBJECTS) $(libsieve_ext_environment_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-environment-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-environment.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-environment.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
+ done
+
+uninstall-pkginc_libHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(pkginc_libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ext-environment-common.Plo
+ -rm -f ./$(DEPDIR)/ext-environment.Plo
+ -rm -f ./$(DEPDIR)/tst-environment.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkginc_libHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ext-environment-common.Plo
+ -rm -f ./$(DEPDIR)/ext-environment.Plo
+ -rm -f ./$(DEPDIR)/tst-environment.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkginc_libHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-pkginc_libHEADERS install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-pkginc_libHEADERS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/environment/ext-environment-common.c b/pigeonhole/src/lib-sieve/plugins/environment/ext-environment-common.c
new file mode 100644
index 0000000..28d4251
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/environment/ext-environment-common.c
@@ -0,0 +1,339 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "hash.h"
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+#include "sieve-interpreter.h"
+
+#include "ext-environment-common.h"
+
+struct ext_environment_interpreter_context;
+
+/*
+ * Core environment items
+ */
+
+static const struct sieve_environment_item *core_env_items[] = {
+ &domain_env_item,
+ &host_env_item,
+ &location_env_item,
+ &phase_env_item,
+ &name_env_item,
+ &version_env_item
+};
+
+static unsigned int core_env_items_count = N_ELEMENTS(core_env_items);
+
+static void
+sieve_environment_item_insert(struct ext_environment_interpreter_context *ctx,
+ const struct sieve_environment_item *item);
+
+/*
+ * Validator context
+ */
+
+struct ext_environment_interpreter_context {
+ HASH_TABLE(const char *,
+ const struct sieve_environment_item *) name_items;
+ ARRAY(const struct sieve_environment_item *) prefix_items;
+
+ bool active:1;
+};
+
+static void
+ext_environment_interpreter_extension_free(const struct sieve_extension *ext,
+ struct sieve_interpreter *interp,
+ void *context);
+
+struct sieve_interpreter_extension environment_interpreter_extension = {
+ .ext_def = &environment_extension,
+ .free = ext_environment_interpreter_extension_free,
+};
+
+static struct ext_environment_interpreter_context *
+ext_environment_interpreter_context_create(
+ const struct sieve_extension *this_ext,
+ struct sieve_interpreter *interp)
+{
+ pool_t pool = sieve_interpreter_pool(interp);
+ struct ext_environment_interpreter_context *ctx;
+
+ ctx = p_new(pool, struct ext_environment_interpreter_context, 1);
+
+ hash_table_create(&ctx->name_items, default_pool, 0, str_hash, strcmp);
+ i_array_init(&ctx->prefix_items, 16);
+
+ sieve_interpreter_extension_register(interp, this_ext,
+ &environment_interpreter_extension,
+ (void *)ctx);
+ return ctx;
+}
+
+static void
+ext_environment_interpreter_extension_free(
+ const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_interpreter *interp ATTR_UNUSED, void *context)
+{
+ struct ext_environment_interpreter_context *ctx =
+ (struct ext_environment_interpreter_context *)context;
+
+ hash_table_destroy(&ctx->name_items);
+ array_free(&ctx->prefix_items);
+}
+
+static struct ext_environment_interpreter_context *
+ext_environment_interpreter_context_get(const struct sieve_extension *this_ext,
+ struct sieve_interpreter *interp)
+{
+ struct ext_environment_interpreter_context *ctx =
+ (struct ext_environment_interpreter_context *)
+ sieve_interpreter_extension_get_context(interp, this_ext);
+
+ if (ctx == NULL) {
+ ctx = ext_environment_interpreter_context_create(
+ this_ext, interp);
+ }
+ return ctx;
+}
+
+void ext_environment_interpreter_init(const struct sieve_extension *this_ext,
+ struct sieve_interpreter *interp)
+{
+ struct ext_environment_interpreter_context *ctx;
+ unsigned int i;
+
+ /* Create our context */
+ ctx = ext_environment_interpreter_context_get(this_ext, interp);
+
+ for (i = 0; i < core_env_items_count; i++)
+ sieve_environment_item_insert(ctx, core_env_items[i]);
+
+ ctx->active = TRUE;
+}
+
+bool sieve_ext_environment_is_active(const struct sieve_extension *env_ext,
+ struct sieve_interpreter *interp)
+{
+ struct ext_environment_interpreter_context *ctx =
+ ext_environment_interpreter_context_get(env_ext, interp);
+
+ return (ctx != NULL && ctx->active);
+}
+
+/*
+ * Registration
+ */
+
+static void
+sieve_environment_item_insert(struct ext_environment_interpreter_context *ctx,
+ const struct sieve_environment_item *item)
+{
+ if (!item->prefix)
+ hash_table_insert(ctx->name_items, item->name, item);
+ else
+ array_append(&ctx->prefix_items, &item, 1);
+}
+
+void sieve_environment_item_register(const struct sieve_extension *env_ext,
+ struct sieve_interpreter *interp,
+ const struct sieve_environment_item *item)
+{
+ struct ext_environment_interpreter_context *ctx;
+
+ i_assert(sieve_extension_is(env_ext, environment_extension));
+ ctx = ext_environment_interpreter_context_get(env_ext, interp);
+
+ sieve_environment_item_insert(ctx, item);
+}
+
+/*
+ * Retrieval
+ */
+
+static const struct sieve_environment_item *
+ext_environment_item_lookup(struct ext_environment_interpreter_context *ctx,
+ const char **_name)
+{
+ const struct sieve_environment_item *item;
+ const char *name = *_name;
+
+ item = hash_table_lookup(ctx->name_items, name);
+ if (item != NULL)
+ return item;
+
+ array_foreach_elem(&ctx->prefix_items, item) {
+ size_t prefix_len;
+
+ i_assert(item->prefix);
+ prefix_len = strlen(item->name);
+
+ if (str_begins(name, item->name)) {
+ if (name[prefix_len] == '.') {
+ *_name = &name[prefix_len+1];
+ return item;
+ } else if (name[prefix_len] == '\0') {
+ *_name = &name[prefix_len+1];
+ return item;
+ }
+ }
+ }
+ return NULL;
+}
+
+const char *
+ext_environment_item_get_value(const struct sieve_extension *env_ext,
+ const struct sieve_runtime_env *renv,
+ const char *name)
+{
+ struct ext_environment_interpreter_context *ctx;
+ const struct sieve_environment_item *item;
+
+ i_assert(sieve_extension_is(env_ext, environment_extension));
+ ctx = ext_environment_interpreter_context_get(env_ext, renv->interp);
+
+ item = ext_environment_item_lookup(ctx, &name);
+ if (item == NULL)
+ return NULL;
+
+ if (item->value != NULL)
+ return item->value;
+ if (item->get_value != NULL)
+ return item->get_value(renv, name);
+ return NULL;
+}
+
+/*
+ * Default environment items
+ */
+
+/* "domain":
+
+ The primary DNS domain associated with the Sieve execution context, usually
+ but not always a proper suffix of the host name.
+ */
+
+static const char *
+envit_domain_get_value(const struct sieve_runtime_env *renv,
+ const char *name ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+
+ return eenv->svinst->domainname;
+}
+
+const struct sieve_environment_item domain_env_item = {
+ .name = "domain",
+ .get_value = envit_domain_get_value,
+};
+
+/* "host":
+
+ The fully-qualified domain name of the host where the Sieve script is
+ executing.
+ */
+
+static const char *
+envit_host_get_value(const struct sieve_runtime_env *renv,
+ const char *name ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+
+ return eenv->svinst->hostname;
+}
+
+const struct sieve_environment_item host_env_item = {
+ .name = "host",
+ .get_value = envit_host_get_value,
+};
+
+/* "location":
+
+ Sieve evaluation can be performed at various different points as messages
+ are processed. This item provides additional information about the type of
+ service that is evaluating the script. Possible values are:
+ "MTA" - the Sieve script is being evaluated by a Message Transfer Agent
+ "MDA" - evaluation is being performed by a Mail Delivery Agent
+ "MUA" - evaluation is being performed by a Mail User Agent (right...)
+ "MS" - evaluation is being performed by a Message Store
+ */
+
+static const char *
+envit_location_get_value(const struct sieve_runtime_env *renv,
+ const char *name ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+
+ switch (eenv->svinst->env_location ) {
+ case SIEVE_ENV_LOCATION_MDA:
+ return "MDA";
+ case SIEVE_ENV_LOCATION_MTA:
+ return "MTA";
+ case SIEVE_ENV_LOCATION_MS:
+ return "MS";
+ default:
+ break;
+ }
+ return NULL;
+}
+
+const struct sieve_environment_item location_env_item = {
+ .name = "location",
+ .get_value = envit_location_get_value
+};
+
+/* "phase":
+
+ The point relative to final delivery where the Sieve script is being
+ evaluated. Possible values are "pre", "during", and "post", referring
+ respectively to processing before, during, and after final delivery has
+ taken place.
+ */
+
+static const char *
+envit_phase_get_value(const struct sieve_runtime_env *renv,
+ const char *name ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+
+ switch (eenv->svinst->delivery_phase) {
+ case SIEVE_DELIVERY_PHASE_PRE:
+ return "pre";
+ case SIEVE_DELIVERY_PHASE_DURING:
+ return "during";
+ case SIEVE_DELIVERY_PHASE_POST:
+ return "post";
+ default:
+ break;
+ }
+ return NULL;
+}
+
+const struct sieve_environment_item phase_env_item = {
+ .name = "phase",
+ .get_value = envit_phase_get_value
+};
+
+/* "name":
+
+ The product name associated with the Sieve interpreter.
+ */
+
+const struct sieve_environment_item name_env_item = {
+ .name = "name",
+ .value = PIGEONHOLE_NAME" Sieve"
+};
+
+/* "version":
+
+ The product version associated with the Sieve interpreter. The meaning of the
+ product version string is product-specific and should always be considered
+ in the context of the product name given by the "name" item.
+ */
+
+const struct sieve_environment_item version_env_item = {
+ .name = "version",
+ .value = PIGEONHOLE_VERSION,
+};
diff --git a/pigeonhole/src/lib-sieve/plugins/environment/ext-environment-common.h b/pigeonhole/src/lib-sieve/plugins/environment/ext-environment-common.h
new file mode 100644
index 0000000..288b82e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/environment/ext-environment-common.h
@@ -0,0 +1,53 @@
+#ifndef EXT_ENVIRONMENT_COMMON_H
+#define EXT_ENVIRONMENT_COMMON_H
+
+#include "lib.h"
+
+#include "sieve-common.h"
+
+#include "sieve-ext-environment.h"
+
+/*
+ * Extension
+ */
+
+extern const struct sieve_extension_def environment_extension;
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def tst_environment;
+
+/*
+ * Operations
+ */
+
+extern const struct sieve_operation_def tst_environment_operation;
+
+/*
+ * Environment items
+ */
+
+extern const struct sieve_environment_item domain_env_item;
+extern const struct sieve_environment_item host_env_item;
+extern const struct sieve_environment_item location_env_item;
+extern const struct sieve_environment_item phase_env_item;
+extern const struct sieve_environment_item name_env_item;
+extern const struct sieve_environment_item version_env_item;
+
+/*
+ * Initialization
+ */
+
+bool ext_environment_init(const struct sieve_extension *ext, void **context);
+void ext_environment_deinit(const struct sieve_extension *ext);
+
+/*
+ * Validator context
+ */
+
+void ext_environment_interpreter_init(const struct sieve_extension *this_ext,
+ struct sieve_interpreter *interp);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/environment/ext-environment.c b/pigeonhole/src/lib-sieve/plugins/environment/ext-environment.c
new file mode 100644
index 0000000..c2130a2
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/environment/ext-environment.c
@@ -0,0 +1,59 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension variables
+ * -------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5183
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "unichar.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+
+#include "sieve-validator.h"
+
+#include "ext-environment-common.h"
+
+/*
+ * Extension
+ */
+
+static bool ext_environment_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+static bool ext_environment_interpreter_load
+(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_extension_def environment_extension = {
+ .name = "environment",
+ .validator_load = ext_environment_validator_load,
+ .interpreter_load = ext_environment_interpreter_load,
+ SIEVE_EXT_DEFINE_OPERATION(tst_environment_operation)
+};
+
+static bool ext_environment_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ sieve_validator_register_command(valdtr, ext, &tst_environment);
+ return TRUE;
+}
+
+static bool ext_environment_interpreter_load
+(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ ext_environment_interpreter_init(ext, renv->interp);
+ return TRUE;
+}
+
diff --git a/pigeonhole/src/lib-sieve/plugins/environment/sieve-ext-environment.h b/pigeonhole/src/lib-sieve/plugins/environment/sieve-ext-environment.h
new file mode 100644
index 0000000..8ae0d18
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/environment/sieve-ext-environment.h
@@ -0,0 +1,54 @@
+#ifndef SIEVE_EXT_ENVIRONMENT_H
+#define SIEVE_EXT_ENVIRONMENT_H
+
+#include "sieve-common.h"
+
+/*
+ * Environment extension
+ */
+
+/* FIXME: this is not suitable for future plugin support */
+
+extern const struct sieve_extension_def environment_extension;
+
+static inline const struct sieve_extension *
+sieve_ext_environment_get_extension
+(struct sieve_instance *svinst)
+{
+ return sieve_extension_register
+ (svinst, &environment_extension, FALSE);
+}
+
+static inline const struct sieve_extension *
+sieve_ext_environment_require_extension
+(struct sieve_instance *svinst)
+{
+ return sieve_extension_require
+ (svinst, &environment_extension, TRUE);
+}
+
+bool sieve_ext_environment_is_active
+ (const struct sieve_extension *env_ext,
+ struct sieve_interpreter *interp);
+
+/*
+ * Environment item
+ */
+
+struct sieve_environment_item {
+ const char *name;
+ bool prefix;
+
+ const char *value;
+ const char *(*get_value)
+ (const struct sieve_runtime_env *renv, const char *name);
+};
+
+void sieve_environment_item_register
+ (const struct sieve_extension *env_ext, struct sieve_interpreter *interp,
+ const struct sieve_environment_item *item);
+const char *ext_environment_item_get_value
+ (const struct sieve_extension *env_ext,
+ const struct sieve_runtime_env *renv, const char *name);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/environment/tst-environment.c b/pigeonhole/src/lib-sieve/plugins/environment/tst-environment.c
new file mode 100644
index 0000000..9eaa099
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/environment/tst-environment.c
@@ -0,0 +1,215 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-match.h"
+
+#include "ext-environment-common.h"
+
+/*
+ * Environment test
+ *
+ * Syntax:
+ * environment [COMPARATOR] [MATCH-TYPE]
+ * <name: string> <key-list: string-list>
+ */
+
+static bool tst_environment_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool tst_environment_validate
+ (struct sieve_validator *valdtr, struct sieve_command *tst);
+static bool tst_environment_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
+
+const struct sieve_command_def tst_environment = {
+ .identifier = "environment",
+ .type = SCT_TEST,
+ .positional_args = 2,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_environment_registered,
+ .validate = tst_environment_validate,
+ .generate = tst_environment_generate
+};
+
+/*
+ * Environment operation
+ */
+
+static bool tst_environment_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int tst_environment_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def tst_environment_operation = {
+ .mnemonic = "ENVIRONMENT",
+ .ext_def = &environment_extension,
+ .dump = tst_environment_operation_dump,
+ .execute = tst_environment_operation_execute
+};
+
+/*
+ * Test registration
+ */
+
+static bool tst_environment_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_command_registration *cmd_reg)
+{
+ /* The order of these is not significant */
+ sieve_comparators_link_tag(valdtr, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
+ sieve_match_types_link_tags(valdtr, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
+
+ return TRUE;
+}
+
+/*
+ * Test validation
+ */
+
+static bool tst_environment_validate
+(struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+ const struct sieve_match_type mcht_default =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ const struct sieve_comparator cmp_default =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "name", 1, SAAT_STRING) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ arg = sieve_ast_argument_next(arg);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "key list", 2, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ /* Validate the key argument to a specified match type */
+ return sieve_match_type_validate
+ (valdtr, tst, arg, &mcht_default, &cmp_default);
+}
+
+/*
+ * Test generation
+ */
+
+static bool tst_environment_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &tst_environment_operation);
+
+ /* Generate arguments */
+ if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool tst_environment_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "ENVIRONMENT");
+ sieve_code_descend(denv);
+
+ /* Optional operands */
+ if ( sieve_match_opr_optional_dump(denv, address, NULL) != 0 )
+ return FALSE;
+
+ return
+ sieve_opr_string_dump(denv, address, "name") &&
+ sieve_opr_stringlist_dump(denv, address, "key list");
+}
+
+/*
+ * Code execution
+ */
+
+static int tst_environment_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ struct sieve_match_type mcht =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ struct sieve_comparator cmp =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+ string_t *name;
+ struct sieve_stringlist *value_list, *key_list;
+ const char *env_item;
+ int match, ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Handle match-type and comparator operands */
+ if ( sieve_match_opr_optional_read
+ (renv, address, NULL, &ret, &cmp, &mcht) < 0 )
+ return ret;
+
+ /* Read source */
+ if ( (ret=sieve_opr_string_read(renv, address, "name", &name)) <= 0 )
+ return ret;
+
+ /* Read key-list */
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "key-list", &key_list))
+ <= 0 )
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "environment test");
+
+ env_item = ext_environment_item_get_value
+ (this_ext, renv, str_c(name));
+
+ if ( env_item != NULL ) {
+ /* Construct value list */
+ value_list = sieve_single_stringlist_create_cstr(renv, env_item, FALSE);
+
+ /* Perform match */
+ if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret))
+ < 0 )
+ return ret;
+ } else {
+ match = 0;
+
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "environment item `%s' not found",
+ str_sanitize(str_c(name), 128));
+ }
+
+ /* Set test result for subsequent conditional jump */
+ sieve_interpreter_set_test_result(renv->interp, match > 0);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/ihave/Makefile.am b/pigeonhole/src/lib-sieve/plugins/ihave/Makefile.am
new file mode 100644
index 0000000..1eb0472
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/ihave/Makefile.am
@@ -0,0 +1,22 @@
+noinst_LTLIBRARIES = libsieve_ext_ihave.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+tests = \
+ tst-ihave.c
+
+commands = \
+ cmd-error.c
+
+libsieve_ext_ihave_la_SOURCES = \
+ $(tests) \
+ $(commands) \
+ ext-ihave-binary.c \
+ ext-ihave-common.c \
+ ext-ihave.c
+
+noinst_HEADERS = \
+ ext-ihave-binary.h \
+ ext-ihave-common.h
diff --git a/pigeonhole/src/lib-sieve/plugins/ihave/Makefile.in b/pigeonhole/src/lib-sieve/plugins/ihave/Makefile.in
new file mode 100644
index 0000000..c5b8952
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/ihave/Makefile.in
@@ -0,0 +1,707 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/ihave
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_ihave_la_LIBADD =
+am__objects_1 = tst-ihave.lo
+am__objects_2 = cmd-error.lo
+am_libsieve_ext_ihave_la_OBJECTS = $(am__objects_1) $(am__objects_2) \
+ ext-ihave-binary.lo ext-ihave-common.lo ext-ihave.lo
+libsieve_ext_ihave_la_OBJECTS = $(am_libsieve_ext_ihave_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cmd-error.Plo \
+ ./$(DEPDIR)/ext-ihave-binary.Plo \
+ ./$(DEPDIR)/ext-ihave-common.Plo ./$(DEPDIR)/ext-ihave.Plo \
+ ./$(DEPDIR)/tst-ihave.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_ihave_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_ihave_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_ihave.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+tests = \
+ tst-ihave.c
+
+commands = \
+ cmd-error.c
+
+libsieve_ext_ihave_la_SOURCES = \
+ $(tests) \
+ $(commands) \
+ ext-ihave-binary.c \
+ ext-ihave-common.c \
+ ext-ihave.c
+
+noinst_HEADERS = \
+ ext-ihave-binary.h \
+ ext-ihave-common.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/ihave/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/ihave/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_ihave.la: $(libsieve_ext_ihave_la_OBJECTS) $(libsieve_ext_ihave_la_DEPENDENCIES) $(EXTRA_libsieve_ext_ihave_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_ihave_la_OBJECTS) $(libsieve_ext_ihave_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-error.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-ihave-binary.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-ihave-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-ihave.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-ihave.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/cmd-error.Plo
+ -rm -f ./$(DEPDIR)/ext-ihave-binary.Plo
+ -rm -f ./$(DEPDIR)/ext-ihave-common.Plo
+ -rm -f ./$(DEPDIR)/ext-ihave.Plo
+ -rm -f ./$(DEPDIR)/tst-ihave.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/cmd-error.Plo
+ -rm -f ./$(DEPDIR)/ext-ihave-binary.Plo
+ -rm -f ./$(DEPDIR)/ext-ihave-common.Plo
+ -rm -f ./$(DEPDIR)/ext-ihave.Plo
+ -rm -f ./$(DEPDIR)/tst-ihave.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/ihave/cmd-error.c b/pigeonhole/src/lib-sieve/plugins/ihave/cmd-error.c
new file mode 100644
index 0000000..6e971bd
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/ihave/cmd-error.c
@@ -0,0 +1,131 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-ihave-common.h"
+
+/*
+ * Error command
+ *
+ * Syntax
+ * error <message: string>
+ */
+
+static bool cmd_error_validate
+ (struct sieve_validator *valdtr, struct sieve_command *tst);
+static bool cmd_error_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+const struct sieve_command_def error_command = {
+ .identifier = "error",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_error_validate,
+ .generate = cmd_error_generate
+};
+
+/*
+ * Body operation
+ */
+
+static bool cmd_error_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int cmd_error_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def cmd_error_operation = {
+ .mnemonic = "ERROR",
+ .ext_def = &ihave_extension,
+ .code = EXT_IHAVE_OPERATION_ERROR,
+ .dump = cmd_error_operation_dump,
+ .execute = cmd_error_operation_execute
+};
+
+/*
+ * Validation
+ */
+
+static bool cmd_error_validate
+(struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "message", 1, SAAT_STRING) ) {
+ return FALSE;
+ }
+
+ return sieve_validator_argument_activate(valdtr, tst, arg, FALSE);
+}
+
+/*
+ * Code generation
+ */
+
+static bool cmd_error_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ (void)sieve_operation_emit(cgenv->sblock, cmd->ext, &cmd_error_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, cmd, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool cmd_error_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "ERROR");
+ sieve_code_descend(denv);
+
+ return sieve_opr_string_dump(denv, address, "message");
+}
+
+/*
+ * Interpretation
+ */
+
+static int cmd_error_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ string_t *message;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Read message */
+
+ if ( (ret=sieve_opr_string_read(renv, address, "message", &message)) <= 0 )
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "error \"%s\"",
+ str_sanitize(str_c(message), 80));
+
+ sieve_runtime_error(renv, NULL, "%s", str_c(message));
+
+ return SIEVE_EXEC_FAILURE;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-binary.c b/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-binary.c
new file mode 100644
index 0000000..01b375e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-binary.c
@@ -0,0 +1,249 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+#include "sieve-error.h"
+#include "sieve-script.h"
+#include "sieve-binary.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-ihave-common.h"
+#include "ext-ihave-binary.h"
+
+/*
+ * Forward declarations
+ */
+
+static bool ext_ihave_binary_pre_save
+ (const struct sieve_extension *ext, struct sieve_binary *sbin,
+ void *context, enum sieve_error *error_r);
+static bool ext_ihave_binary_open
+ (const struct sieve_extension *ext, struct sieve_binary *sbin,
+ void *context);
+static bool ext_ihave_binary_up_to_date
+ (const struct sieve_extension *ext, struct sieve_binary *sbin,
+ void *context, enum sieve_compile_flags cpflags);
+
+/*
+ * Binary include extension
+ */
+
+const struct sieve_binary_extension ihave_binary_ext = {
+ .extension = &ihave_extension,
+ .binary_pre_save = ext_ihave_binary_pre_save,
+ .binary_open = ext_ihave_binary_open,
+ .binary_up_to_date = ext_ihave_binary_up_to_date
+};
+
+/*
+ * Binary context management
+ */
+
+struct ext_ihave_binary_context {
+ struct sieve_binary *binary;
+ struct sieve_binary_block *block;
+
+ ARRAY(const char *) missing_extensions;
+};
+
+static struct ext_ihave_binary_context *ext_ihave_binary_create_context
+(const struct sieve_extension *this_ext, struct sieve_binary *sbin)
+{
+ pool_t pool = sieve_binary_pool(sbin);
+
+ struct ext_ihave_binary_context *ctx =
+ p_new(pool, struct ext_ihave_binary_context, 1);
+
+ ctx->binary = sbin;
+ p_array_init(&ctx->missing_extensions, pool, 64);
+
+ sieve_binary_extension_set(sbin, this_ext, &ihave_binary_ext, ctx);
+ return ctx;
+}
+
+struct ext_ihave_binary_context *ext_ihave_binary_get_context
+(const struct sieve_extension *this_ext, struct sieve_binary *sbin)
+{
+ struct ext_ihave_binary_context *ctx = (struct ext_ihave_binary_context *)
+ sieve_binary_extension_get_context(sbin, this_ext);
+
+ if ( ctx == NULL )
+ ctx = ext_ihave_binary_create_context(this_ext, sbin);
+
+ return ctx;
+}
+
+struct ext_ihave_binary_context *ext_ihave_binary_init
+(const struct sieve_extension *this_ext, struct sieve_binary *sbin,
+ struct sieve_ast *ast)
+{
+ struct ext_ihave_ast_context *ast_ctx =
+ ext_ihave_get_ast_context(this_ext, ast);
+ struct ext_ihave_binary_context *binctx;
+ const char *const *exts;
+ unsigned int i, count;
+
+ binctx = ext_ihave_binary_get_context(this_ext, sbin);
+
+ exts = array_get(&ast_ctx->missing_extensions, &count);
+
+ if ( count > 0 ) {
+ pool_t pool = sieve_binary_pool(sbin);
+
+ if ( binctx->block == NULL )
+ binctx->block = sieve_binary_extension_create_block(sbin, this_ext);
+
+ for ( i = 0; i < count; i++ ) {
+ const char *ext_name = p_strdup(pool, exts[i]);
+
+ array_append(&binctx->missing_extensions, &ext_name, 1);
+ }
+ }
+
+ return binctx;
+}
+
+/*
+ * Binary extension
+ */
+
+static bool ext_ihave_binary_pre_save
+(const struct sieve_extension *ext, struct sieve_binary *sbin,
+ void *context, enum sieve_error *error_r ATTR_UNUSED)
+{
+ struct ext_ihave_binary_context *binctx =
+ (struct ext_ihave_binary_context *) context;
+ const char *const *exts;
+ unsigned int count, i;
+
+ exts = array_get(&binctx->missing_extensions, &count);
+
+ if ( binctx->block != NULL )
+ sieve_binary_block_clear(binctx->block);
+
+ if ( count > 0 ) {
+ if ( binctx->block == NULL )
+ binctx->block = sieve_binary_extension_create_block(sbin, ext);
+
+ sieve_binary_emit_unsigned(binctx->block, count);
+
+ for ( i = 0; i < count; i++ ) {
+ sieve_binary_emit_cstring(binctx->block, exts[i]);
+ }
+ }
+
+ return TRUE;
+}
+
+static bool ext_ihave_binary_open
+(const struct sieve_extension *ext, struct sieve_binary *sbin, void *context)
+{
+ struct sieve_instance *svinst = ext->svinst;
+ struct ext_ihave_binary_context *binctx =
+ (struct ext_ihave_binary_context *) context;
+ struct sieve_binary_block *sblock;
+ unsigned int i, count, block_id;
+ sieve_size_t offset;
+
+ sblock = sieve_binary_extension_get_block(sbin, ext);
+
+ if ( sblock != NULL ) {
+ binctx->block = sblock;
+ block_id = sieve_binary_block_get_id(sblock);
+
+ offset = 0;
+
+ /* Read number of missing extensions to read subsequently */
+ if ( !sieve_binary_read_unsigned(sblock, &offset, &count) ) {
+ e_error(svinst->event, "ihave: "
+ "failed to read missing extension count "
+ "from block %d of binary %s",
+ block_id, sieve_binary_path(sbin));
+ return FALSE;
+ }
+
+ /* Read dependencies */
+ for ( i = 0; i < count; i++ ) {
+ string_t *ext_name;
+ const char *name;
+
+ if ( !sieve_binary_read_string(sblock, &offset, &ext_name) ) {
+ /* Binary is corrupt, recompile */
+ e_error(svinst->event, "ihave: "
+ "failed to read missing extension name "
+ "from block %d of binary %s",
+ block_id, sieve_binary_path(sbin));
+ return FALSE;
+ }
+
+ name = str_c(ext_name);
+ array_append(&binctx->missing_extensions, &name, 1);
+ }
+ }
+
+ return TRUE;
+}
+
+static bool ext_ihave_binary_up_to_date
+(const struct sieve_extension *ext, struct sieve_binary *sbin ATTR_UNUSED,
+ void *context, enum sieve_compile_flags cpflags)
+{
+ struct ext_ihave_binary_context *binctx =
+ (struct ext_ihave_binary_context *) context;
+ const struct sieve_extension *mext;
+ const char *const *mexts;
+ unsigned int count, i;
+
+ mexts = array_get(&binctx->missing_extensions, &count);
+ for ( i = 0; i < count; i++ ) {
+ if ( (mext=sieve_extension_get_by_name(ext->svinst, mexts[i])) != NULL &&
+ ((cpflags & SIEVE_COMPILE_FLAG_NOGLOBAL) == 0 || !mext->global) )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Main extension interface
+ */
+
+bool ext_ihave_binary_load
+(const struct sieve_extension *ext, struct sieve_binary *sbin)
+{
+ (void)ext_ihave_binary_get_context(ext, sbin);
+
+ return TRUE;
+}
+
+bool ext_ihave_binary_dump
+(const struct sieve_extension *ext, struct sieve_dumptime_env *denv)
+{
+ struct sieve_binary *sbin = denv->sbin;
+ struct ext_ihave_binary_context *binctx =
+ ext_ihave_binary_get_context(ext, sbin);
+ const char *const *exts;
+ unsigned int count, i;
+
+ exts = array_get(&binctx->missing_extensions, &count);
+
+ if ( count > 0 ) {
+ sieve_binary_dump_sectionf(denv,
+ "Extensions missing at compile (block: %d)",
+ sieve_binary_block_get_id(binctx->block));
+
+ for ( i = 0; i < count; i++ ) {
+ sieve_binary_dumpf(denv, " - %s\n", exts[i]);
+ }
+ }
+
+ return TRUE;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-binary.h b/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-binary.h
new file mode 100644
index 0000000..418f078
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-binary.h
@@ -0,0 +1,33 @@
+#ifndef EXT_IHAVE_BINARY_H
+#define EXT_IHAVE_BINARY_H
+
+/*
+ * Binary context management
+ */
+
+struct ext_ihave_binary_context;
+
+struct ext_ihave_binary_context *ext_ihave_binary_get_context
+ (const struct sieve_extension *this_ext, struct sieve_binary *sbin);
+struct ext_ihave_binary_context *ext_ihave_binary_init
+ (const struct sieve_extension *this_ext, struct sieve_binary *sbin,
+ struct sieve_ast *ast);
+
+/*
+ * Registering missing extension
+ */
+
+void ext_ihave_binary_add_missing_extension
+ (struct ext_ihave_binary_context *binctx, const char *ext_name);
+
+/*
+ * Main extension interface
+ */
+
+bool ext_ihave_binary_load
+ (const struct sieve_extension *ext, struct sieve_binary *sbin);
+bool ext_ihave_binary_dump
+ (const struct sieve_extension *ext, struct sieve_dumptime_env *denv);
+
+#endif
+
diff --git a/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-common.c b/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-common.c
new file mode 100644
index 0000000..1d31238
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-common.c
@@ -0,0 +1,52 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-ast.h"
+
+#include "ext-ihave-common.h"
+
+/*
+ * AST context management
+ */
+
+struct ext_ihave_ast_context *ext_ihave_get_ast_context
+(const struct sieve_extension *this_ext, struct sieve_ast *ast)
+{
+ struct ext_ihave_ast_context *actx = (struct ext_ihave_ast_context *)
+ sieve_ast_extension_get_context(ast, this_ext);
+ pool_t pool;
+
+ if ( actx != NULL )
+ return actx;
+
+ pool = sieve_ast_pool(ast);
+ actx = p_new(pool, struct ext_ihave_ast_context, 1);
+ p_array_init(&actx->missing_extensions, pool, 64);
+
+ sieve_ast_extension_set_context(ast, this_ext, (void *) actx);
+
+ return actx;
+}
+
+void ext_ihave_ast_add_missing_extension
+(const struct sieve_extension *this_ext, struct sieve_ast *ast,
+ const char *ext_name)
+{
+ struct ext_ihave_ast_context *actx =
+ ext_ihave_get_ast_context(this_ext, ast);
+ const char *const *exts;
+ unsigned int i, count;
+
+ exts = array_get(&actx->missing_extensions, &count);
+ for ( i = 0; i < count; i++ ) {
+ if ( strcmp(exts[i], ext_name) == 0 )
+ return;
+ }
+
+ array_append(&actx->missing_extensions, &ext_name, 1);
+}
+
diff --git a/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-common.h b/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-common.h
new file mode 100644
index 0000000..371d03d
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-common.h
@@ -0,0 +1,52 @@
+#ifndef EXT_IHAVE_COMMON_H
+#define EXT_IHAVE_COMMON_H
+
+#include "sieve-common.h"
+
+/*
+ * Extensions
+ */
+
+extern const struct sieve_extension_def ihave_extension;
+
+/*
+ * Tests
+ */
+
+extern const struct sieve_command_def ihave_test;
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def error_command;
+
+/*
+ * Operations
+ */
+
+enum ext_ihave_opcode {
+ EXT_IHAVE_OPERATION_IHAVE,
+ EXT_IHAVE_OPERATION_ERROR
+};
+
+extern const struct sieve_operation_def tst_ihave_operation;
+extern const struct sieve_operation_def cmd_error_operation;
+
+/*
+ * AST context
+ */
+
+struct ext_ihave_ast_context {
+ ARRAY(const char *) missing_extensions;
+};
+
+struct ext_ihave_ast_context *ext_ihave_get_ast_context
+ (const struct sieve_extension *this_ext, struct sieve_ast *ast);
+
+void ext_ihave_ast_add_missing_extension
+ (const struct sieve_extension *this_ext, struct sieve_ast *ast,
+ const char *ext_name);
+
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave.c b/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave.c
new file mode 100644
index 0000000..40b70eb
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave.c
@@ -0,0 +1,70 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension ihave
+ * ---------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5463
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+
+#include "ext-ihave-common.h"
+#include "ext-ihave-binary.h"
+
+/*
+ * Operations
+ */
+
+const struct sieve_operation_def *ext_ihave_operations[] = {
+ &tst_ihave_operation,
+ &cmd_error_operation
+};
+
+/*
+ * Extension
+ */
+
+static bool ext_ihave_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *validator);
+static bool ext_ihave_generator_load
+ (const struct sieve_extension *ext, const struct sieve_codegen_env *cgenv);
+
+const struct sieve_extension_def ihave_extension = {
+ "ihave",
+ .version = 1,
+ .validator_load = ext_ihave_validator_load,
+ .generator_load = ext_ihave_generator_load,
+ .binary_load = ext_ihave_binary_load,
+ .binary_dump = ext_ihave_binary_dump,
+ SIEVE_EXT_DEFINE_OPERATIONS(ext_ihave_operations)
+};
+
+static bool ext_ihave_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *validator)
+{
+ sieve_validator_register_command(validator, ext, &ihave_test);
+ sieve_validator_register_command(validator, ext, &error_command);
+
+ return TRUE;
+}
+
+static bool ext_ihave_generator_load
+(const struct sieve_extension *ext, const struct sieve_codegen_env *cgenv)
+{
+ (void)ext_ihave_binary_init(ext, cgenv->sbin, cgenv->ast);
+
+ return TRUE;
+}
+
diff --git a/pigeonhole/src/lib-sieve/plugins/ihave/tst-ihave.c b/pigeonhole/src/lib-sieve/plugins/ihave/tst-ihave.c
new file mode 100644
index 0000000..c6c8e8f
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/ihave/tst-ihave.c
@@ -0,0 +1,294 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+#include "sieve-extensions.h"
+#include "sieve-code.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+#include "ext-ihave-common.h"
+
+/*
+ * Ihave test
+ *
+ * Syntax:
+ * ihave <capabilities: string-list>
+ */
+
+static bool
+tst_ihave_validate(struct sieve_validator *valdtr, struct sieve_command *tst);
+static bool
+tst_ihave_validate_const(struct sieve_validator *valdtr,
+ struct sieve_command *tst, int *const_current,
+ int const_next);
+static bool
+tst_ihave_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *tst);
+
+const struct sieve_command_def ihave_test = {
+ .identifier = "ihave",
+ .type = SCT_TEST,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = tst_ihave_validate,
+ .validate_const = tst_ihave_validate_const,
+ .generate = tst_ihave_generate
+};
+
+/*
+ * Ihave operation
+ */
+
+static bool
+tst_ihave_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+tst_ihave_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def tst_ihave_operation = {
+ .mnemonic = "IHAVE",
+ .ext_def = &ihave_extension,
+ .code = EXT_IHAVE_OPERATION_IHAVE,
+ .dump = tst_ihave_operation_dump,
+ .execute = tst_ihave_operation_execute
+};
+
+/*
+ * Code validation
+ */
+
+static bool
+tst_ihave_validate(struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct _capability {
+ const struct sieve_extension *ext;
+ struct sieve_ast_argument *arg;
+ };
+ struct sieve_ast_argument *arg = tst->first_positional;
+ struct sieve_ast_argument *stritem;
+ enum sieve_compile_flags cpflags =
+ sieve_validator_compile_flags(valdtr);
+ bool no_global = ((cpflags & SIEVE_COMPILE_FLAG_NOGLOBAL) != 0);
+ ARRAY(struct _capability) capabilities;
+ struct _capability capability;
+ const struct _capability *caps;
+ unsigned int i, count;
+ bool all_known = TRUE;
+
+ t_array_init(&capabilities, 64);
+
+ tst->data = (void *)FALSE;
+
+ /* Check stringlist argument */
+ if (!sieve_validate_positional_argument(valdtr, tst, arg,
+ "capabilities", 1,
+ SAAT_STRING_LIST))
+ return FALSE;
+
+ switch (sieve_ast_argument_type(arg)) {
+ case SAAT_STRING:
+ /* Single string */
+ capability.arg = arg;
+ capability.ext = sieve_extension_get_by_name(
+ tst->ext->svinst, sieve_ast_argument_strc(arg));
+
+ if (capability.ext == NULL ||
+ (no_global && capability.ext->global)) {
+ all_known = FALSE;
+
+ ext_ihave_ast_add_missing_extension(
+ tst->ext, tst->ast_node->ast,
+ sieve_ast_argument_strc(arg));
+ } else {
+ array_append(&capabilities, &capability, 1);
+ }
+
+ break;
+
+ case SAAT_STRING_LIST:
+ /* String list */
+ stritem = sieve_ast_strlist_first(arg);
+
+ while (stritem != NULL) {
+ capability.arg = stritem;
+ capability.ext = sieve_extension_get_by_name(
+ tst->ext->svinst,
+ sieve_ast_argument_strc(stritem));
+
+ if (capability.ext == NULL ||
+ (no_global && capability.ext->global)) {
+ all_known = FALSE;
+
+ ext_ihave_ast_add_missing_extension(
+ tst->ext, tst->ast_node->ast,
+ sieve_ast_argument_strc(stritem));
+ } else {
+ array_append(&capabilities, &capability, 1);
+ }
+ stritem = sieve_ast_strlist_next(stritem);
+ }
+
+ break;
+ default:
+ i_unreached();
+ }
+
+ if (!all_known)
+ return TRUE;
+
+ /* RFC 5463, Section 4, page 4:
+
+ The "ihave" extension is designed to be used with other extensions
+ that add tests, actions, comparators, or arguments. Implementations
+ MUST NOT allow it to be used with extensions that change the
+ underlying Sieve grammar, or extensions like encoded-character
+ [RFC5228], or variables [RFC5229] that change how the content of
+ Sieve scripts are interpreted. The test MUST fail and the extension
+ MUST NOT be enabled if such usage is attempted.
+
+ FIXME: current implementation of this restriction is hardcoded and
+ therefore highly inflexible
+ */
+ caps = array_get(&capabilities, &count);
+ for (i = 0; i < count; i++) {
+ if (sieve_extension_name_is(caps[i].ext, "variables") ||
+ sieve_extension_name_is(caps[i].ext, "encoded-character"))
+ return TRUE;
+ }
+
+ /* Load all extensions */
+ caps = array_get(&capabilities, &count);
+ for (i = 0; i < count; i++) {
+ if (!sieve_validator_extension_load(valdtr, tst, caps[i].arg,
+ caps[i].ext, FALSE))
+ return FALSE;
+ }
+
+ if (!sieve_validator_argument_activate(valdtr, tst, arg, FALSE))
+ return FALSE;
+
+ tst->data = (void *)TRUE;
+ return TRUE;
+}
+
+static bool
+tst_ihave_validate_const(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_command *tst, int *const_current,
+ int const_next ATTR_UNUSED)
+{
+ if ((bool)tst->data == TRUE)
+ *const_current = -1;
+ else
+ *const_current = 0;
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+bool tst_ihave_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *tst)
+{
+ /* Emit opcode */
+ sieve_operation_emit(cgenv->sblock, tst->ext, &tst_ihave_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, tst, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+tst_ihave_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "IHAVE");
+ sieve_code_descend(denv);
+
+ return sieve_opr_stringlist_dump(denv, address, "capabilities");
+}
+
+/*
+ * Code execution
+ */
+
+static int
+tst_ihave_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ struct sieve_instance *svinst = eenv->svinst;
+ struct sieve_stringlist *capabilities;
+ string_t *cap_item;
+ bool matched;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Read capabilities */
+ if ((ret = sieve_opr_stringlist_read(renv, address, "capabilities",
+ &capabilities)) <= 0)
+ return ret;
+
+ /*
+ * Perform test
+ */
+
+ /* Perform the test */
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "ihave test");
+ sieve_runtime_trace_descend(renv);
+
+ cap_item = NULL;
+ matched = TRUE;
+ while (matched &&
+ (ret = sieve_stringlist_next_item(capabilities,
+ &cap_item)) > 0) {
+ const struct sieve_extension *ext;
+ int sret;
+
+ ext = sieve_extension_get_by_name(svinst, str_c(cap_item));
+ if (ext == NULL) {
+ sieve_runtime_trace_error(
+ renv, "ihave: invalid extension name");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ sret = sieve_interpreter_extension_start(renv->interp, ext);
+ if (sret == SIEVE_EXEC_FAILURE) {
+ sieve_runtime_trace(
+ renv, SIEVE_TRLVL_TESTS,
+ "extension `%s' not available",
+ sieve_extension_name(ext));
+ matched = FALSE;
+ } else if (sret == SIEVE_EXEC_OK) {
+ sieve_runtime_trace(
+ renv, SIEVE_TRLVL_TESTS,
+ "extension `%s' available",
+ sieve_extension_name(ext));
+ } else {
+ return sret;
+ }
+ }
+ if (ret < 0) {
+ sieve_runtime_trace_error(renv, "invalid capabilities item");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ /* Set test result for subsequent conditional jump */
+ sieve_interpreter_set_test_result(renv->interp, matched);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/Makefile.am b/pigeonhole/src/lib-sieve/plugins/imap4flags/Makefile.am
new file mode 100644
index 0000000..e5390d4
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/Makefile.am
@@ -0,0 +1,33 @@
+noinst_LTLIBRARIES = libsieve_ext_imap4flags.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../variables \
+ $(LIBDOVECOT_INCLUDE)
+
+commands = \
+ cmd-flag.c
+
+tests = \
+ tst-hasflag.c
+
+tags = \
+ tag-flags.c
+
+libsieve_ext_imap4flags_la_SOURCES = \
+ ext-imap4flags-common.c \
+ $(commands) \
+ $(tests) \
+ $(tags) \
+ ext-imap4flags.c \
+ ext-imapflags.c
+
+public_headers = \
+ sieve-ext-imap4flags.h
+
+headers = \
+ ext-imap4flags-common.h
+
+pkginc_libdir=$(dovecot_pkgincludedir)/sieve
+pkginc_lib_HEADERS = $(public_headers)
+noinst_HEADERS = $(headers)
diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/Makefile.in b/pigeonhole/src/lib-sieve/plugins/imap4flags/Makefile.in
new file mode 100644
index 0000000..77f2dc3
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/Makefile.in
@@ -0,0 +1,776 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/imap4flags
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(pkginc_lib_HEADERS) $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_imap4flags_la_LIBADD =
+am__objects_1 = cmd-flag.lo
+am__objects_2 = tst-hasflag.lo
+am__objects_3 = tag-flags.lo
+am_libsieve_ext_imap4flags_la_OBJECTS = ext-imap4flags-common.lo \
+ $(am__objects_1) $(am__objects_2) $(am__objects_3) \
+ ext-imap4flags.lo ext-imapflags.lo
+libsieve_ext_imap4flags_la_OBJECTS = \
+ $(am_libsieve_ext_imap4flags_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cmd-flag.Plo \
+ ./$(DEPDIR)/ext-imap4flags-common.Plo \
+ ./$(DEPDIR)/ext-imap4flags.Plo ./$(DEPDIR)/ext-imapflags.Plo \
+ ./$(DEPDIR)/tag-flags.Plo ./$(DEPDIR)/tst-hasflag.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_imap4flags_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_imap4flags_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkginc_libdir)"
+HEADERS = $(noinst_HEADERS) $(pkginc_lib_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_imap4flags.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../variables \
+ $(LIBDOVECOT_INCLUDE)
+
+commands = \
+ cmd-flag.c
+
+tests = \
+ tst-hasflag.c
+
+tags = \
+ tag-flags.c
+
+libsieve_ext_imap4flags_la_SOURCES = \
+ ext-imap4flags-common.c \
+ $(commands) \
+ $(tests) \
+ $(tags) \
+ ext-imap4flags.c \
+ ext-imapflags.c
+
+public_headers = \
+ sieve-ext-imap4flags.h
+
+headers = \
+ ext-imap4flags-common.h
+
+pkginc_libdir = $(dovecot_pkgincludedir)/sieve
+pkginc_lib_HEADERS = $(public_headers)
+noinst_HEADERS = $(headers)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/imap4flags/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/imap4flags/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_imap4flags.la: $(libsieve_ext_imap4flags_la_OBJECTS) $(libsieve_ext_imap4flags_la_DEPENDENCIES) $(EXTRA_libsieve_ext_imap4flags_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_imap4flags_la_OBJECTS) $(libsieve_ext_imap4flags_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-flag.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-imap4flags-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-imap4flags.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-imapflags.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tag-flags.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-hasflag.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
+ done
+
+uninstall-pkginc_libHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(pkginc_libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/cmd-flag.Plo
+ -rm -f ./$(DEPDIR)/ext-imap4flags-common.Plo
+ -rm -f ./$(DEPDIR)/ext-imap4flags.Plo
+ -rm -f ./$(DEPDIR)/ext-imapflags.Plo
+ -rm -f ./$(DEPDIR)/tag-flags.Plo
+ -rm -f ./$(DEPDIR)/tst-hasflag.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkginc_libHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/cmd-flag.Plo
+ -rm -f ./$(DEPDIR)/ext-imap4flags-common.Plo
+ -rm -f ./$(DEPDIR)/ext-imap4flags.Plo
+ -rm -f ./$(DEPDIR)/ext-imapflags.Plo
+ -rm -f ./$(DEPDIR)/tag-flags.Plo
+ -rm -f ./$(DEPDIR)/tst-hasflag.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkginc_libHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-pkginc_libHEADERS install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-pkginc_libHEADERS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/cmd-flag.c b/pigeonhole/src/lib-sieve/plugins/imap4flags/cmd-flag.c
new file mode 100644
index 0000000..2645669
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/cmd-flag.c
@@ -0,0 +1,251 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-code.h"
+#include "sieve-stringlist.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-imap4flags-common.h"
+
+/*
+ * Commands
+ */
+
+/* Forward declarations */
+
+static bool cmd_flag_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+/* Setflag command
+ *
+ * Syntax:
+ * setflag [<variablename: string>] <list-of-flags: string-list>
+ */
+
+const struct sieve_command_def cmd_setflag = {
+ .identifier = "setflag",
+ .type = SCT_COMMAND,
+ .positional_args = -1, /* We check positional arguments ourselves */
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = ext_imap4flags_command_validate,
+ .generate = cmd_flag_generate
+};
+
+/* Addflag command
+ *
+ * Syntax:
+ * addflag [<variablename: string>] <list-of-flags: string-list>
+ */
+
+const struct sieve_command_def cmd_addflag = {
+ .identifier = "addflag",
+ .type = SCT_COMMAND,
+ .positional_args = -1, /* We check positional arguments ourselves */
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = ext_imap4flags_command_validate,
+ .generate = cmd_flag_generate
+};
+
+
+/* Removeflag command
+ *
+ * Syntax:
+ * removeflag [<variablename: string>] <list-of-flags: string-list>
+ */
+
+const struct sieve_command_def cmd_removeflag = {
+ .identifier = "removeflag",
+ .type = SCT_COMMAND,
+ .positional_args = -1, /* We check positional arguments ourselves */
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = ext_imap4flags_command_validate,
+ .generate = cmd_flag_generate
+};
+
+/*
+ * Operations
+ */
+
+/* Forward declarations */
+
+bool cmd_flag_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int cmd_flag_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+/* Setflag operation */
+
+const struct sieve_operation_def setflag_operation = {
+ .mnemonic = "SETFLAG",
+ .ext_def = &imap4flags_extension,
+ .code = EXT_IMAP4FLAGS_OPERATION_SETFLAG,
+ .dump = cmd_flag_operation_dump,
+ .execute = cmd_flag_operation_execute
+};
+
+/* Addflag operation */
+
+const struct sieve_operation_def addflag_operation = {
+ .mnemonic = "ADDFLAG",
+ .ext_def = &imap4flags_extension,
+ .code = EXT_IMAP4FLAGS_OPERATION_ADDFLAG,
+ .dump = cmd_flag_operation_dump,
+ .execute = cmd_flag_operation_execute
+};
+
+/* Removeflag operation */
+
+const struct sieve_operation_def removeflag_operation = {
+ .mnemonic = "REMOVEFLAG",
+ .ext_def = &imap4flags_extension,
+ .code = EXT_IMAP4FLAGS_OPERATION_REMOVEFLAG,
+ .dump = cmd_flag_operation_dump,
+ .execute = cmd_flag_operation_execute
+};
+
+/*
+ * Code generation
+ */
+
+static bool cmd_flag_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg1, *arg2;
+
+ /* Emit operation */
+ if ( sieve_command_is(cmd, cmd_setflag) )
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &setflag_operation);
+ else if ( sieve_command_is(cmd, cmd_addflag) )
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &addflag_operation);
+ else if ( sieve_command_is(cmd, cmd_removeflag) )
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &removeflag_operation);
+
+ arg1 = cmd->first_positional;
+ arg2 = sieve_ast_argument_next(arg1);
+
+ if ( arg2 == NULL ) {
+ /* No variable */
+ sieve_opr_omitted_emit(cgenv->sblock);
+ if ( !sieve_generate_argument(cgenv, arg1, cmd) )
+ return FALSE;
+ } else {
+ /* Full command */
+ if ( !sieve_generate_argument(cgenv, arg1, cmd) )
+ return FALSE;
+ if ( !sieve_generate_argument(cgenv, arg2, cmd) )
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+bool cmd_flag_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ struct sieve_operand oprnd;
+
+ sieve_code_dumpf(denv, "%s", sieve_operation_mnemonic(denv->oprtn));
+ sieve_code_descend(denv);
+
+ sieve_code_mark(denv);
+ if ( !sieve_operand_read(denv->sblock, address, NULL, &oprnd) ) {
+ sieve_code_dumpf(denv, "ERROR: INVALID OPERAND");
+ return FALSE;
+ }
+
+ if ( !sieve_operand_is_omitted(&oprnd) ) {
+ return
+ sieve_opr_string_dump_data(denv, &oprnd, address, "variable name") &&
+ sieve_opr_stringlist_dump(denv, address, "list of flags");
+ }
+
+ return
+ sieve_opr_stringlist_dump(denv, address, "list of flags");
+}
+
+/*
+ * Code execution
+ */
+
+static int cmd_flag_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ const struct sieve_operation *op = renv->oprtn;
+ struct sieve_operand oprnd;
+ struct sieve_stringlist *flag_list;
+ struct sieve_variable_storage *storage;
+ unsigned int var_index;
+ ext_imapflag_flag_operation_t flag_op;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Read bare operand (two types possible) */
+ if ( (ret=sieve_operand_runtime_read
+ (renv, address, NULL, &oprnd)) <= 0 )
+ return ret;
+
+ /* Variable operand (optional) */
+ if ( !sieve_operand_is_omitted(&oprnd) ) {
+ /* Read the variable operand */
+ if ( (ret=sieve_variable_operand_read_data
+ (renv, &oprnd, address, "variable", &storage, &var_index)) <= 0 )
+ return ret;
+
+ /* Read flag list */
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "flag-list", &flag_list))
+ <= 0 )
+ return ret;
+
+ /* Flag-list operand */
+ } else {
+ storage = NULL;
+ var_index = 0;
+
+ /* Read flag list */
+ if ( (ret=sieve_opr_stringlist_read(renv, address,
+ "flag-list", &flag_list)) <= 0 )
+ return ret;
+ }
+
+ /*
+ * Perform operation
+ */
+
+ /* Determine what to do */
+
+ if ( sieve_operation_is(op, setflag_operation) ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "setflag command");
+ flag_op = sieve_ext_imap4flags_set_flags;
+ } else if ( sieve_operation_is(op, addflag_operation) ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "addflag command");
+ flag_op = sieve_ext_imap4flags_add_flags;
+ } else if ( sieve_operation_is(op, removeflag_operation) ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "removeflag command");
+ flag_op = sieve_ext_imap4flags_remove_flags;
+ } else {
+ i_unreached();
+ }
+
+ sieve_runtime_trace_descend(renv);
+
+ /* Perform requested operation */
+ return flag_op(renv, op->ext, storage, var_index, flag_list);
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c b/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
new file mode 100644
index 0000000..3c364b8
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
@@ -0,0 +1,733 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "mail-storage.h"
+#include "imap-arg.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-stringlist.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-result.h"
+#include "sieve-dump.h"
+
+#include "sieve-ext-variables.h"
+
+#include "ext-imap4flags-common.h"
+
+/*
+ * Tagged arguments
+ */
+
+extern const struct sieve_argument_def tag_flags;
+extern const struct sieve_argument_def tag_flags_implicit;
+
+/*
+ * Common command functions
+ */
+
+bool ext_imap4flags_command_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+ struct sieve_ast_argument *arg2;
+ const struct sieve_extension *var_ext;
+
+ /* Check arguments */
+
+ if ( arg == NULL ) {
+ sieve_command_validate_error(valdtr, cmd,
+ "the %s %s expects at least one argument, but none was found",
+ sieve_command_identifier(cmd), sieve_command_type_name(cmd));
+ return FALSE;
+ }
+
+ if ( sieve_ast_argument_type(arg) != SAAT_STRING &&
+ sieve_ast_argument_type(arg) != SAAT_STRING_LIST )
+ {
+ sieve_argument_validate_error(valdtr, arg,
+ "the %s %s expects either a string (variable name) or "
+ "a string-list (list of flags) as first argument, but %s was found",
+ sieve_command_identifier(cmd), sieve_command_type_name(cmd),
+ sieve_ast_argument_name(arg));
+ return FALSE;
+ }
+
+ arg2 = sieve_ast_argument_next(arg);
+ if ( arg2 != NULL ) {
+ /* First, check syntax sanity */
+
+ if ( sieve_ast_argument_type(arg) != SAAT_STRING )
+ {
+ if ( sieve_command_is(cmd, tst_hasflag) ) {
+ if ( sieve_ast_argument_type(arg) != SAAT_STRING_LIST ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "if a second argument is specified for the hasflag, the first "
+ "must be a string-list (variable-list), but %s was found",
+ sieve_ast_argument_name(arg));
+ return FALSE;
+ }
+ } else {
+ sieve_argument_validate_error(valdtr, arg,
+ "if a second argument is specified for the %s %s, the first "
+ "must be a string (variable name), but %s was found",
+ sieve_command_identifier(cmd), sieve_command_type_name(cmd),
+ sieve_ast_argument_name(arg));
+ return FALSE;
+ }
+ }
+
+ /* Then, check whether the second argument is permitted */
+
+ var_ext = sieve_ext_variables_get_extension(cmd->ext->svinst);
+
+ if ( var_ext == NULL || !sieve_ext_variables_is_active(var_ext, valdtr) )
+ {
+ sieve_argument_validate_error(valdtr,arg,
+ "the %s %s only allows for the specification of a "
+ "variable name when the variables extension is active",
+ sieve_command_identifier(cmd), sieve_command_type_name(cmd));
+ return FALSE;
+ }
+
+ if ( !sieve_variable_argument_activate(var_ext, var_ext,
+ valdtr, cmd, arg, !sieve_command_is(cmd, tst_hasflag) ) )
+ return FALSE;
+
+ if ( sieve_ast_argument_type(arg2) != SAAT_STRING &&
+ sieve_ast_argument_type(arg2) != SAAT_STRING_LIST )
+ {
+ sieve_argument_validate_error(valdtr, arg2,
+ "the %s %s expects a string list (list of flags) as "
+ "second argument when two arguments are specified, "
+ "but %s was found",
+ sieve_command_identifier(cmd), sieve_command_type_name(cmd),
+ sieve_ast_argument_name(arg2));
+ return FALSE;
+ }
+ } else
+ arg2 = arg;
+
+ if ( !sieve_validator_argument_activate(valdtr, cmd, arg2, FALSE) )
+ return FALSE;
+
+ if ( !sieve_command_is(cmd, tst_hasflag) &&
+ sieve_argument_is_string_literal(arg2) ) {
+ struct ext_imap4flags_iter fiter;
+ const char *flag;
+
+ /* Warn the user about validity of verifiable flags */
+ ext_imap4flags_iter_init(&fiter, sieve_ast_argument_str(arg));
+
+ while ( (flag=ext_imap4flags_iter_get_flag(&fiter)) != NULL ) {
+ if ( !sieve_ext_imap4flags_flag_is_valid(flag) ) {
+ sieve_argument_validate_warning(valdtr, arg,
+ "IMAP flag '%s' specified for the %s command is invalid "
+ "and will be ignored (only first invalid is reported)",
+ str_sanitize(flag, 64), sieve_command_identifier(cmd));
+ break;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+/*
+ * Flags tag registration
+ */
+
+void ext_imap4flags_attach_flags_tag
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ const char *command)
+{
+ /* Register :flags tag with the command and we don't care whether it is
+ * registered or even whether it will be registered at all. The validator
+ * handles either situation gracefully
+ */
+
+ /* Tag specified by user */
+ sieve_validator_register_external_tag
+ (valdtr, command, ext, &tag_flags, SIEVE_OPT_SIDE_EFFECT);
+}
+
+void sieve_ext_imap4flags_register_side_effect
+(struct sieve_validator *valdtr, const struct sieve_extension *flg_ext,
+ const char *command)
+{
+ /* Implicit tag if none is specified */
+ sieve_validator_register_persistent_tag
+ (valdtr, command, flg_ext, &tag_flags_implicit);
+}
+
+
+/*
+ * Result context
+ */
+
+struct ext_imap4flags_result_context {
+ string_t *internal_flags;
+};
+
+static void _get_initial_flags
+(struct sieve_result *result, string_t *flags)
+{
+ const struct sieve_message_data *msgdata =
+ sieve_result_get_message_data(result);
+ enum mail_flags mail_flags;
+ const char *const *mail_keywords;
+
+ mail_flags = mail_get_flags(msgdata->mail);
+ mail_keywords = mail_get_keywords(msgdata->mail);
+
+ if ( (mail_flags & MAIL_FLAGGED) > 0 )
+ str_printfa(flags, " \\flagged");
+
+ if ( (mail_flags & MAIL_ANSWERED) > 0 )
+ str_printfa(flags, " \\answered");
+
+ if ( (mail_flags & MAIL_DELETED) > 0 )
+ str_printfa(flags, " \\deleted");
+
+ if ( (mail_flags & MAIL_SEEN) > 0 )
+ str_printfa(flags, " \\seen");
+
+ if ( (mail_flags & MAIL_DRAFT) > 0 )
+ str_printfa(flags, " \\draft");
+
+ while ( *mail_keywords != NULL ) {
+ str_printfa(flags, " %s", *mail_keywords);
+ mail_keywords++;
+ }
+}
+
+static inline struct ext_imap4flags_result_context *_get_result_context
+(const struct sieve_extension *this_ext, struct sieve_result *result)
+{
+ struct ext_imap4flags_result_context *rctx =
+ (struct ext_imap4flags_result_context *)
+ sieve_result_extension_get_context(result, this_ext);
+
+ if ( rctx == NULL ) {
+ pool_t pool = sieve_result_pool(result);
+
+ rctx =p_new(pool, struct ext_imap4flags_result_context, 1);
+ rctx->internal_flags = str_new(pool, 32);
+ _get_initial_flags(result, rctx->internal_flags);
+
+ sieve_result_extension_set_context
+ (result, this_ext, rctx);
+ }
+
+ return rctx;
+}
+
+static string_t *_get_flags_string
+(const struct sieve_extension *this_ext, struct sieve_result *result)
+{
+ struct ext_imap4flags_result_context *ctx =
+ _get_result_context(this_ext, result);
+
+ return ctx->internal_flags;
+}
+
+/*
+ * Runtime initialization
+ */
+
+static int ext_imap4flags_runtime_init
+(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ void *context ATTR_UNUSED, bool deferred ATTR_UNUSED)
+{
+ sieve_result_add_implicit_side_effect
+ (renv->result, NULL, TRUE, ext, &flags_side_effect, NULL);
+ return SIEVE_EXEC_OK;
+}
+
+const struct sieve_interpreter_extension
+imap4flags_interpreter_extension = {
+ .ext_def = &imap4flags_extension,
+ .run = ext_imap4flags_runtime_init
+};
+
+/*
+ * Flag handling
+ */
+
+/* FIXME: This currently accepts a potentially unlimited number of
+ * flags, making the internal or variable flag list indefinitely long
+ */
+
+bool sieve_ext_imap4flags_flag_is_valid(const char *flag)
+{
+ if ( *flag == '\0' )
+ return FALSE;
+
+ if ( *flag == '\\' ) {
+ /* System flag */
+ const char *atom = t_str_ucase(flag);
+
+ if (
+ (strcmp(atom, "\\ANSWERED") != 0) &&
+ (strcmp(atom, "\\FLAGGED") != 0) &&
+ (strcmp(atom, "\\DELETED") != 0) &&
+ (strcmp(atom, "\\SEEN") != 0) &&
+ (strcmp(atom, "\\DRAFT") != 0) )
+ {
+ return FALSE;
+ }
+ } else {
+ const char *p;
+
+ /* Custom keyword:
+ *
+ * Syntax (IMAP4rev1, RFC 3501, Section 9. Formal Syntax) :
+ * flag-keyword = atom
+ * atom = 1*ATOM-CHAR
+ */
+ p = flag;
+ while ( *p != '\0' ) {
+ if ( !IS_ATOM_CHAR(*p) )
+ return FALSE;
+ p++;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Flag iterator */
+
+static void ext_imap4flags_iter_clear
+(struct ext_imap4flags_iter *iter)
+{
+ i_zero(iter);
+}
+
+void ext_imap4flags_iter_init
+(struct ext_imap4flags_iter *iter, string_t *flags_list)
+{
+ ext_imap4flags_iter_clear(iter);
+ iter->flags_list = flags_list;
+}
+
+static string_t *ext_imap4flags_iter_get_flag_str
+(struct ext_imap4flags_iter *iter)
+{
+ unsigned int len;
+ const unsigned char *fp;
+ const unsigned char *fbegin;
+ const unsigned char *fstart;
+ const unsigned char *fend;
+
+ /* Return if not initialized */
+ if ( iter->flags_list == NULL ) return NULL;
+
+ /* Return if no more flags are available */
+ len = str_len(iter->flags_list);
+ if ( iter->offset >= len ) return NULL;
+
+ /* Mark string boundries */
+ fbegin = str_data(iter->flags_list);
+ fend = fbegin + len;
+
+ /* Start of this flag */
+ fstart = fbegin + iter->offset;
+
+ /* Scan for next flag */
+ fp = fstart;
+ for (;;) {
+ /* Have we reached the end or a flag boundary? */
+ if ( fp >= fend || *fp == ' ' ) {
+ /* Did we scan more than nothing ? */
+ if ( fp > fstart ) {
+ /* Return flag */
+ string_t *flag = t_str_new(fp-fstart+1);
+ str_append_data(flag, fstart, fp-fstart);
+
+ iter->last = fstart - fbegin;
+ iter->offset = fp - fbegin;
+
+ return flag;
+ }
+
+ fstart = fp + 1;
+ }
+
+ if ( fp >= fend ) break;
+
+ fp++;
+ }
+
+ iter->last = fstart - fbegin;
+ iter->offset = fp - fbegin;
+ return NULL;
+}
+
+const char *ext_imap4flags_iter_get_flag
+(struct ext_imap4flags_iter *iter)
+{
+ string_t *flag = ext_imap4flags_iter_get_flag_str(iter);
+
+ if ( flag == NULL ) return NULL;
+
+ return str_c(flag);
+}
+
+static void ext_imap4flags_iter_delete_last
+(struct ext_imap4flags_iter *iter)
+{
+ iter->offset++;
+ if ( iter->offset > str_len(iter->flags_list) )
+ iter->offset = str_len(iter->flags_list);
+ if ( iter->offset == str_len(iter->flags_list) && iter->last > 0 )
+ iter->last--;
+
+ str_delete(iter->flags_list, iter->last, iter->offset - iter->last);
+
+ iter->offset = iter->last;
+}
+
+/* Flag operations */
+
+static string_t *ext_imap4flags_get_flag_variable
+(const struct sieve_runtime_env *renv,
+ const struct sieve_extension *flg_ext,
+ struct sieve_variable_storage *storage,
+ unsigned int var_index)
+ ATTR_NULL(2);
+
+static bool flags_list_flag_exists
+(string_t *flags_list, const char *flag)
+{
+ const char *flg;
+ struct ext_imap4flags_iter flit;
+
+ ext_imap4flags_iter_init(&flit, flags_list);
+
+ while ( (flg=ext_imap4flags_iter_get_flag(&flit)) != NULL ) {
+ if ( strcasecmp(flg, flag) == 0 )
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void flags_list_flag_delete
+(string_t *flags_list, const char *flag)
+{
+ const char *flg;
+ struct ext_imap4flags_iter flit;
+
+ ext_imap4flags_iter_init(&flit, flags_list);
+
+ while ( (flg=ext_imap4flags_iter_get_flag(&flit)) != NULL ) {
+ if ( strcasecmp(flg, flag) == 0 ) {
+ ext_imap4flags_iter_delete_last(&flit);
+ }
+ }
+}
+
+static void flags_list_add_flags
+(string_t *flags_list, string_t *flags)
+{
+ const char *flg;
+ struct ext_imap4flags_iter flit;
+
+ ext_imap4flags_iter_init(&flit, flags);
+
+ while ( (flg=ext_imap4flags_iter_get_flag(&flit)) != NULL ) {
+ if ( sieve_ext_imap4flags_flag_is_valid(flg) &&
+ !flags_list_flag_exists(flags_list, flg) ) {
+ if ( str_len(flags_list) != 0 )
+ str_append_c(flags_list, ' ');
+ str_append(flags_list, flg);
+ }
+ }
+}
+
+static void flags_list_remove_flags
+(string_t *flags_list, string_t *flags)
+{
+ const char *flg;
+ struct ext_imap4flags_iter flit;
+
+ ext_imap4flags_iter_init(&flit, flags);
+
+ while ( (flg=ext_imap4flags_iter_get_flag(&flit)) != NULL ) {
+ flags_list_flag_delete(flags_list, flg);
+ }
+}
+
+static void flags_list_set_flags
+(string_t *flags_list, string_t *flags)
+{
+ str_truncate(flags_list, 0);
+ flags_list_add_flags(flags_list, flags);
+}
+
+static void flags_list_clear_flags
+(string_t *flags_list)
+{
+ str_truncate(flags_list, 0);
+}
+
+static string_t *ext_imap4flags_get_flag_variable
+(const struct sieve_runtime_env *renv,
+ const struct sieve_extension *flg_ext,
+ struct sieve_variable_storage *storage,
+ unsigned int var_index)
+{
+ string_t *flags;
+
+ if ( storage != NULL ) {
+ if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+ const char *var_name, *var_id;
+
+ (void)sieve_variable_get_identifier(storage, var_index, &var_name);
+ var_id = sieve_variable_get_varid(storage, var_index);
+
+ sieve_runtime_trace(renv, 0, "update variable `%s' [%s]",
+ var_name, var_id);
+ }
+
+ if ( !sieve_variable_get_modifiable(storage, var_index, &flags) )
+ return NULL;
+ } else {
+ i_assert( sieve_extension_is(flg_ext, imap4flags_extension) );
+ flags = _get_flags_string(flg_ext, renv->result);
+ }
+
+ return flags;
+}
+
+int sieve_ext_imap4flags_set_flags
+(const struct sieve_runtime_env *renv,
+ const struct sieve_extension *flg_ext,
+ struct sieve_variable_storage *storage,
+ unsigned int var_index,
+ struct sieve_stringlist *flags)
+{
+ string_t *cur_flags = ext_imap4flags_get_flag_variable
+ (renv, flg_ext, storage, var_index);
+
+ if ( cur_flags != NULL ) {
+ string_t *flags_item;
+ int ret;
+
+ flags_list_clear_flags(cur_flags);
+ while ( (ret=sieve_stringlist_next_item(flags, &flags_item)) > 0 ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
+ "set flags `%s'", str_c(flags_item));
+
+ flags_list_add_flags(cur_flags, flags_item);
+ }
+
+ if ( ret < 0 ) return SIEVE_EXEC_BIN_CORRUPT;
+
+ return SIEVE_EXEC_OK;
+ }
+
+ return SIEVE_EXEC_BIN_CORRUPT;
+}
+
+int sieve_ext_imap4flags_add_flags
+(const struct sieve_runtime_env *renv,
+ const struct sieve_extension *flg_ext,
+ struct sieve_variable_storage *storage,
+ unsigned int var_index,
+ struct sieve_stringlist *flags)
+{
+ string_t *cur_flags = ext_imap4flags_get_flag_variable
+ (renv, flg_ext, storage, var_index);
+
+ if ( cur_flags != NULL ) {
+ string_t *flags_item;
+ int ret;
+
+ while ( (ret=sieve_stringlist_next_item(flags, &flags_item)) > 0 ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
+ "add flags `%s'", str_c(flags_item));
+
+ flags_list_add_flags(cur_flags, flags_item);
+ }
+
+ if ( ret < 0 ) return SIEVE_EXEC_BIN_CORRUPT;
+
+ return SIEVE_EXEC_OK;
+ }
+
+ return SIEVE_EXEC_BIN_CORRUPT;
+}
+
+int sieve_ext_imap4flags_remove_flags
+(const struct sieve_runtime_env *renv,
+ const struct sieve_extension *flg_ext,
+ struct sieve_variable_storage *storage,
+ unsigned int var_index,
+ struct sieve_stringlist *flags)
+{
+ string_t *cur_flags = ext_imap4flags_get_flag_variable
+ (renv, flg_ext, storage, var_index);
+
+ if ( cur_flags != NULL ) {
+ string_t *flags_item;
+ int ret;
+
+ while ( (ret=sieve_stringlist_next_item(flags, &flags_item)) > 0 ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
+ "remove flags `%s'", str_c(flags_item));
+
+ flags_list_remove_flags(cur_flags, flags_item);
+ }
+
+ if ( ret < 0 ) return SIEVE_EXEC_BIN_CORRUPT;
+
+ return SIEVE_EXEC_OK;
+ }
+
+ return SIEVE_EXEC_BIN_CORRUPT;
+}
+
+/* Flag stringlist */
+
+static int ext_imap4flags_stringlist_next_item
+ (struct sieve_stringlist *_strlist, string_t **str_r);
+static void ext_imap4flags_stringlist_reset
+ (struct sieve_stringlist *_strlist);
+
+struct ext_imap4flags_stringlist {
+ struct sieve_stringlist strlist;
+
+ struct sieve_stringlist *flags_list;
+ string_t *flags_string;
+ struct ext_imap4flags_iter flit;
+
+ bool normalize:1;
+};
+
+static struct sieve_stringlist *ext_imap4flags_stringlist_create
+(const struct sieve_runtime_env *renv, struct sieve_stringlist *flags_list,
+ bool normalize)
+{
+ struct ext_imap4flags_stringlist *strlist;
+
+ strlist = t_new(struct ext_imap4flags_stringlist, 1);
+ strlist->strlist.exec_status = SIEVE_EXEC_OK;
+ strlist->strlist.runenv = renv;
+ strlist->strlist.next_item = ext_imap4flags_stringlist_next_item;
+ strlist->strlist.reset = ext_imap4flags_stringlist_reset;
+ strlist->normalize = normalize;
+
+ strlist->flags_list = flags_list;
+
+ return &strlist->strlist;
+}
+
+static struct sieve_stringlist *ext_imap4flags_stringlist_create_single
+(const struct sieve_runtime_env *renv, string_t *flags_string, bool normalize)
+{
+ struct ext_imap4flags_stringlist *strlist;
+
+ strlist = t_new(struct ext_imap4flags_stringlist, 1);
+ strlist->strlist.exec_status = SIEVE_EXEC_OK;
+ strlist->strlist.runenv = renv;
+ strlist->strlist.next_item = ext_imap4flags_stringlist_next_item;
+ strlist->strlist.reset = ext_imap4flags_stringlist_reset;
+ strlist->normalize = normalize;
+
+ if ( normalize ) {
+ strlist->flags_string = t_str_new(256);
+ flags_list_set_flags(strlist->flags_string, flags_string);
+ } else {
+ strlist->flags_string = flags_string;
+ }
+
+ ext_imap4flags_iter_init(&strlist->flit, strlist->flags_string);
+
+ return &strlist->strlist;
+}
+
+static int ext_imap4flags_stringlist_next_item
+(struct sieve_stringlist *_strlist, string_t **str_r)
+{
+ struct ext_imap4flags_stringlist *strlist =
+ (struct ext_imap4flags_stringlist *)_strlist;
+
+ while ( (*str_r=ext_imap4flags_iter_get_flag_str(&strlist->flit)) == NULL ) {
+ int ret;
+
+ if ( strlist->flags_list == NULL )
+ return 0;
+
+ if ( (ret=sieve_stringlist_next_item
+ (strlist->flags_list, &strlist->flags_string)) <= 0 )
+ return ret;
+
+ if ( strlist->flags_string == NULL )
+ return -1;
+
+ if ( strlist->normalize ) {
+ string_t *flags_string = t_str_new(256);
+
+ flags_list_set_flags(flags_string, strlist->flags_string);
+ strlist->flags_string = flags_string;
+ }
+
+ ext_imap4flags_iter_init(&strlist->flit, strlist->flags_string);
+ }
+
+ return 1;
+}
+
+static void ext_imap4flags_stringlist_reset
+(struct sieve_stringlist *_strlist)
+{
+ struct ext_imap4flags_stringlist *strlist =
+ (struct ext_imap4flags_stringlist *)_strlist;
+
+ if ( strlist->flags_list != NULL ) {
+ sieve_stringlist_reset(strlist->flags_list);
+ ext_imap4flags_iter_clear(&strlist->flit);
+ } else {
+ ext_imap4flags_iter_init(&strlist->flit, strlist->flags_string);
+ }
+}
+
+/* Flag access */
+
+struct sieve_stringlist *sieve_ext_imap4flags_get_flags
+(const struct sieve_runtime_env *renv,
+ const struct sieve_extension *flg_ext,
+ struct sieve_stringlist *flags_list)
+{
+ if ( flags_list == NULL ) {
+ i_assert( sieve_extension_is(flg_ext, imap4flags_extension) );
+ return ext_imap4flags_stringlist_create_single
+ (renv, _get_flags_string(flg_ext, renv->result), FALSE);
+ }
+
+ return ext_imap4flags_stringlist_create(renv, flags_list, TRUE);
+}
+
+void ext_imap4flags_get_implicit_flags_init
+(struct ext_imap4flags_iter *iter, const struct sieve_extension *this_ext,
+ struct sieve_result *result)
+{
+ string_t *cur_flags = _get_flags_string(this_ext, result);
+
+ ext_imap4flags_iter_init(iter, cur_flags);
+}
+
+
+
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h b/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
new file mode 100644
index 0000000..4bedb85
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h
@@ -0,0 +1,97 @@
+#ifndef EXT_IMAP4FLAGS_COMMON_H
+#define EXT_IMAP4FLAGS_COMMON_H
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-ext-variables.h"
+
+#include "sieve-ext-imap4flags.h"
+
+/*
+ * Side effect
+ */
+
+extern const struct sieve_side_effect_def flags_side_effect;
+
+/*
+ * Operands
+ */
+
+extern const struct sieve_operand_def flags_side_effect_operand;
+
+/*
+ * Operations
+ */
+
+enum ext_imap4flags_opcode {
+ EXT_IMAP4FLAGS_OPERATION_SETFLAG,
+ EXT_IMAP4FLAGS_OPERATION_ADDFLAG,
+ EXT_IMAP4FLAGS_OPERATION_REMOVEFLAG,
+ EXT_IMAP4FLAGS_OPERATION_HASFLAG
+};
+
+extern const struct sieve_operation_def setflag_operation;
+extern const struct sieve_operation_def addflag_operation;
+extern const struct sieve_operation_def removeflag_operation;
+extern const struct sieve_operation_def hasflag_operation;
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def cmd_setflag;
+extern const struct sieve_command_def cmd_addflag;
+extern const struct sieve_command_def cmd_removeflag;
+
+extern const struct sieve_command_def tst_hasflag;
+
+/*
+ * Common command functions
+ */
+
+bool ext_imap4flags_command_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+
+/*
+ * Flags tagged argument
+ */
+
+void ext_imap4flags_attach_flags_tag
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ const char *command);
+
+/*
+ * Flag management
+ */
+
+struct ext_imap4flags_iter {
+ string_t *flags_list;
+ unsigned int offset;
+ unsigned int last;
+};
+
+void ext_imap4flags_iter_init
+ (struct ext_imap4flags_iter *iter, string_t *flags_list);
+
+const char *ext_imap4flags_iter_get_flag
+ (struct ext_imap4flags_iter *iter);
+
+/* Flag operations */
+
+typedef int (*ext_imapflag_flag_operation_t)
+ (const struct sieve_runtime_env *renv,
+ const struct sieve_extension *flg_ext,
+ struct sieve_variable_storage *storage,
+ unsigned int var_index, struct sieve_stringlist *flags)
+ ATTR_NULL(2);
+
+/* Flags access */
+
+void ext_imap4flags_get_implicit_flags_init
+ (struct ext_imap4flags_iter *iter, const struct sieve_extension *this_ext,
+ struct sieve_result *result);
+
+
+#endif
+
diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags.c b/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
new file mode 100644
index 0000000..23230c1
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
@@ -0,0 +1,96 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension imap4flags
+ * --------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5232
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "lib.h"
+#include "mempool.h"
+#include "str.h"
+
+#include "sieve-common.h"
+
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-actions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+#include "ext-imap4flags-common.h"
+
+/*
+ * Operations
+ */
+
+const struct sieve_operation_def *imap4flags_operations[] = {
+ &setflag_operation,
+ &addflag_operation,
+ &removeflag_operation,
+ &hasflag_operation
+};
+
+/*
+ * Extension
+ */
+
+static bool ext_imap4flags_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+static bool ext_imap4flags_interpreter_load
+ (const struct sieve_extension *ext, const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_extension_def imap4flags_extension = {
+ .name = "imap4flags",
+ .version = 1,
+ .validator_load = ext_imap4flags_validator_load,
+ .interpreter_load = ext_imap4flags_interpreter_load,
+ SIEVE_EXT_DEFINE_OPERATIONS(imap4flags_operations),
+ SIEVE_EXT_DEFINE_OPERAND(flags_side_effect_operand)
+};
+
+static bool ext_imap4flags_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Register commands */
+ sieve_validator_register_command(valdtr, ext, &cmd_setflag);
+ sieve_validator_register_command(valdtr, ext, &cmd_addflag);
+ sieve_validator_register_command(valdtr, ext, &cmd_removeflag);
+ sieve_validator_register_command(valdtr, ext, &tst_hasflag);
+
+ /* Attach :flags tag to keep and fileinto commands */
+ ext_imap4flags_attach_flags_tag(valdtr, ext, "keep");
+ ext_imap4flags_attach_flags_tag(valdtr, ext, "fileinto");
+
+ /* Attach flags side-effect to keep and fileinto actions */
+ sieve_ext_imap4flags_register_side_effect(valdtr, ext, "keep");
+ sieve_ext_imap4flags_register_side_effect(valdtr, ext, "fileinto");
+
+ return TRUE;
+}
+
+void sieve_ext_imap4flags_interpreter_load
+(const struct sieve_extension *ext, const struct sieve_runtime_env *renv)
+{
+ sieve_interpreter_extension_register
+ (renv->interp, ext, &imap4flags_interpreter_extension, NULL);
+}
+
+static bool ext_imap4flags_interpreter_load
+(const struct sieve_extension *ext, const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ sieve_ext_imap4flags_interpreter_load(ext, renv);
+ return TRUE;
+}
+
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imapflags.c b/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imapflags.c
new file mode 100644
index 0000000..ba99035
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imapflags.c
@@ -0,0 +1,213 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension imapflags
+ * --------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: draft-melnikov-sieve-imapflags-03.txt
+ * Implementation: full, but deprecated; provided for backwards compatibility
+ * Status: testing
+ *
+ */
+
+#include "lib.h"
+#include "mempool.h"
+#include "str.h"
+
+#include "sieve-common.h"
+
+#include "sieve-ast.h"
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-actions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+#include "ext-imap4flags-common.h"
+
+/*
+ * Commands
+ */
+
+static bool cmd_mark_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+
+/* Mark command
+ *
+ * Syntax:
+ * mark
+ */
+
+static const struct sieve_command_def cmd_mark = {
+ .identifier = "mark",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_mark_validate
+};
+
+/* Unmark command
+ *
+ * Syntax:
+ * unmark
+ */
+static const struct sieve_command_def cmd_unmark = {
+ .identifier = "unmark",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_mark_validate
+};
+
+/*
+ * Extension
+ */
+
+static bool ext_imapflags_load
+ (const struct sieve_extension *ext, void **context);
+static bool ext_imapflags_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+static bool ext_imapflags_interpreter_load
+ (const struct sieve_extension *ext, const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_extension_def imapflags_extension = {
+ .name = "imapflags",
+ .load = ext_imapflags_load,
+ .validator_load = ext_imapflags_validator_load,
+ .interpreter_load = ext_imapflags_interpreter_load
+};
+
+static bool ext_imapflags_load
+(const struct sieve_extension *ext, void **context)
+{
+ if ( *context == NULL ) {
+ /* Make sure real extension is registered, it is needed by the binary */
+ *context = (void *)
+ sieve_extension_require(ext->svinst, &imap4flags_extension, FALSE);
+ }
+
+ return TRUE;
+}
+
+/*
+ * Validator
+ */
+
+static bool ext_imapflags_validator_check_conflict
+ (const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context,
+ struct sieve_ast_argument *require_arg,
+ const struct sieve_extension *other_ext,
+ bool required);
+static bool ext_imapflags_validator_validate
+ (const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context,
+ struct sieve_ast_argument *require_arg,
+ bool required);
+
+const struct sieve_validator_extension
+imapflags_validator_extension = {
+ .ext = &imapflags_extension,
+ .check_conflict = ext_imapflags_validator_check_conflict,
+ .validate = ext_imapflags_validator_validate
+};
+
+static bool ext_imapflags_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ sieve_validator_extension_register
+ (valdtr, ext, &imapflags_validator_extension, NULL);
+
+ return TRUE;
+}
+
+static bool ext_imapflags_validator_check_conflict
+(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context ATTR_UNUSED,
+ struct sieve_ast_argument *require_arg,
+ const struct sieve_extension *ext_other,
+ bool required ATTR_UNUSED)
+{
+ const struct sieve_extension *master_ext =
+ (const struct sieve_extension *) ext->context;
+
+ if ( ext_other == master_ext ) {
+ sieve_argument_validate_error(valdtr, require_arg,
+ "the (deprecated) imapflags extension cannot be used "
+ "together with the imap4flags extension");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool ext_imapflags_validator_validate
+(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context ATTR_UNUSED,
+ struct sieve_ast_argument *require_arg ATTR_UNUSED,
+ bool required ATTR_UNUSED)
+{
+ const struct sieve_extension *master_ext =
+ (const struct sieve_extension *) ext->context;
+
+ /* No conflicts */
+
+ /* Register commands */
+ sieve_validator_register_command(valdtr, master_ext, &cmd_setflag);
+ sieve_validator_register_command(valdtr, master_ext, &cmd_addflag);
+ sieve_validator_register_command(valdtr, master_ext, &cmd_removeflag);
+
+ sieve_validator_register_command(valdtr, master_ext, &cmd_mark);
+ sieve_validator_register_command(valdtr, master_ext, &cmd_unmark);
+
+ /* Attach flags side-effect to keep and fileinto actions */
+ sieve_ext_imap4flags_register_side_effect(valdtr, master_ext, "keep");
+ sieve_ext_imap4flags_register_side_effect(valdtr, master_ext, "fileinto");
+
+ return TRUE;
+}
+
+/*
+ * Interpreter
+ */
+
+static bool ext_imapflags_interpreter_load
+(const struct sieve_extension *ext, const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ const struct sieve_extension *master_ext =
+ (const struct sieve_extension *) ext->context;
+
+ sieve_ext_imap4flags_interpreter_load(master_ext, renv);
+ return TRUE;
+}
+
+/*
+ * Command validation
+ */
+
+static bool cmd_mark_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ if ( sieve_command_is(cmd, cmd_mark) )
+ cmd->def = &cmd_addflag;
+ else
+ cmd->def = &cmd_removeflag;
+
+ cmd->first_positional = sieve_ast_argument_cstring_create
+ (cmd->ast_node, "\\flagged", cmd->ast_node->source_line);
+
+ if ( !sieve_validator_argument_activate
+ (valdtr, cmd, cmd->first_positional, FALSE) )
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h b/pigeonhole/src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h
new file mode 100644
index 0000000..b38a3c8
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h
@@ -0,0 +1,74 @@
+#ifndef SIEVE_EXT_IMAP4FLAGS_H
+#define SIEVE_EXT_IMAP4FLAGS_H
+
+struct sieve_variable_storage;
+
+/*
+ * Imap4flags extension
+ */
+
+/* FIXME: this is not suitable for future plugin support */
+
+extern const struct sieve_extension_def imap4flags_extension;
+extern const struct sieve_interpreter_extension
+ imap4flags_interpreter_extension;
+
+static inline const struct sieve_extension *
+sieve_ext_imap4flags_require_extension
+(struct sieve_instance *svinst)
+{
+ return sieve_extension_require
+ (svinst, &imap4flags_extension, TRUE);
+}
+
+void sieve_ext_imap4flags_interpreter_load
+(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv);
+
+/*
+ * Action side-effect
+ */
+
+void sieve_ext_imap4flags_register_side_effect
+(struct sieve_validator *valdtr, const struct sieve_extension *flg_ext,
+ const char *command);
+
+/*
+ * Flag syntax
+ */
+
+bool sieve_ext_imap4flags_flag_is_valid(const char *flag);
+
+/*
+ * Flag manipulation
+ */
+
+int sieve_ext_imap4flags_set_flags
+(const struct sieve_runtime_env *renv,
+ const struct sieve_extension *flg_ext,
+ struct sieve_variable_storage *storage,
+ unsigned int var_index,
+ struct sieve_stringlist *flags) ATTR_NULL(3);
+int sieve_ext_imap4flags_add_flags
+(const struct sieve_runtime_env *renv,
+ const struct sieve_extension *flg_ext,
+ struct sieve_variable_storage *storage,
+ unsigned int var_index,
+ struct sieve_stringlist *flags) ATTR_NULL(3);
+int sieve_ext_imap4flags_remove_flags
+(const struct sieve_runtime_env *renv,
+ const struct sieve_extension *flg_ext,
+ struct sieve_variable_storage *storage,
+ unsigned int var_index,
+ struct sieve_stringlist *flags) ATTR_NULL(3);
+
+/*
+ * Flag retrieval
+ */
+
+struct sieve_stringlist *sieve_ext_imap4flags_get_flags
+(const struct sieve_runtime_env *renv,
+ const struct sieve_extension *flg_ext,
+ struct sieve_stringlist *flags_list);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/tag-flags.c b/pigeonhole/src/lib-sieve/plugins/imap4flags/tag-flags.c
new file mode 100644
index 0000000..331063d
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/tag-flags.c
@@ -0,0 +1,402 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+#include "array.h"
+#include "mail-storage.h"
+
+#include "sieve-code.h"
+#include "sieve-stringlist.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-result.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-actions.h"
+#include "sieve-dump.h"
+
+#include "ext-imap4flags-common.h"
+
+#include <ctype.h>
+
+/*
+ * Flags tagged argument
+ */
+
+static bool
+tag_flags_validate(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg, struct sieve_command *cmd);
+static bool
+tag_flags_validate_persistent(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ const struct sieve_extension *ext);
+static bool
+tag_flags_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_argument *arg, struct sieve_command *cmd);
+
+const struct sieve_argument_def tag_flags = {
+ .identifier = "flags",
+ .validate = tag_flags_validate,
+ .generate = tag_flags_generate,
+};
+
+const struct sieve_argument_def tag_flags_implicit = {
+ .identifier = "flags-implicit",
+ .validate_persistent = tag_flags_validate_persistent,
+ .generate = tag_flags_generate,
+};
+
+/*
+ * Side effect
+ */
+
+static bool
+seff_flags_dump_context(const struct sieve_side_effect *seffect,
+ const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+seff_flags_read_context(const struct sieve_side_effect *seffect,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address, void **context);
+
+static int
+seff_flags_merge(const struct sieve_runtime_env *renv,
+ const struct sieve_action *action,
+ const struct sieve_side_effect *old_seffect,
+ const struct sieve_side_effect *new_seffect,
+ void **old_context);
+
+static void
+seff_flags_print(const struct sieve_side_effect *seffect,
+ const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv, bool *keep);
+
+static int
+seff_flags_pre_execute(const struct sieve_side_effect *seffect,
+ const struct sieve_action_exec_env *aenv,
+ void *tr_context, void **se_tr_context);
+
+const struct sieve_side_effect_def flags_side_effect = {
+ SIEVE_OBJECT("flags", &flags_side_effect_operand, 0),
+ .to_action = &act_store,
+ .dump_context = seff_flags_dump_context,
+ .read_context = seff_flags_read_context,
+ .merge = seff_flags_merge,
+ .print = seff_flags_print,
+ .pre_execute = seff_flags_pre_execute,
+};
+
+/*
+ * Operand
+ */
+
+static const struct sieve_extension_objects ext_side_effects =
+ SIEVE_EXT_DEFINE_SIDE_EFFECT(flags_side_effect);
+
+const struct sieve_operand_def flags_side_effect_operand = {
+ .name = "flags operand",
+ .ext_def = &imap4flags_extension,
+ .class = &sieve_side_effect_operand_class,
+ .interface = &ext_side_effects,
+};
+
+/*
+ * Tag validation
+ */
+
+static bool
+tag_flags_validate_persistent(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_command *cmd,
+ const struct sieve_extension *ext)
+{
+ if (sieve_command_find_argument(cmd, &tag_flags) == NULL)
+ sieve_command_add_dynamic_tag(cmd, ext, &tag_flags_implicit,
+ -1);
+ return TRUE;
+}
+
+static bool
+tag_flags_validate(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_argument_next(*arg);
+
+ /* Check syntax:
+ * :flags <list-of-flags: string-list>
+ */
+ if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0,
+ SAAT_STRING_LIST, FALSE))
+ return FALSE;
+
+ tag->parameters = *arg;
+
+ /* Detach parameter */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+tag_flags_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_argument *arg, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *param;
+
+ if (sieve_ast_argument_type(arg) != SAAT_TAG)
+ return FALSE;
+
+ sieve_opr_side_effect_emit(cgenv->sblock, arg->argument->ext,
+ &flags_side_effect);
+
+ if (sieve_argument_is(arg, tag_flags)) {
+ /* Explicit :flags tag */
+ param = arg->parameters;
+
+ /* Call the generation function for the argument */
+ if (param->argument != NULL && param->argument->def != NULL &&
+ param->argument->def->generate != NULL &&
+ !param->argument->def->generate(cgenv, param, cmd))
+ return FALSE;
+ } else if (sieve_argument_is(arg, tag_flags_implicit)) {
+ /* Implicit flags */
+ sieve_opr_omitted_emit(cgenv->sblock);
+ } else {
+ /* Something else?! */
+ i_unreached();
+ }
+ return TRUE;
+}
+
+/*
+ * Side effect implementation
+ */
+
+/* Context data */
+
+struct seff_flags_context {
+ ARRAY(const char *) keywords;
+ enum mail_flags flags;
+};
+
+/* Context coding */
+
+static bool
+seff_flags_dump_context(const struct sieve_side_effect *seffect ATTR_UNUSED,
+ const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ return sieve_opr_stringlist_dump_ex(denv, address, "flags", "INTERNAL");
+}
+
+static struct seff_flags_context *
+seff_flags_get_implicit_context(const struct sieve_extension *this_ext,
+ struct sieve_result *result)
+{
+ pool_t pool = sieve_result_pool(result);
+ struct seff_flags_context *ctx;
+ const char *flag;
+ struct ext_imap4flags_iter flit;
+
+ ctx = p_new(pool, struct seff_flags_context, 1);
+ p_array_init(&ctx->keywords, pool, 2);
+
+ T_BEGIN {
+ /* Unpack */
+ ext_imap4flags_get_implicit_flags_init(&flit, this_ext, result);
+ while ((flag = ext_imap4flags_iter_get_flag(&flit)) != NULL) {
+ if (flag != NULL && *flag != '\\') {
+ /* keyword */
+ const char *keyword = p_strdup(pool, flag);
+ array_append(&ctx->keywords, &keyword, 1);
+ } else {
+ /* system flag */
+ if (flag == NULL ||
+ strcasecmp(flag, "\\flagged") == 0)
+ ctx->flags |= MAIL_FLAGGED;
+ else if (strcasecmp(flag, "\\answered") == 0)
+ ctx->flags |= MAIL_ANSWERED;
+ else if (strcasecmp(flag, "\\deleted") == 0)
+ ctx->flags |= MAIL_DELETED;
+ else if (strcasecmp(flag, "\\seen") == 0)
+ ctx->flags |= MAIL_SEEN;
+ else if (strcasecmp(flag, "\\draft") == 0)
+ ctx->flags |= MAIL_DRAFT;
+ }
+ }
+ } T_END;
+
+ return ctx;
+}
+
+static int
+seff_flags_do_read_context(const struct sieve_side_effect *seffect,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address, void **se_context)
+{
+ pool_t pool = sieve_result_pool(renv->result);
+ struct seff_flags_context *ctx;
+ string_t *flags_item;
+ struct sieve_stringlist *flag_list = NULL;
+ int ret;
+
+ ret = sieve_opr_stringlist_read_ex(renv, address, "flags", TRUE,
+ &flag_list);
+ if (ret <= 0)
+ return ret;
+
+ if (flag_list == NULL) {
+ /* Flag list is omitted, use current value of internal
+ * variable to construct side effect context.
+ */
+ *se_context = seff_flags_get_implicit_context(
+ SIEVE_OBJECT_EXTENSION(seffect), renv->result);
+ return SIEVE_EXEC_OK;
+ }
+
+ ctx = p_new(pool, struct seff_flags_context, 1);
+ p_array_init(&ctx->keywords, pool, 2);
+
+ /* Unpack */
+ flags_item = NULL;
+ while ((ret = sieve_stringlist_next_item(flag_list, &flags_item)) > 0) {
+ const char *flag;
+ struct ext_imap4flags_iter flit;
+
+ ext_imap4flags_iter_init(&flit, flags_item);
+
+ while ((flag = ext_imap4flags_iter_get_flag(&flit)) != NULL) {
+ if (flag != NULL && *flag != '\\') {
+ /* keyword */
+ const char *keyword = p_strdup(pool, flag);
+
+ /* FIXME: should check for duplicates (cannot
+ trust variables) */
+ array_append(&ctx->keywords, &keyword, 1);
+ } else {
+ /* system flag */
+ if (flag == NULL ||
+ strcasecmp(flag, "\\flagged") == 0)
+ ctx->flags |= MAIL_FLAGGED;
+ else if (strcasecmp(flag, "\\answered") == 0)
+ ctx->flags |= MAIL_ANSWERED;
+ else if (strcasecmp(flag, "\\deleted") == 0)
+ ctx->flags |= MAIL_DELETED;
+ else if (strcasecmp(flag, "\\seen") == 0)
+ ctx->flags |= MAIL_SEEN;
+ else if (strcasecmp(flag, "\\draft") == 0)
+ ctx->flags |= MAIL_DRAFT;
+ }
+ }
+ }
+
+ if (ret < 0)
+ return flag_list->exec_status;
+
+ *se_context = (void *)ctx;
+ return SIEVE_EXEC_OK;
+}
+
+static int
+seff_flags_read_context(const struct sieve_side_effect *seffect,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address, void **se_context)
+{
+ int ret;
+
+ T_BEGIN {
+ ret = seff_flags_do_read_context(seffect, renv, address,
+ se_context);
+ } T_END;
+
+ return ret;
+}
+
+/* Result verification */
+
+static int
+seff_flags_merge(const struct sieve_runtime_env *renv ATTR_UNUSED,
+ const struct sieve_action *action ATTR_UNUSED,
+ const struct sieve_side_effect *old_seffect ATTR_UNUSED,
+ const struct sieve_side_effect *new_seffect,
+ void **old_context)
+{
+ if (new_seffect != NULL)
+ *old_context = new_seffect->context;
+ return 1;
+}
+
+/* Result printing */
+
+static void
+seff_flags_print(const struct sieve_side_effect *seffect,
+ const struct sieve_action *action ATTR_UNUSED,
+ const struct sieve_result_print_env *rpenv,
+ bool *keep ATTR_UNUSED)
+{
+ struct sieve_result *result = rpenv->result;
+ struct seff_flags_context *ctx =
+ (struct seff_flags_context *)seffect->context;
+ unsigned int i;
+
+ if (ctx == NULL) {
+ ctx = seff_flags_get_implicit_context(
+ SIEVE_OBJECT_EXTENSION(seffect), result);
+ }
+
+ if (ctx->flags != 0 || array_count(&ctx->keywords) > 0) {
+ T_BEGIN {
+ string_t *flags = t_str_new(128);
+
+ if ((ctx->flags & MAIL_FLAGGED) > 0)
+ str_printfa(flags, " \\flagged");
+ if ((ctx->flags & MAIL_ANSWERED) > 0)
+ str_printfa(flags, " \\answered");
+ if ((ctx->flags & MAIL_DELETED) > 0)
+ str_printfa(flags, " \\deleted");
+ if ((ctx->flags & MAIL_SEEN) > 0)
+ str_printfa(flags, " \\seen");
+ if ((ctx->flags & MAIL_DRAFT) > 0)
+ str_printfa(flags, " \\draft");
+
+ for (i = 0; i < array_count(&ctx->keywords); i++) {
+ const char *const *keyword =
+ array_idx(&ctx->keywords, i);
+ str_printfa(flags, " %s",
+ str_sanitize(*keyword, 64));
+ }
+
+ sieve_result_seffect_printf(rpenv, "add IMAP flags:%s",
+ str_c(flags));
+ } T_END;
+ }
+}
+
+/* Result execution */
+
+static int
+seff_flags_pre_execute(const struct sieve_side_effect *seffect,
+ const struct sieve_action_exec_env *aenv,
+ void *tr_context, void **se_tr_context ATTR_UNUSED)
+{
+ struct seff_flags_context *ctx = seffect->context;
+ const char *const *keywords;
+
+ if (ctx == NULL) {
+ ctx = seff_flags_get_implicit_context(
+ SIEVE_OBJECT_EXTENSION(seffect), aenv->result);
+ }
+
+ (void)array_append_space(&ctx->keywords);
+ keywords = array_idx(&ctx->keywords, 0);
+
+ sieve_act_store_add_flags(aenv, tr_context, keywords, ctx->flags);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/tst-hasflag.c b/pigeonhole/src/lib-sieve/plugins/imap4flags/tst-hasflag.c
new file mode 100644
index 0000000..23f2acc
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/tst-hasflag.c
@@ -0,0 +1,248 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-commands.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-match.h"
+
+#include "ext-imap4flags-common.h"
+
+/*
+ * Hasflag test
+ *
+ * Syntax:
+ * hasflag [MATCH-TYPE] [COMPARATOR] [<variable-list: string-list>]
+ * <list-of-flags: string-list>
+ */
+
+static bool tst_hasflag_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool tst_hasflag_validate
+ (struct sieve_validator *valdtr, struct sieve_command *tst);
+static bool tst_hasflag_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
+
+const struct sieve_command_def tst_hasflag = {
+ .identifier = "hasflag",
+ .type = SCT_TEST,
+ .positional_args = -1, /* We check positional arguments ourselves */
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_hasflag_registered,
+ .validate = tst_hasflag_validate,
+ .generate = tst_hasflag_generate
+};
+
+/*
+ * Hasflag operation
+ */
+
+static bool tst_hasflag_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int tst_hasflag_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def hasflag_operation = {
+ .mnemonic = "HASFLAG",
+ .ext_def = &imap4flags_extension,
+ .code = EXT_IMAP4FLAGS_OPERATION_HASFLAG,
+ .dump = tst_hasflag_operation_dump,
+ .execute = tst_hasflag_operation_execute
+};
+
+/*
+ * Optional arguments
+ */
+
+enum tst_hasflag_optional {
+ OPT_VARIABLES = SIEVE_MATCH_OPT_LAST,
+};
+
+/*
+ * Tag registration
+ */
+
+static bool tst_hasflag_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_command_registration *cmd_reg)
+{
+ /* The order of these is not significant */
+ sieve_comparators_link_tag(valdtr, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
+ sieve_match_types_link_tags(valdtr, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
+
+ return TRUE;
+}
+
+/*
+ * Validation
+ */
+
+static bool tst_hasflag_validate
+(struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *vars = tst->first_positional;
+ struct sieve_ast_argument *keys = sieve_ast_argument_next(vars);
+ const struct sieve_match_type mcht_default =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ const struct sieve_comparator cmp_default =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+
+ if ( !ext_imap4flags_command_validate(valdtr, tst) )
+ return FALSE;
+
+ if ( keys == NULL ) {
+ keys = vars;
+ vars = NULL;
+ } else {
+ vars->argument->id_code = OPT_VARIABLES;
+ }
+
+ /* Validate the key argument to a specified match type */
+ return sieve_match_type_validate
+ (valdtr, tst, keys, &mcht_default, &cmp_default);
+}
+
+/*
+ * Code generation
+ */
+
+static bool tst_hasflag_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &hasflag_operation);
+
+ /* Generate arguments */
+ if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool tst_hasflag_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "HASFLAG");
+ sieve_code_descend(denv);
+
+ /* Optional operands */
+
+ for (;;) {
+ bool opok = TRUE;
+ int opt;
+
+ if ( (opt=sieve_match_opr_optional_dump(denv, address, &opt_code))
+ < 0 )
+ return FALSE;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_VARIABLES:
+ opok = sieve_opr_stringlist_dump(denv, address, "variables");
+ break;
+ default:
+ return FALSE;
+ }
+
+ if ( !opok ) return FALSE;
+ }
+
+ return
+ sieve_opr_stringlist_dump(denv, address, "list of flags");
+}
+
+/*
+ * Interpretation
+ */
+
+static int tst_hasflag_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ const struct sieve_operation *op = renv->oprtn;
+ int opt_code = 0;
+ struct sieve_comparator cmp =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+ struct sieve_match_type mcht =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ struct sieve_stringlist *flag_list, *variables_list, *value_list, *key_list;
+ int match, ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Optional operands */
+
+ variables_list = NULL;
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_match_opr_optional_read
+ (renv, address, &opt_code, &ret, &cmp, &mcht)) < 0 )
+ return ret;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_VARIABLES:
+ ret = sieve_opr_stringlist_read
+ (renv, address, "variables-list", &variables_list);
+ break;
+ default:
+ sieve_runtime_trace_error(renv, "invalid optional operand");
+ ret = SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if ( ret <= 0 ) return ret;
+ }
+
+ /* Fixed operands */
+
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "flag-list", &flag_list))
+ <= 0 )
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "hasflag test");
+
+ value_list = sieve_ext_imap4flags_get_flags
+ (renv, op->ext, variables_list);
+
+ if ( sieve_match_type_is(&mcht, is_match_type) ||
+ sieve_match_type_is(&mcht, contains_match_type) ) {
+ key_list = sieve_ext_imap4flags_get_flags
+ (renv, op->ext, flag_list);
+ } else {
+ key_list = flag_list;
+ }
+
+ /* Perform match */
+ if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret)) < 0 )
+ return ret;
+
+ /* Set test result for subsequent conditional jump */
+ sieve_interpreter_set_test_result(renv->interp, match > 0);
+ return SIEVE_EXEC_OK;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/include/Makefile.am b/pigeonhole/src/lib-sieve/plugins/include/Makefile.am
new file mode 100644
index 0000000..5ce1599
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/include/Makefile.am
@@ -0,0 +1,24 @@
+noinst_LTLIBRARIES = libsieve_ext_include.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../variables \
+ $(LIBDOVECOT_INCLUDE)
+
+cmds = \
+ cmd-include.c \
+ cmd-return.c \
+ cmd-global.c
+
+libsieve_ext_include_la_SOURCES = \
+ $(cmds) \
+ ext-include-common.c \
+ ext-include-binary.c \
+ ext-include-variables.c \
+ ext-include.c
+
+noinst_HEADERS = \
+ ext-include-common.h \
+ ext-include-limits.h \
+ ext-include-binary.h \
+ ext-include-variables.h
diff --git a/pigeonhole/src/lib-sieve/plugins/include/Makefile.in b/pigeonhole/src/lib-sieve/plugins/include/Makefile.in
new file mode 100644
index 0000000..06f003f
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/include/Makefile.in
@@ -0,0 +1,718 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/include
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_include_la_LIBADD =
+am__objects_1 = cmd-include.lo cmd-return.lo cmd-global.lo
+am_libsieve_ext_include_la_OBJECTS = $(am__objects_1) \
+ ext-include-common.lo ext-include-binary.lo \
+ ext-include-variables.lo ext-include.lo
+libsieve_ext_include_la_OBJECTS = \
+ $(am_libsieve_ext_include_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cmd-global.Plo \
+ ./$(DEPDIR)/cmd-include.Plo ./$(DEPDIR)/cmd-return.Plo \
+ ./$(DEPDIR)/ext-include-binary.Plo \
+ ./$(DEPDIR)/ext-include-common.Plo \
+ ./$(DEPDIR)/ext-include-variables.Plo \
+ ./$(DEPDIR)/ext-include.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_include_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_include_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_include.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../variables \
+ $(LIBDOVECOT_INCLUDE)
+
+cmds = \
+ cmd-include.c \
+ cmd-return.c \
+ cmd-global.c
+
+libsieve_ext_include_la_SOURCES = \
+ $(cmds) \
+ ext-include-common.c \
+ ext-include-binary.c \
+ ext-include-variables.c \
+ ext-include.c
+
+noinst_HEADERS = \
+ ext-include-common.h \
+ ext-include-limits.h \
+ ext-include-binary.h \
+ ext-include-variables.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/include/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/include/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_include.la: $(libsieve_ext_include_la_OBJECTS) $(libsieve_ext_include_la_DEPENDENCIES) $(EXTRA_libsieve_ext_include_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_include_la_OBJECTS) $(libsieve_ext_include_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-global.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-include.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-return.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-include-binary.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-include-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-include-variables.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-include.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/cmd-global.Plo
+ -rm -f ./$(DEPDIR)/cmd-include.Plo
+ -rm -f ./$(DEPDIR)/cmd-return.Plo
+ -rm -f ./$(DEPDIR)/ext-include-binary.Plo
+ -rm -f ./$(DEPDIR)/ext-include-common.Plo
+ -rm -f ./$(DEPDIR)/ext-include-variables.Plo
+ -rm -f ./$(DEPDIR)/ext-include.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/cmd-global.Plo
+ -rm -f ./$(DEPDIR)/cmd-include.Plo
+ -rm -f ./$(DEPDIR)/cmd-return.Plo
+ -rm -f ./$(DEPDIR)/ext-include-binary.Plo
+ -rm -f ./$(DEPDIR)/ext-include-common.Plo
+ -rm -f ./$(DEPDIR)/ext-include-variables.Plo
+ -rm -f ./$(DEPDIR)/ext-include.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/include/cmd-global.c b/pigeonhole/src/lib-sieve/plugins/include/cmd-global.c
new file mode 100644
index 0000000..0ef37eb
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/include/cmd-global.c
@@ -0,0 +1,329 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-code.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "sieve-ext-variables.h"
+
+#include "ext-include-common.h"
+#include "ext-include-binary.h"
+#include "ext-include-variables.h"
+
+/*
+ * Commands
+ */
+
+static bool cmd_global_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool cmd_global_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
+
+const struct sieve_command_def cmd_global = {
+ .identifier = "global",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_global_validate,
+ .generate = cmd_global_generate,
+};
+
+/* DEPRICATED:
+ */
+
+/* Import command
+ *
+ * Syntax
+ * import
+ */
+const struct sieve_command_def cmd_import = {
+ .identifier = "import",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_global_validate,
+ .generate = cmd_global_generate,
+};
+
+/* Export command
+ *
+ * Syntax
+ * export
+ */
+const struct sieve_command_def cmd_export = {
+ .identifier = "export",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_global_validate,
+ .generate = cmd_global_generate,
+};
+
+/*
+ * Operations
+ */
+
+static bool opc_global_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int opc_global_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+/* Global operation */
+
+const struct sieve_operation_def global_operation = {
+ .mnemonic = "GLOBAL",
+ .ext_def = &include_extension,
+ .code = EXT_INCLUDE_OPERATION_GLOBAL,
+ .dump = opc_global_dump,
+ .execute = opc_global_execute
+};
+
+/*
+ * Validation
+ */
+
+static inline struct sieve_argument *_create_variable_argument
+(struct sieve_command *cmd, struct sieve_variable *var)
+{
+ struct sieve_argument *argument = sieve_argument_create
+ (cmd->ast_node->ast, NULL, cmd->ext, 0);
+
+ argument->data = (void *) var;
+
+ return argument;
+}
+
+static bool cmd_global_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ const struct sieve_extension *this_ext = cmd->ext;
+ struct sieve_ast_argument *arg = cmd->first_positional;
+ struct sieve_command *prev = sieve_command_prev(cmd);
+
+ /* DEPRECATED: Check valid command placement */
+ if ( !sieve_command_is(cmd, cmd_global) ) {
+ if ( !sieve_command_is_toplevel(cmd) ||
+ ( !sieve_command_is_first(cmd) && prev != NULL &&
+ !sieve_command_is(prev, cmd_require) &&
+ !sieve_command_is(prev, cmd_import) &&
+ !sieve_command_is(prev, cmd_export) ) ) {
+ sieve_command_validate_error(valdtr, cmd,
+ "the DEPRECATED %s command can only be placed at top level "
+ "at the beginning of the file after any require or "
+ "import/export commands",
+ sieve_command_identifier(cmd));
+ return FALSE;
+ }
+ }
+
+ /* Check for use of variables extension */
+ if ( !ext_include_validator_have_variables(this_ext, valdtr) ) {
+ sieve_command_validate_error(valdtr, cmd,
+ "%s command requires that variables extension is active",
+ sieve_command_identifier(cmd));
+ return FALSE;
+ }
+
+ /* Register global variable */
+ if ( sieve_ast_argument_type(arg) == SAAT_STRING ) {
+ /* Single string */
+ const char *identifier = sieve_ast_argument_strc(arg);
+ struct sieve_variable *var;
+
+ if ( (var=ext_include_variable_import_global
+ (valdtr, cmd, identifier)) == NULL )
+ return FALSE;
+
+ arg->argument = _create_variable_argument(cmd, var);
+
+ } else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) {
+ /* String list */
+ struct sieve_ast_argument *stritem = sieve_ast_strlist_first(arg);
+
+ while ( stritem != NULL ) {
+ const char *identifier = sieve_ast_argument_strc(stritem);
+ struct sieve_variable *var;
+
+ if ( (var=ext_include_variable_import_global
+ (valdtr, cmd, identifier)) == NULL )
+ return FALSE;
+
+ stritem->argument = _create_variable_argument(cmd, var);
+
+ stritem = sieve_ast_strlist_next(stritem);
+ }
+ } else {
+ /* Something else */
+ sieve_argument_validate_error(valdtr, arg,
+ "the %s command accepts a single string or string list argument, "
+ "but %s was found", sieve_command_identifier(cmd),
+ sieve_ast_argument_name(arg));
+ return FALSE;
+ }
+
+ /* Join global commands with predecessors if possible */
+ if ( sieve_commands_equal(prev, cmd) ) {
+ /* Join this command's string list with the previous one */
+ prev->first_positional = sieve_ast_stringlist_join
+ (prev->first_positional, cmd->first_positional);
+
+ if ( prev->first_positional == NULL ) {
+ /* Not going to happen unless MAXINT stringlist items are specified */
+ sieve_command_validate_error(valdtr, cmd,
+ "compiler reached AST limit (script too complex)");
+ return FALSE;
+ }
+
+ /* Detach this command node */
+ sieve_ast_node_detach(cmd->ast_node);
+ }
+
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool cmd_global_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &global_operation);
+
+ if ( sieve_ast_argument_type(arg) == SAAT_STRING ) {
+ /* Single string */
+ struct sieve_variable *var = (struct sieve_variable *) arg->argument->data;
+
+ (void)sieve_binary_emit_unsigned(cgenv->sblock, 1);
+ (void)sieve_binary_emit_unsigned(cgenv->sblock, var->index);
+
+ } else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) {
+ /* String list */
+ struct sieve_ast_argument *stritem = sieve_ast_strlist_first(arg);
+
+ (void)sieve_binary_emit_unsigned
+ (cgenv->sblock, sieve_ast_strlist_count(arg));
+
+ while ( stritem != NULL ) {
+ struct sieve_variable *var =
+ (struct sieve_variable *) stritem->argument->data;
+
+ (void)sieve_binary_emit_unsigned(cgenv->sblock, var->index);
+
+ stritem = sieve_ast_strlist_next(stritem);
+ }
+ } else {
+ i_unreached();
+ }
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool opc_global_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ const struct sieve_extension *this_ext = denv->oprtn->ext;
+ unsigned int count, i, var_count;
+ struct sieve_variable_scope_binary *global_vars;
+ struct sieve_variable_scope *global_scope;
+ struct sieve_variable * const *vars;
+
+ if ( !sieve_binary_read_unsigned(denv->sblock, address, &count) )
+ return FALSE;
+
+ sieve_code_dumpf(denv, "GLOBAL (count: %u):", count);
+
+ global_vars = ext_include_binary_get_global_scope(this_ext, denv->sbin);
+ global_scope = sieve_variable_scope_binary_get(global_vars);
+ vars = sieve_variable_scope_get_variables(global_scope, &var_count);
+
+ sieve_code_descend(denv);
+
+ for ( i = 0; i < count; i++ ) {
+ unsigned int index;
+
+ sieve_code_mark(denv);
+ if ( !sieve_binary_read_unsigned(denv->sblock, address, &index) ||
+ index >= var_count )
+ return FALSE;
+
+ sieve_code_dumpf(denv, "%d: VAR[%d]: '%s'", i, index, vars[index]->identifier);
+ }
+
+ return TRUE;
+}
+
+/*
+ * Execution
+ */
+
+static int opc_global_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ struct sieve_variable_scope_binary *global_vars;
+ struct sieve_variable_scope *global_scope;
+ struct sieve_variable_storage *storage;
+ struct sieve_variable * const *vars;
+ unsigned int var_count, count, i;
+
+ if ( !sieve_binary_read_unsigned(renv->sblock, address, &count) ) {
+ sieve_runtime_trace_error(renv,
+ "global: count operand invalid");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ global_vars = ext_include_binary_get_global_scope(this_ext, renv->sbin);
+ global_scope = sieve_variable_scope_binary_get(global_vars);
+ vars = sieve_variable_scope_get_variables(global_scope, &var_count);
+ storage = ext_include_interpreter_get_global_variables
+ (this_ext, renv->interp);
+
+ for ( i = 0; i < count; i++ ) {
+ unsigned int index;
+
+ if ( !sieve_binary_read_unsigned(renv->sblock, address, &index) ) {
+ sieve_runtime_trace_error(renv,
+ "global: variable index operand invalid");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if ( index >= var_count ) {
+ sieve_runtime_trace_error(renv,
+ "global: variable index %u is invalid in global storage (> %u)",
+ index, var_count);
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
+ "global: exporting variable '%s' [gvid: %u, vid: %u]",
+ vars[index]->identifier, i, index);
+
+ /* Make sure variable is initialized (export) */
+ (void)sieve_variable_get_modifiable(storage, index, NULL);
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/include/cmd-include.c b/pigeonhole/src/lib-sieve/plugins/include/cmd-include.c
new file mode 100644
index 0000000..92aefb4
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/include/cmd-include.c
@@ -0,0 +1,406 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+
+#include "sieve-common.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+#include "sieve-ast.h"
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-binary.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-include-common.h"
+#include "ext-include-binary.h"
+
+/*
+ * Include command
+ *
+ * Syntax:
+ * include [LOCATION] [":once"] [":optional"] <value: string>
+ *
+ * [LOCATION]:
+ * ":personal" / ":global"
+ */
+
+static bool cmd_include_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool cmd_include_pre_validate
+ (struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *cmd);
+static bool cmd_include_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool cmd_include_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+const struct sieve_command_def cmd_include = {
+ .identifier = "include",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = cmd_include_registered,
+ .pre_validate = cmd_include_pre_validate,
+ .validate = cmd_include_validate,
+ .generate = cmd_include_generate
+};
+
+/*
+ * Include operation
+ */
+
+static bool opc_include_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int opc_include_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def include_operation = {
+ .mnemonic = "include",
+ .ext_def = &include_extension,
+ .code = EXT_INCLUDE_OPERATION_INCLUDE,
+ .dump = opc_include_dump,
+ .execute = opc_include_execute
+};
+
+/*
+ * Context structures
+ */
+
+struct cmd_include_context_data {
+ enum ext_include_script_location location;
+
+ struct sieve_script *script;
+ enum ext_include_flags flags;
+
+ bool location_assigned:1;
+};
+
+/*
+ * Tagged arguments
+ */
+
+static bool cmd_include_validate_location_tag
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+static const struct sieve_argument_def include_personal_tag = {
+ .identifier = "personal",
+ .validate = cmd_include_validate_location_tag
+};
+
+static const struct sieve_argument_def include_global_tag = {
+ .identifier = "global",
+ .validate = cmd_include_validate_location_tag
+};
+
+static bool cmd_include_validate_boolean_tag
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+static const struct sieve_argument_def include_once_tag = {
+ .identifier = "once",
+ .validate = cmd_include_validate_boolean_tag
+};
+
+static const struct sieve_argument_def include_optional_tag = {
+ .identifier = "optional",
+ .validate = cmd_include_validate_boolean_tag
+};
+
+/*
+ * Tag validation
+ */
+
+static bool cmd_include_validate_location_tag
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct cmd_include_context_data *ctx_data =
+ (struct cmd_include_context_data *) cmd->data;
+
+ if ( ctx_data->location_assigned) {
+ sieve_argument_validate_error(valdtr, *arg,
+ "include: cannot use location tags ':personal' and ':global' "
+ "multiple times");
+ return FALSE;
+ }
+
+ if ( sieve_argument_is(*arg, include_personal_tag) )
+ ctx_data->location = EXT_INCLUDE_LOCATION_PERSONAL;
+ else if ( sieve_argument_is(*arg, include_global_tag) )
+ ctx_data->location = EXT_INCLUDE_LOCATION_GLOBAL;
+ else
+ return FALSE;
+
+ ctx_data->location_assigned = TRUE;
+
+ /* Delete this tag (for now) */
+ *arg = sieve_ast_arguments_detach(*arg, 1);
+
+ return TRUE;
+}
+
+static bool cmd_include_validate_boolean_tag
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct cmd_include_context_data *ctx_data =
+ (struct cmd_include_context_data *) cmd->data;
+
+ if ( sieve_argument_is(*arg, include_once_tag) )
+ ctx_data->flags |= EXT_INCLUDE_FLAG_ONCE;
+ else
+ ctx_data->flags |= EXT_INCLUDE_FLAG_OPTIONAL;
+
+ /* Delete this tag (for now) */
+ *arg = sieve_ast_arguments_detach(*arg, 1);
+
+ return TRUE;
+}
+
+/*
+ * Command registration
+ */
+
+static bool cmd_include_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_validator_register_tag(valdtr, cmd_reg, ext, &include_personal_tag, 0);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext, &include_global_tag, 0);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext, &include_once_tag, 0);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext, &include_optional_tag, 0);
+
+ return TRUE;
+}
+
+/*
+ * Command validation
+ */
+
+static bool cmd_include_pre_validate
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *cmd)
+{
+ struct cmd_include_context_data *ctx_data;
+
+ /* Assign context */
+ ctx_data = p_new(sieve_command_pool(cmd), struct cmd_include_context_data, 1);
+ ctx_data->location = EXT_INCLUDE_LOCATION_PERSONAL;
+ cmd->data = ctx_data;
+
+ return TRUE;
+}
+
+static bool cmd_include_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ const struct sieve_extension *this_ext = cmd->ext;
+ struct sieve_ast_argument *arg = cmd->first_positional;
+ struct cmd_include_context_data *ctx_data =
+ (struct cmd_include_context_data *) cmd->data;
+ struct sieve_storage *storage;
+ struct sieve_script *script;
+ const char *script_name;
+ enum sieve_error error = SIEVE_ERROR_NONE;
+ int ret;
+
+ /* Check argument */
+ if ( !sieve_validate_positional_argument
+ (valdtr, cmd, arg, "value", 1, SAAT_STRING) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, cmd, arg, FALSE) )
+ return FALSE;
+
+ /*
+ * Variables are not allowed.
+ */
+ if ( !sieve_argument_is_string_literal(arg) ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "the include command requires a constant string for its value argument");
+ return FALSE;
+ }
+
+ /* Find the script */
+
+ script_name = sieve_ast_argument_strc(arg);
+
+ if ( !sieve_script_name_is_valid(script_name) ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "include: invalid script name '%s'",
+ str_sanitize(script_name, 80));
+ return FALSE;
+ }
+
+ storage = ext_include_get_script_storage
+ (this_ext, ctx_data->location, script_name, &error);
+ if ( storage == NULL ) {
+ // FIXME: handle ':optional' in this case
+ if (error == SIEVE_ERROR_NOT_FOUND) {
+ sieve_argument_validate_error(valdtr, arg,
+ "include: %s location for included script `%s' is unavailable "
+ "(contact system administrator for more information)",
+ ext_include_script_location_name(ctx_data->location),
+ str_sanitize(script_name, 80));
+ } else {
+ sieve_argument_validate_error(valdtr, arg,
+ "include: failed to access %s location for included script `%s' "
+ "(contact system administrator for more information)",
+ ext_include_script_location_name(ctx_data->location),
+ str_sanitize(script_name, 80));
+ }
+ return FALSE;
+ }
+
+ /* Create script object */
+ script = sieve_storage_get_script
+ (storage, script_name, &error);
+ if ( script == NULL )
+ return FALSE;
+
+ ret = sieve_script_open(script, &error);
+ if ( ret < 0 ) {
+ if ( error != SIEVE_ERROR_NOT_FOUND ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "failed to access included %s script '%s': %s",
+ ext_include_script_location_name(ctx_data->location),
+ str_sanitize(script_name, 80),
+ sieve_script_get_last_error_lcase(script));
+ sieve_script_unref(&script);
+ return FALSE;
+
+ /* Not found */
+ } else {
+ enum sieve_compile_flags cpflags =
+ sieve_validator_compile_flags(valdtr);
+
+ if ( (ctx_data->flags & EXT_INCLUDE_FLAG_OPTIONAL) != 0 ) {
+ /* :optional */
+
+ } else if ( (cpflags & SIEVE_COMPILE_FLAG_UPLOADED) != 0 ) {
+ /* Script is being uploaded */
+ sieve_argument_validate_warning(valdtr, arg,
+ "included %s script '%s' does not exist (ignored during upload)",
+ ext_include_script_location_name(ctx_data->location),
+ str_sanitize(script_name, 80));
+ ctx_data->flags |= EXT_INCLUDE_FLAG_MISSING_AT_UPLOAD;
+
+ } else {
+ /* Should have existed */
+ sieve_argument_validate_error(valdtr, arg,
+ "included %s script '%s' does not exist",
+ ext_include_script_location_name(ctx_data->location),
+ str_sanitize(script_name, 80));
+ sieve_script_unref(&script);
+ return FALSE;
+ }
+ }
+ }
+
+ ext_include_ast_link_included_script(cmd->ext, cmd->ast_node->ast, script);
+ ctx_data->script = script;
+
+ (void)sieve_ast_arguments_detach(arg, 1);
+ return TRUE;
+}
+
+/*
+ * Code Generation
+ */
+
+static bool cmd_include_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ struct cmd_include_context_data *ctx_data =
+ (struct cmd_include_context_data *) cmd->data;
+ const struct ext_include_script_info *included;
+ int ret;
+
+ /* Compile (if necessary) and include the script into the binary.
+ * This yields the id of the binary block containing the compiled byte code.
+ */
+ if ( (ret=ext_include_generate_include
+ (cgenv, cmd, ctx_data->location, ctx_data->flags, ctx_data->script,
+ &included)) < 0 )
+ return FALSE;
+
+ if ( ret > 0 ) {
+ (void)sieve_operation_emit(cgenv->sblock, cmd->ext, &include_operation);
+ (void)sieve_binary_emit_unsigned(cgenv->sblock, included->id);
+ (void)sieve_binary_emit_byte(cgenv->sblock, ctx_data->flags);
+ }
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool opc_include_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ const struct ext_include_script_info *included;
+ struct ext_include_binary_context *binctx;
+ unsigned int include_id, flags;
+
+ sieve_code_dumpf(denv, "INCLUDE:");
+
+ sieve_code_mark(denv);
+ if ( !sieve_binary_read_unsigned(denv->sblock, address, &include_id) )
+ return FALSE;
+
+ if ( !sieve_binary_read_byte(denv->sblock, address, &flags) )
+ return FALSE;
+
+ binctx = ext_include_binary_get_context(denv->oprtn->ext, denv->sbin);
+ included = ext_include_binary_script_get_included(binctx, include_id);
+ if ( included == NULL )
+ return FALSE;
+
+ sieve_code_descend(denv);
+ sieve_code_dumpf(denv, "script: `%s' from %s %s%s[ID: %d, BLOCK: %d]",
+ sieve_script_name(included->script), sieve_script_location(included->script),
+ ((flags & EXT_INCLUDE_FLAG_ONCE) != 0 ? "(once) " : ""),
+ ((flags & EXT_INCLUDE_FLAG_OPTIONAL) != 0 ? "(optional) " : ""),
+ include_id, sieve_binary_block_get_id(included->block));
+
+ return TRUE;
+}
+
+/*
+ * Execution
+ */
+
+static int opc_include_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ unsigned int include_id, flags;
+
+ if ( !sieve_binary_read_unsigned(renv->sblock, address, &include_id) ) {
+ sieve_runtime_trace_error(renv, "invalid include-id operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if ( !sieve_binary_read_unsigned(renv->sblock, address, &flags) ) {
+ sieve_runtime_trace_error(renv, "invalid flags operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ return ext_include_execute_include
+ (renv, include_id, (enum ext_include_flags)flags);
+}
+
+
+
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/include/cmd-return.c b/pigeonhole/src/lib-sieve/plugins/include/cmd-return.c
new file mode 100644
index 0000000..65a156d
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/include/cmd-return.c
@@ -0,0 +1,71 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-code.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+#include "ext-include-common.h"
+
+/*
+ * Return command
+ *
+ * Syntax
+ * return
+ */
+
+static bool cmd_return_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
+
+const struct sieve_command_def cmd_return = {
+ .identifier = "return",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .generate = cmd_return_generate
+};
+
+/*
+ * Return operation
+ */
+
+static int opc_return_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def return_operation = {
+ .mnemonic = "RETURN",
+ .ext_def = &include_extension,
+ .code = EXT_INCLUDE_OPERATION_RETURN,
+ .execute = opc_return_execute
+};
+
+/*
+ * Code generation
+ */
+
+static bool cmd_return_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &return_operation);
+
+ return TRUE;
+}
+
+/*
+ * Execution
+ */
+
+static int opc_return_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address ATTR_UNUSED)
+{
+ ext_include_execute_return(renv);
+ return SIEVE_EXEC_OK;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/include/ext-include-binary.c b/pigeonhole/src/lib-sieve/plugins/include/ext-include-binary.c
new file mode 100644
index 0000000..3711c30
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/include/ext-include-binary.c
@@ -0,0 +1,492 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+#include "sieve-binary.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "sieve-ext-variables.h"
+
+#include "ext-include-common.h"
+#include "ext-include-limits.h"
+#include "ext-include-variables.h"
+#include "ext-include-binary.h"
+
+/*
+ * Forward declarations
+ */
+
+static bool ext_include_binary_pre_save
+ (const struct sieve_extension *ext, struct sieve_binary *sbin,
+ void *context, enum sieve_error *error_r);
+static bool ext_include_binary_open
+ (const struct sieve_extension *ext, struct sieve_binary *sbin,
+ void *context);
+static bool ext_include_binary_up_to_date
+ (const struct sieve_extension *ext, struct sieve_binary *sbin,
+ void *context, enum sieve_compile_flags cpflags);
+static void ext_include_binary_free
+ (const struct sieve_extension *ext, struct sieve_binary *sbin,
+ void *context);
+
+/*
+ * Binary include extension
+ */
+
+const struct sieve_binary_extension include_binary_ext = {
+ .extension = &include_extension,
+ .binary_pre_save = ext_include_binary_pre_save,
+ .binary_open = ext_include_binary_open,
+ .binary_free = ext_include_binary_free,
+ .binary_up_to_date = ext_include_binary_up_to_date
+};
+
+/*
+ * Binary context management
+ */
+
+struct ext_include_binary_context {
+ struct sieve_binary *binary;
+ struct sieve_binary_block *dependency_block;
+
+ HASH_TABLE(struct sieve_script *,
+ struct ext_include_script_info *) included_scripts;
+ ARRAY(struct ext_include_script_info *) include_index;
+
+ struct sieve_variable_scope_binary *global_vars;
+
+ bool outdated:1;
+};
+
+static struct ext_include_binary_context *ext_include_binary_create_context
+(const struct sieve_extension *this_ext, struct sieve_binary *sbin)
+{
+ pool_t pool = sieve_binary_pool(sbin);
+
+ struct ext_include_binary_context *ctx =
+ p_new(pool, struct ext_include_binary_context, 1);
+
+ ctx->binary = sbin;
+ hash_table_create(&ctx->included_scripts, pool, 0,
+ sieve_script_hash, sieve_script_cmp);
+ p_array_init(&ctx->include_index, pool, 128);
+
+ sieve_binary_extension_set(sbin, this_ext, &include_binary_ext, ctx);
+
+ return ctx;
+}
+
+struct ext_include_binary_context *ext_include_binary_get_context
+(const struct sieve_extension *this_ext, struct sieve_binary *sbin)
+{
+ struct ext_include_binary_context *ctx = (struct ext_include_binary_context *)
+ sieve_binary_extension_get_context(sbin, this_ext);
+
+ if ( ctx == NULL )
+ ctx = ext_include_binary_create_context(this_ext, sbin);
+
+ return ctx;
+}
+
+struct ext_include_binary_context *ext_include_binary_init
+(const struct sieve_extension *this_ext, struct sieve_binary *sbin,
+ struct sieve_ast *ast)
+{
+ struct ext_include_ast_context *ast_ctx =
+ ext_include_get_ast_context(this_ext, ast);
+ struct ext_include_binary_context *ctx;
+
+ /* Get/create our context from the binary we are working on */
+ ctx = ext_include_binary_get_context(this_ext, sbin);
+
+ /* Create dependency block */
+ if ( ctx->dependency_block == 0 )
+ ctx->dependency_block =
+ sieve_binary_extension_create_block(sbin, this_ext);
+
+ if ( ctx->global_vars == NULL ) {
+ ctx->global_vars =
+ sieve_variable_scope_binary_create(ast_ctx->global_vars);
+ sieve_variable_scope_binary_ref(ctx->global_vars);
+ }
+
+ return ctx;
+}
+
+/*
+ * Script inclusion
+ */
+
+struct ext_include_script_info *ext_include_binary_script_include
+(struct ext_include_binary_context *binctx,
+ enum ext_include_script_location location, enum ext_include_flags flags,
+ struct sieve_script *script, struct sieve_binary_block *inc_block)
+{
+ pool_t pool = sieve_binary_pool(binctx->binary);
+ struct ext_include_script_info *incscript;
+
+ incscript = p_new(pool, struct ext_include_script_info, 1);
+ incscript->id = array_count(&binctx->include_index)+1;
+ incscript->location = location;
+ incscript->flags = flags;
+ incscript->script = script;
+ incscript->block = inc_block;
+
+ /* Unreferenced on binary_free */
+ sieve_script_ref(script);
+
+ hash_table_insert(binctx->included_scripts, script, incscript);
+ array_append(&binctx->include_index, &incscript, 1);
+
+ return incscript;
+}
+
+struct ext_include_script_info *ext_include_binary_script_get_include_info
+(struct ext_include_binary_context *binctx, struct sieve_script *script)
+{
+ struct ext_include_script_info *incscript =
+ hash_table_lookup(binctx->included_scripts, script);
+
+ return incscript;
+}
+
+const struct ext_include_script_info *ext_include_binary_script_get_included
+(struct ext_include_binary_context *binctx, unsigned int include_id)
+{
+ if ( include_id > 0 &&
+ (include_id - 1) < array_count(&binctx->include_index) ) {
+ struct ext_include_script_info *const *sinfo =
+ array_idx(&binctx->include_index, include_id - 1);
+
+ return *sinfo;
+ }
+
+ return NULL;
+}
+
+const struct ext_include_script_info *ext_include_binary_script_get
+(struct ext_include_binary_context *binctx, struct sieve_script *script)
+{
+ return hash_table_lookup(binctx->included_scripts, script);
+}
+
+unsigned int ext_include_binary_script_get_count
+(struct ext_include_binary_context *binctx)
+{
+ return array_count(&binctx->include_index);
+}
+
+/*
+ * Variables
+ */
+
+struct sieve_variable_scope_binary *ext_include_binary_get_global_scope
+(const struct sieve_extension *this_ext, struct sieve_binary *sbin)
+{
+ struct ext_include_binary_context *binctx =
+ ext_include_binary_get_context(this_ext, sbin);
+
+ return binctx->global_vars;
+}
+
+/*
+ * Binary extension
+ */
+
+static bool ext_include_binary_pre_save
+(const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_binary *sbin ATTR_UNUSED, void *context,
+ enum sieve_error *error_r)
+{
+ struct ext_include_binary_context *binctx =
+ (struct ext_include_binary_context *) context;
+ struct ext_include_script_info *const *scripts;
+ struct sieve_binary_block *sblock = binctx->dependency_block;
+ unsigned int script_count, i;
+ bool result = TRUE;
+
+ sieve_binary_block_clear(sblock);
+
+ scripts = array_get(&binctx->include_index, &script_count);
+
+ sieve_binary_emit_unsigned(sblock, script_count);
+
+ for ( i = 0; i < script_count; i++ ) {
+ struct ext_include_script_info *incscript = scripts[i];
+
+ if ( incscript->block != NULL ) {
+ sieve_binary_emit_unsigned
+ (sblock, sieve_binary_block_get_id(incscript->block));
+ } else {
+ sieve_binary_emit_unsigned(sblock, 0);
+ }
+ sieve_binary_emit_byte(sblock, incscript->location);
+ sieve_binary_emit_cstring(sblock, sieve_script_name(incscript->script));
+ sieve_binary_emit_byte(sblock, incscript->flags);
+ sieve_script_binary_write_metadata(incscript->script, sblock);
+ }
+
+ result = ext_include_variables_save(sblock, binctx->global_vars, error_r);
+
+ return result;
+}
+
+static bool ext_include_binary_open
+(const struct sieve_extension *ext, struct sieve_binary *sbin, void *context)
+{
+ struct sieve_instance *svinst = ext->svinst;
+ struct ext_include_context *ext_ctx =
+ (struct ext_include_context *)ext->context;
+ struct ext_include_binary_context *binctx =
+ (struct ext_include_binary_context *) context;
+ struct sieve_binary_block *sblock;
+ unsigned int depcount, i, block_id;
+ sieve_size_t offset;
+
+ sblock = sieve_binary_extension_get_block(sbin, ext);
+ block_id = sieve_binary_block_get_id(sblock);
+
+ offset = 0;
+
+ if ( !sieve_binary_read_unsigned(sblock, &offset, &depcount) ) {
+ e_error(svinst->event,
+ "include: failed to read include count "
+ "for dependency block %d of binary %s", block_id,
+ sieve_binary_path(sbin));
+ return FALSE;
+ }
+
+ /* Check include limit */
+ if ( depcount > ext_ctx->max_includes ) {
+ e_error(svinst->event,
+ "include: binary %s includes too many scripts (%u > %u)",
+ sieve_binary_path(sbin), depcount, ext_ctx->max_includes);
+ return FALSE;
+ }
+
+ /* Read dependencies */
+ for ( i = 0; i < depcount; i++ ) {
+ unsigned int inc_block_id;
+ struct sieve_binary_block *inc_block = NULL;
+ unsigned int location, flags;
+ string_t *script_name;
+ struct sieve_storage *storage;
+ struct sieve_script *script;
+ enum sieve_error error;
+ int ret;
+
+ if (
+ !sieve_binary_read_unsigned(sblock, &offset, &inc_block_id) ||
+ !sieve_binary_read_byte(sblock, &offset, &location) ||
+ !sieve_binary_read_string(sblock, &offset, &script_name) ||
+ !sieve_binary_read_byte(sblock, &offset, &flags) ) {
+ /* Binary is corrupt, recompile */
+ e_error(svinst->event,
+ "include: failed to read included script "
+ "from dependency block %d of binary %s",
+ block_id, sieve_binary_path(sbin));
+ return FALSE;
+ }
+
+ if ( inc_block_id != 0 &&
+ (inc_block=sieve_binary_block_get(sbin, inc_block_id)) == NULL ) {
+ e_error(svinst->event,
+ "include: failed to find block %d for included script "
+ "from dependency block %d of binary %s",
+ inc_block_id, block_id,
+ sieve_binary_path(sbin));
+ return FALSE;
+ }
+
+ if ( location >= EXT_INCLUDE_LOCATION_INVALID ) {
+ /* Binary is corrupt, recompile */
+ e_error(svinst->event,
+ "include: dependency block %d of binary %s "
+ "uses invalid script location (id %d)",
+ block_id, sieve_binary_path(sbin), location);
+ return FALSE;
+ }
+
+ /* Can we find the script dependency ? */
+ storage = ext_include_get_script_storage
+ (ext, location, str_c(script_name), &error);
+ if ( storage == NULL ) {
+ /* No, recompile */
+ // FIXME: handle ':optional' in this case
+ return FALSE;
+ }
+
+ /* Can we open the script dependency ? */
+ script = sieve_storage_get_script
+ (storage, str_c(script_name), &error);
+ if ( script == NULL ) {
+ /* No, recompile */
+ return FALSE;
+ }
+ if ( sieve_script_open(script, &error) < 0 ) {
+ if ( error != SIEVE_ERROR_NOT_FOUND ) {
+ /* No, recompile */
+ return FALSE;
+ }
+
+ if ( (flags & EXT_INCLUDE_FLAG_OPTIONAL) == 0 ) {
+ /* Not supposed to be missing, recompile */
+ if ( svinst->debug ) {
+ e_debug(svinst->event, "include: "
+ "script '%s' included in binary %s is missing, "
+ "so recompile",
+ str_c(script_name),
+ sieve_binary_path(sbin));
+ }
+ return FALSE;
+ }
+
+ } else if (inc_block == NULL) {
+ /* Script exists, but it is missing from the binary, recompile no matter
+ * what.
+ */
+ if ( svinst->debug ) {
+ e_debug(svinst->event, "include: "
+ "script '%s' is missing in binary %s, but is now available, "
+ "so recompile", str_c(script_name), sieve_binary_path(sbin));
+ }
+ sieve_script_unref(&script);
+ return FALSE;
+ }
+
+ /* Can we read script metadata ? */
+ if ( (ret=sieve_script_binary_read_metadata
+ (script, sblock, &offset)) < 0 ) {
+ /* Binary is corrupt, recompile */
+ e_error(svinst->event, "include: "
+ "dependency block %d of binary %s "
+ "contains invalid script metadata for script %s",
+ block_id, sieve_binary_path(sbin),
+ sieve_script_location(script));
+ sieve_script_unref(&script);
+ return FALSE;
+ }
+
+ if ( ret == 0 )
+ binctx->outdated = TRUE;
+
+ (void)ext_include_binary_script_include
+ (binctx, location, flags, script, inc_block);
+
+ sieve_script_unref(&script);
+ }
+
+ if ( !ext_include_variables_load
+ (ext, sblock, &offset, &binctx->global_vars) )
+ return FALSE;
+
+ return TRUE;
+}
+
+static bool ext_include_binary_up_to_date
+(const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_binary *sbin ATTR_UNUSED, void *context,
+ enum sieve_compile_flags cpflags ATTR_UNUSED)
+{
+ struct ext_include_binary_context *binctx =
+ (struct ext_include_binary_context *) context;
+
+ return !binctx->outdated;
+}
+
+static void ext_include_binary_free
+(const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_binary *sbin ATTR_UNUSED, void *context)
+{
+ struct ext_include_binary_context *binctx =
+ (struct ext_include_binary_context *) context;
+ struct hash_iterate_context *hctx;
+ struct sieve_script *script;
+ struct ext_include_script_info *incscript;
+
+ /* Release references to all included script objects */
+ hctx = hash_table_iterate_init(binctx->included_scripts);
+ while ( hash_table_iterate
+ (hctx, binctx->included_scripts, &script, &incscript) )
+ sieve_script_unref(&incscript->script);
+ hash_table_iterate_deinit(&hctx);
+
+ hash_table_destroy(&binctx->included_scripts);
+
+ if ( binctx->global_vars != NULL )
+ sieve_variable_scope_binary_unref(&binctx->global_vars);
+}
+
+/*
+ * Dumping the binary
+ */
+
+bool ext_include_binary_dump
+(const struct sieve_extension *ext, struct sieve_dumptime_env *denv)
+{
+ struct sieve_binary *sbin = denv->sbin;
+ struct ext_include_binary_context *binctx =
+ ext_include_binary_get_context(ext, sbin);
+ struct hash_iterate_context *hctx;
+ struct sieve_script *script;
+ struct ext_include_script_info *incscript;
+
+ if ( !ext_include_variables_dump(denv, binctx->global_vars) )
+ return FALSE;
+
+ hctx = hash_table_iterate_init(binctx->included_scripts);
+ while ( hash_table_iterate
+ (hctx, binctx->included_scripts, &script, &incscript) ) {
+
+ if ( incscript->block == NULL ) {
+ sieve_binary_dump_sectionf(denv, "Included %s script '%s' (MISSING)",
+ ext_include_script_location_name(incscript->location),
+ sieve_script_name(incscript->script));
+
+ } else {
+ unsigned int block_id = sieve_binary_block_get_id(incscript->block);
+
+ sieve_binary_dump_sectionf(denv, "Included %s script '%s' (block: %d)",
+ ext_include_script_location_name(incscript->location),
+ sieve_script_name(incscript->script), block_id);
+
+ denv->sblock = incscript->block;
+ denv->cdumper = sieve_code_dumper_create(denv);
+
+ if ( denv->cdumper == NULL )
+ return FALSE;
+
+ sieve_code_dumper_run(denv->cdumper);
+ sieve_code_dumper_free(&(denv->cdumper));
+ }
+ }
+ hash_table_iterate_deinit(&hctx);
+
+ return TRUE;
+}
+
+bool ext_include_code_dump
+(const struct sieve_extension *ext, const struct sieve_dumptime_env *denv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ struct sieve_binary *sbin = denv->sbin;
+ struct ext_include_binary_context *binctx =
+ ext_include_binary_get_context(ext, sbin);
+ struct ext_include_context *ectx = ext_include_get_context(ext);
+
+ sieve_ext_variables_dump_set_scope
+ (ectx->var_ext, denv, ext,
+ sieve_variable_scope_binary_get(binctx->global_vars));
+
+ return TRUE;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/include/ext-include-binary.h b/pigeonhole/src/lib-sieve/plugins/include/ext-include-binary.h
new file mode 100644
index 0000000..066df2f
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/include/ext-include-binary.h
@@ -0,0 +1,64 @@
+#ifndef EXT_INCLUDE_BINARY_H
+#define EXT_INCLUDE_BINARY_H
+
+#include "sieve-common.h"
+
+/*
+ * Binary context management
+ */
+
+struct ext_include_binary_context;
+
+struct ext_include_binary_context *ext_include_binary_init
+ (const struct sieve_extension *this_ext, struct sieve_binary *sbin,
+ struct sieve_ast *ast);
+struct ext_include_binary_context *ext_include_binary_get_context
+ (const struct sieve_extension *this_ext, struct sieve_binary *sbin);
+
+/*
+ * Variables
+ */
+
+struct sieve_variable_scope_binary *ext_include_binary_get_global_scope
+ (const struct sieve_extension *this_ext, struct sieve_binary *sbin);
+
+/*
+ * Including scripts
+ */
+
+struct ext_include_script_info {
+ unsigned int id;
+
+ struct sieve_script *script;
+ enum ext_include_flags flags;
+ enum ext_include_script_location location;
+
+ struct sieve_binary_block *block;
+};
+
+struct ext_include_script_info *ext_include_binary_script_include
+ (struct ext_include_binary_context *binctx,
+ enum ext_include_script_location location, enum ext_include_flags flags,
+ struct sieve_script *script, struct sieve_binary_block *inc_block);
+struct ext_include_script_info *ext_include_binary_script_get_include_info
+ (struct ext_include_binary_context *binctx, struct sieve_script *script);
+
+const struct ext_include_script_info *ext_include_binary_script_get_included
+ (struct ext_include_binary_context *binctx, unsigned int include_id);
+const struct ext_include_script_info *ext_include_binary_script_get
+ (struct ext_include_binary_context *binctx, struct sieve_script *script);
+unsigned int ext_include_binary_script_get_count
+ (struct ext_include_binary_context *binctx);
+
+/*
+ * Dumping the binary
+ */
+
+bool ext_include_binary_dump
+ (const struct sieve_extension *ext, struct sieve_dumptime_env *denv);
+bool ext_include_code_dump
+ (const struct sieve_extension *ext, const struct sieve_dumptime_env *denv,
+ sieve_size_t *address ATTR_UNUSED);
+
+#endif
+
diff --git a/pigeonhole/src/lib-sieve/plugins/include/ext-include-common.c b/pigeonhole/src/lib-sieve/plugins/include/ext-include-common.c
new file mode 100644
index 0000000..7af3f00
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/include/ext-include-common.c
@@ -0,0 +1,892 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "str-sanitize.h"
+#include "home-expand.h"
+
+#include "sieve-common.h"
+#include "sieve-settings.h"
+#include "sieve-error.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+#include "sieve-ast.h"
+#include "sieve-binary.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+#include "ext-include-common.h"
+#include "ext-include-limits.h"
+#include "ext-include-binary.h"
+#include "ext-include-variables.h"
+
+
+/*
+ * Forward declarations
+ */
+
+/* Generator context */
+
+struct ext_include_generator_context {
+ unsigned int nesting_depth;
+ struct sieve_script *script;
+ struct ext_include_generator_context *parent;
+};
+
+static inline struct ext_include_generator_context *
+ext_include_get_generator_context(const struct sieve_extension *ext_this,
+ struct sieve_generator *gentr);
+
+/* Interpreter context */
+
+struct ext_include_interpreter_global {
+ ARRAY(struct sieve_script *) included_scripts;
+
+ struct sieve_variable_scope_binary *var_scope;
+ struct sieve_variable_storage *var_storage;
+};
+
+struct ext_include_interpreter_context {
+ struct ext_include_interpreter_context *parent;
+ struct ext_include_interpreter_global *global;
+
+ struct sieve_interpreter *interp;
+ pool_t pool;
+
+ unsigned int nesting_depth;
+
+ struct sieve_script *script;
+ const struct ext_include_script_info *script_info;
+
+ const struct ext_include_script_info *include;
+ bool returned;
+};
+
+/*
+ * Extension configuration
+ */
+
+/* Extension hooks */
+
+bool ext_include_load(const struct sieve_extension *ext, void **context)
+{
+ struct sieve_instance *svinst = ext->svinst;
+ struct ext_include_context *ctx;
+ const char *location;
+ unsigned long long int uint_setting;
+
+ if (*context != NULL)
+ ext_include_unload(ext);
+
+ ctx = i_new(struct ext_include_context, 1);
+
+ /* Get location for :global scripts */
+ location = sieve_setting_get(svinst, "sieve_global");
+ if (location == NULL)
+ location = sieve_setting_get(svinst, "sieve_global_dir");
+
+ if (location == NULL) {
+ e_debug(svinst->event, "include: "
+ "sieve_global is not set; "
+ "it is currently not possible to include `:global' scripts.");
+ }
+
+ ctx->global_location = i_strdup(location);
+
+ /* Get limits */
+ ctx->max_nesting_depth = EXT_INCLUDE_DEFAULT_MAX_NESTING_DEPTH;
+ ctx->max_includes = EXT_INCLUDE_DEFAULT_MAX_INCLUDES;
+
+ if (sieve_setting_get_uint_value(
+ svinst, "sieve_include_max_nesting_depth", &uint_setting))
+ ctx->max_nesting_depth = (unsigned int)uint_setting;
+ if (sieve_setting_get_uint_value(
+ svinst, "sieve_include_max_includes", &uint_setting))
+ ctx->max_includes = (unsigned int)uint_setting;
+
+ /* Extension dependencies */
+ ctx->var_ext = sieve_ext_variables_get_extension(ext->svinst);
+
+ *context = (void *)ctx;
+ return TRUE;
+}
+
+void ext_include_unload(const struct sieve_extension *ext)
+{
+ struct ext_include_context *ctx =
+ (struct ext_include_context *)ext->context;
+
+ if (ctx->global_storage != NULL)
+ sieve_storage_unref(&ctx->global_storage);
+ if (ctx->personal_storage != NULL)
+ sieve_storage_unref(&ctx->personal_storage);
+
+ i_free(ctx->global_location);
+ i_free(ctx);
+}
+
+/*
+ * Script access
+ */
+
+struct sieve_storage *
+ext_include_get_script_storage(const struct sieve_extension *ext,
+ enum ext_include_script_location location,
+ const char *script_name,
+ enum sieve_error *error_r)
+{
+ struct sieve_instance *svinst = ext->svinst;
+ struct ext_include_context *ctx =
+ (struct ext_include_context *)ext->context;
+
+ switch (location) {
+ case EXT_INCLUDE_LOCATION_PERSONAL:
+ if (ctx->personal_storage == NULL) {
+ ctx->personal_storage =
+ sieve_storage_create_main(svinst, NULL, 0,
+ error_r);
+ }
+ return ctx->personal_storage;
+ case EXT_INCLUDE_LOCATION_GLOBAL:
+ if (ctx->global_location == NULL) {
+ e_info(svinst->event, "include: "
+ "sieve_global is unconfigured; "
+ "include of `:global' script `%s' is therefore not possible",
+ str_sanitize(script_name, 80));
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NOT_FOUND;
+ return NULL;
+ }
+ if (ctx->global_storage == NULL) {
+ ctx->global_storage = sieve_storage_create(
+ svinst, ctx->global_location, 0, error_r);
+ }
+ return ctx->global_storage;
+ default:
+ break;
+ }
+
+ i_unreached();
+ return NULL;
+}
+
+/*
+ * AST context management
+ */
+
+static void
+ext_include_ast_free(const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_ast *ast ATTR_UNUSED, void *context)
+{
+ struct ext_include_ast_context *actx =
+ (struct ext_include_ast_context *)context;
+ struct sieve_script **scripts;
+ unsigned int count, i;
+
+ /* Unreference included scripts */
+ scripts = array_get_modifiable(&actx->included_scripts, &count);
+ for (i = 0; i < count; i++) {
+ sieve_script_unref(&scripts[i]);
+ }
+
+ /* Unreference variable scopes */
+ if (actx->global_vars != NULL)
+ sieve_variable_scope_unref(&actx->global_vars);
+}
+
+static const struct sieve_ast_extension include_ast_extension = {
+ &include_extension,
+ ext_include_ast_free
+};
+
+struct ext_include_ast_context *
+ext_include_create_ast_context(const struct sieve_extension *this_ext,
+ struct sieve_ast *ast, struct sieve_ast *parent)
+{
+ struct ext_include_ast_context *actx;
+
+ pool_t pool = sieve_ast_pool(ast);
+ actx = p_new(pool, struct ext_include_ast_context, 1);
+ p_array_init(&actx->included_scripts, pool, 32);
+
+ if (parent != NULL) {
+ struct ext_include_ast_context *parent_ctx =
+ (struct ext_include_ast_context *)
+ sieve_ast_extension_get_context(parent, this_ext);
+
+ actx->global_vars = parent_ctx->global_vars;
+ i_assert(actx->global_vars != NULL);
+
+ sieve_variable_scope_ref(actx->global_vars);
+ } else {
+ struct ext_include_context *ectx =
+ ext_include_get_context(this_ext);
+
+ actx->global_vars = sieve_variable_scope_create(
+ this_ext->svinst, ectx->var_ext, this_ext);
+ }
+
+ sieve_ast_extension_register(ast, this_ext, &include_ast_extension,
+ (void *)actx);
+ return actx;
+}
+
+struct ext_include_ast_context *
+ext_include_get_ast_context(const struct sieve_extension *this_ext,
+ struct sieve_ast *ast)
+{
+ struct ext_include_ast_context *actx =
+ (struct ext_include_ast_context *)
+ sieve_ast_extension_get_context(ast, this_ext);
+
+ if (actx != NULL)
+ return actx;
+ return ext_include_create_ast_context(this_ext, ast, NULL);
+}
+
+void ext_include_ast_link_included_script(
+ const struct sieve_extension *this_ext, struct sieve_ast *ast,
+ struct sieve_script *script)
+{
+ struct ext_include_ast_context *actx =
+ ext_include_get_ast_context(this_ext, ast);
+
+ array_append(&actx->included_scripts, &script, 1);
+}
+
+bool ext_include_validator_have_variables(
+ const struct sieve_extension *this_ext, struct sieve_validator *valdtr)
+{
+ struct ext_include_context *ectx = ext_include_get_context(this_ext);
+
+ return sieve_ext_variables_is_active(ectx->var_ext, valdtr);
+}
+
+/*
+ * Generator context management
+ */
+
+static struct ext_include_generator_context *
+ext_include_create_generator_context(
+ struct sieve_generator *gentr,
+ struct ext_include_generator_context *parent,
+ struct sieve_script *script)
+{
+ struct ext_include_generator_context *ctx;
+
+ pool_t pool = sieve_generator_pool(gentr);
+ ctx = p_new(pool, struct ext_include_generator_context, 1);
+ ctx->parent = parent;
+ ctx->script = script;
+ if (parent == NULL)
+ ctx->nesting_depth = 0;
+ else
+ ctx->nesting_depth = parent->nesting_depth + 1;
+
+ return ctx;
+}
+
+static inline struct ext_include_generator_context *
+ext_include_get_generator_context(const struct sieve_extension *this_ext,
+ struct sieve_generator *gentr)
+{
+ return (struct ext_include_generator_context *)
+ sieve_generator_extension_get_context(gentr, this_ext);
+}
+
+static inline void
+ext_include_initialize_generator_context(
+ const struct sieve_extension *this_ext, struct sieve_generator *gentr,
+ struct ext_include_generator_context *parent,
+ struct sieve_script *script)
+{
+ sieve_generator_extension_set_context(
+ gentr, this_ext,
+ ext_include_create_generator_context(gentr, parent, script));
+}
+
+void ext_include_register_generator_context(
+ const struct sieve_extension *this_ext,
+ const struct sieve_codegen_env *cgenv)
+{
+ struct ext_include_generator_context *ctx =
+ ext_include_get_generator_context(this_ext, cgenv->gentr);
+
+ /* Initialize generator context if necessary */
+ if (ctx == NULL) {
+ ctx = ext_include_create_generator_context(
+ cgenv->gentr, NULL, cgenv->script);
+
+ sieve_generator_extension_set_context(
+ cgenv->gentr, this_ext, (void *)ctx);
+ }
+
+ /* Initialize ast context if necessary */
+ (void)ext_include_get_ast_context(this_ext, cgenv->ast);
+ (void)ext_include_binary_init(this_ext, cgenv->sbin, cgenv->ast);
+}
+
+/*
+ * Runtime initialization
+ */
+
+static int
+ext_include_runtime_init(const struct sieve_extension *this_ext,
+ const struct sieve_runtime_env *renv,
+ void *context, bool deferred ATTR_UNUSED)
+{
+ struct ext_include_interpreter_context *ctx =
+ (struct ext_include_interpreter_context *)context;
+ struct ext_include_context *ectx = ext_include_get_context(this_ext);
+
+ if (ctx->parent == NULL) {
+ ctx->global = p_new(ctx->pool,
+ struct ext_include_interpreter_global, 1);
+ p_array_init(&ctx->global->included_scripts, ctx->pool, 10);
+
+ ctx->global->var_scope =
+ ext_include_binary_get_global_scope(
+ this_ext, renv->sbin);
+ ctx->global->var_storage =
+ sieve_variable_storage_create(ectx->var_ext, ctx->pool,
+ ctx->global->var_scope);
+ } else {
+ ctx->global = ctx->parent->global;
+ }
+
+ sieve_ext_variables_runtime_set_storage(ectx->var_ext, renv, this_ext,
+ ctx->global->var_storage);
+ return SIEVE_EXEC_OK;
+}
+
+static struct sieve_interpreter_extension include_interpreter_extension = {
+ .ext_def = &include_extension,
+ .run = ext_include_runtime_init
+};
+
+/*
+ * Interpreter context management
+ */
+
+static struct ext_include_interpreter_context *
+ext_include_interpreter_context_create(
+ struct sieve_interpreter *interp,
+ struct ext_include_interpreter_context *parent,
+ struct sieve_script *script,
+ const struct ext_include_script_info *sinfo)
+{
+ struct ext_include_interpreter_context *ctx;
+
+ pool_t pool = sieve_interpreter_pool(interp);
+ ctx = p_new(pool, struct ext_include_interpreter_context, 1);
+ ctx->pool = pool;
+ ctx->parent = parent;
+ ctx->interp = interp;
+ ctx->script = script;
+ ctx->script_info = sinfo;
+
+ if (parent == NULL)
+ ctx->nesting_depth = 0;
+ else
+ ctx->nesting_depth = parent->nesting_depth + 1;
+ return ctx;
+}
+
+static inline struct ext_include_interpreter_context *
+ext_include_get_interpreter_context(const struct sieve_extension *this_ext,
+ struct sieve_interpreter *interp)
+{
+ return (struct ext_include_interpreter_context *)
+ sieve_interpreter_extension_get_context(interp, this_ext);
+}
+
+static inline struct ext_include_interpreter_context *
+ext_include_interpreter_context_init_child(
+ const struct sieve_extension *this_ext,
+ struct sieve_interpreter *interp,
+ struct ext_include_interpreter_context *parent,
+ struct sieve_script *script,
+ const struct ext_include_script_info *sinfo)
+{
+ struct ext_include_interpreter_context *ctx =
+ ext_include_interpreter_context_create(interp, parent,
+ script, sinfo);
+
+ sieve_interpreter_extension_register(interp, this_ext,
+ &include_interpreter_extension,
+ ctx);
+ return ctx;
+}
+
+void ext_include_interpreter_context_init(
+ const struct sieve_extension *this_ext,
+ struct sieve_interpreter *interp)
+{
+ struct ext_include_interpreter_context *ctx =
+ ext_include_get_interpreter_context(this_ext, interp);
+
+ /* Is this is the top-level interpreter ? */
+ if (ctx == NULL) {
+ struct sieve_script *script;
+
+ /* Initialize top context */
+ script = sieve_interpreter_script(interp);
+ ctx = ext_include_interpreter_context_create(interp, NULL,
+ script, NULL);
+
+ sieve_interpreter_extension_register(
+ interp, this_ext, &include_interpreter_extension,
+ (void *)ctx);
+ }
+}
+
+struct sieve_variable_storage *
+ext_include_interpreter_get_global_variables(
+ const struct sieve_extension *this_ext,
+ struct sieve_interpreter *interp)
+{
+ struct ext_include_interpreter_context *ctx =
+ ext_include_get_interpreter_context(this_ext, interp);
+
+ return ctx->global->var_storage;
+}
+
+/*
+ * Including a script during code generation
+ */
+
+int ext_include_generate_include(
+ const struct sieve_codegen_env *cgenv, struct sieve_command *cmd,
+ enum ext_include_script_location location, enum ext_include_flags flags,
+ struct sieve_script *script,
+ const struct ext_include_script_info **included_r)
+{
+ const struct sieve_extension *this_ext = cmd->ext;
+ struct ext_include_context *ext_ctx =
+ (struct ext_include_context *)this_ext->context;
+ int result = 1;
+ struct sieve_ast *ast;
+ struct sieve_binary *sbin = cgenv->sbin;
+ struct sieve_generator *gentr = cgenv->gentr;
+ struct ext_include_binary_context *binctx;
+ struct sieve_generator *subgentr;
+ struct ext_include_generator_context *ctx =
+ ext_include_get_generator_context(this_ext, gentr);
+ struct ext_include_generator_context *pctx;
+ struct sieve_error_handler *ehandler =
+ sieve_generator_error_handler(gentr);
+ struct ext_include_script_info *included;
+
+ *included_r = NULL;
+
+ /* Just to be sure: do not include more scripts when errors have occured
+ already.
+ */
+ if (sieve_get_errors(ehandler) > 0)
+ return -1;
+
+ /* Limit nesting level */
+ if (ctx->nesting_depth >= ext_ctx->max_nesting_depth) {
+ sieve_command_generate_error(
+ gentr, cmd,
+ "cannot nest includes deeper than %d levels",
+ ext_ctx->max_nesting_depth);
+ return -1;
+ }
+
+ /* Check for circular include */
+ if ((flags & EXT_INCLUDE_FLAG_ONCE) == 0) {
+ pctx = ctx;
+ while (pctx != NULL) {
+ if (sieve_script_equals(pctx->script, script)) {
+ /* Just drop circular include when uploading
+ inactive script; not an error
+ */
+ if ((cgenv->flags & SIEVE_COMPILE_FLAG_UPLOADED) != 0 &&
+ (cgenv->flags & SIEVE_COMPILE_FLAG_ACTIVATED) == 0) {
+ sieve_command_generate_warning(
+ gentr, cmd,
+ "circular include (ignored during upload)");
+ return 0;
+ }
+
+ sieve_command_generate_error(gentr, cmd,
+ "circular include");
+ return -1;
+ }
+
+ pctx = pctx->parent;
+ }
+ }
+
+ /* Get binary context */
+ binctx = ext_include_binary_init(this_ext, sbin, cgenv->ast);
+
+ /* Is the script already compiled into the current binary? */
+ included = ext_include_binary_script_get_include_info(binctx, script);
+ if (included != NULL) {
+ /* Yes, only update flags */
+ if ((flags & EXT_INCLUDE_FLAG_OPTIONAL) == 0)
+ included->flags &= ENUM_NEGATE(EXT_INCLUDE_FLAG_OPTIONAL);
+ if ((flags & EXT_INCLUDE_FLAG_ONCE) == 0)
+ included->flags &= ENUM_NEGATE(EXT_INCLUDE_FLAG_ONCE);
+ } else {
+ const char *script_name = sieve_script_name(script);
+ enum sieve_compile_flags cpflags = cgenv->flags;
+
+ /* No, include new script */
+
+ /* Check whether include limit is exceeded */
+ if (ext_include_binary_script_get_count(binctx) >=
+ ext_ctx->max_includes) {
+ sieve_command_generate_error(
+ gentr, cmd, "failed to include script '%s': "
+ "no more than %u includes allowed",
+ str_sanitize(script_name, 80),
+ ext_ctx->max_includes);
+ return -1;
+ }
+
+ /* Allocate a new block in the binary and mark the script as
+ included. */
+ if (!sieve_script_is_open(script)) {
+ /* Just making an empty entry to mark a missing script
+ */
+ i_assert((flags & EXT_INCLUDE_FLAG_MISSING_AT_UPLOAD) != 0 ||
+ (flags & EXT_INCLUDE_FLAG_OPTIONAL) != 0);
+ included = ext_include_binary_script_include(
+ binctx, location, flags, script, NULL);
+ result = 0;
+
+ } else {
+ struct sieve_binary_block *inc_block =
+ sieve_binary_block_create(sbin);
+
+ /* Real include */
+ included = ext_include_binary_script_include(
+ binctx, location, flags, script, inc_block);
+
+ /* Parse */
+ if ((ast = sieve_parse(script, ehandler,
+ NULL)) == NULL) {
+ sieve_command_generate_error(
+ gentr, cmd,
+ "failed to parse included script '%s'",
+ str_sanitize(script_name, 80));
+ return -1;
+ }
+
+ /* Included scripts inherit global variable scope */
+ (void)ext_include_create_ast_context(
+ this_ext, ast, cmd->ast_node->ast);
+
+ if (location == EXT_INCLUDE_LOCATION_GLOBAL) {
+ cpflags &=
+ ENUM_NEGATE(SIEVE_EXECUTE_FLAG_NOGLOBAL);
+ } else {
+ cpflags |= SIEVE_EXECUTE_FLAG_NOGLOBAL;
+ }
+
+ /* Validate */
+ if (!sieve_validate(ast, ehandler, cpflags, NULL)) {
+ sieve_command_generate_error(
+ gentr, cmd,
+ "failed to validate included script '%s'",
+ str_sanitize(script_name, 80));
+ sieve_ast_unref(&ast);
+ return -1;
+ }
+
+ /* Generate
+
+ FIXME: It might not be a good idea to recurse code
+ generation for included scripts.
+ */
+ subgentr = sieve_generator_create(ast, ehandler, cpflags);
+ ext_include_initialize_generator_context(
+ cmd->ext, subgentr, ctx, script);
+
+ if (sieve_generator_run(subgentr, &inc_block) == NULL) {
+ sieve_command_generate_error(
+ gentr, cmd,
+ "failed to generate code for included script '%s'",
+ str_sanitize(script_name, 80));
+ result = -1;
+ }
+
+ sieve_generator_free(&subgentr);
+
+ /* Cleanup */
+ sieve_ast_unref(&ast);
+ }
+ }
+
+ if (result > 0)
+ *included_r = included;
+ return result;
+}
+
+/*
+ * Executing an included script during interpretation
+ */
+
+static bool
+ext_include_runtime_check_circular(
+ struct ext_include_interpreter_context *ctx,
+ const struct ext_include_script_info *include)
+{
+ struct ext_include_interpreter_context *pctx;
+
+ pctx = ctx;
+ while (pctx != NULL) {
+
+ if (sieve_script_equals(include->script, pctx->script))
+ return TRUE;
+
+ pctx = pctx->parent;
+ }
+
+ return FALSE;
+}
+
+static bool
+ext_include_runtime_include_mark(struct ext_include_interpreter_context *ctx,
+ const struct ext_include_script_info *include,
+ bool once)
+{
+ struct sieve_script *const *includes;
+ unsigned int count, i;
+
+ includes = array_get(&ctx->global->included_scripts, &count);
+ for (i = 0; i < count; i++) {
+ if (sieve_script_equals(include->script, includes[i]))
+ return (!once);
+ }
+
+ array_append(&ctx->global->included_scripts, &include->script, 1);
+ return TRUE;
+}
+
+int ext_include_execute_include(const struct sieve_runtime_env *renv,
+ unsigned int include_id,
+ enum ext_include_flags flags)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ int result = SIEVE_EXEC_OK;
+ struct ext_include_interpreter_context *ctx;
+ const struct ext_include_script_info *included;
+ struct ext_include_binary_context *binctx =
+ ext_include_binary_get_context(this_ext, renv->sbin);
+ bool once = ((flags & EXT_INCLUDE_FLAG_ONCE) != 0);
+ unsigned int block_id;
+
+ /* Check for invalid include id (== corrupt binary) */
+ included = ext_include_binary_script_get_included(binctx, include_id);
+ if (included == NULL) {
+ sieve_runtime_trace_error(
+ renv, "include: include id %d is invalid", include_id);
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ ctx = ext_include_get_interpreter_context(this_ext, renv->interp);
+ block_id = sieve_binary_block_get_id(included->block);
+
+ /* If :once modifier is specified, check for duplicate include */
+ if (ext_include_runtime_include_mark(ctx, included, once)) {
+ sieve_runtime_trace(
+ renv, SIEVE_TRLVL_NONE,
+ "include: start script '%s' [inc id: %d, block: %d]",
+ sieve_script_name(included->script),
+ include_id, block_id);
+ } else {
+ /* skip */
+ sieve_runtime_trace(
+ renv, SIEVE_TRLVL_NONE,
+ "include: skipped include for script '%s' "
+ "[inc id: %d, block: %d]; already run once",
+ sieve_script_name(included->script),
+ include_id, block_id);
+ return result;
+ }
+
+ /* Check circular include during interpretation as well.
+ * Let's not trust binaries.
+ */
+ if (ext_include_runtime_check_circular(ctx, included)) {
+ sieve_runtime_trace_error(renv,
+ "include: circular include of script '%s' "
+ "[inc id: %d, block: %d]",
+ sieve_script_name(included->script),
+ include_id, block_id);
+
+ /* Situation has no valid way to emerge at runtime */
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if (ctx->parent == NULL) {
+ struct ext_include_interpreter_context *curctx = NULL;
+ struct sieve_error_handler *ehandler = renv->ehandler;
+ struct sieve_interpreter *subinterp;
+ bool interrupted = FALSE;
+
+ /* We are the top-level interpreter instance */
+ if (result == SIEVE_EXEC_OK) {
+ struct sieve_execute_env eenv_new = *eenv;
+
+ if (included->location != EXT_INCLUDE_LOCATION_GLOBAL)
+ eenv_new.flags |= SIEVE_EXECUTE_FLAG_NOGLOBAL;
+ else {
+ eenv_new.flags &=
+ ENUM_NEGATE(SIEVE_EXECUTE_FLAG_NOGLOBAL);
+ }
+
+ /* Create interpreter for top-level included script
+ (first sub-interpreter)
+ */
+ subinterp = sieve_interpreter_create_for_block(
+ included->block, included->script, renv->interp,
+ &eenv_new, ehandler);
+ if (subinterp != NULL) {
+ curctx = ext_include_interpreter_context_init_child(
+ this_ext, subinterp, ctx, included->script,
+ included);
+
+ /* Activate and start the top-level included script */
+ result = sieve_interpreter_start(
+ subinterp, renv->result, &interrupted);
+ } else {
+ result = SIEVE_EXEC_BIN_CORRUPT;
+ }
+ }
+
+ /* Included scripts can have includes of their own. This is not
+ implemented recursively. Rather, the sub-interpreter
+ interrupts and defers the include to the top-level
+ interpreter, which is here. */
+ if (result == SIEVE_EXEC_OK && interrupted &&
+ !curctx->returned) {
+ while (result == SIEVE_EXEC_OK) {
+ if (((interrupted && curctx->returned) ||
+ (!interrupted)) &&
+ curctx->parent != NULL) {
+ const struct ext_include_script_info *ended_script =
+ curctx->script_info;
+
+ /* Sub-interpreter ended or executed
+ return */
+
+ /* Ascend interpreter stack */
+ curctx = curctx->parent;
+ sieve_interpreter_free(&subinterp);
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_NONE,
+ "include: script '%s' ended "
+ "[inc id: %d, block: %d]",
+ sieve_script_name(ended_script->script),
+ ended_script->id,
+ sieve_binary_block_get_id(ended_script->block));
+
+ /* This is the top-most sub-interpreter,
+ bail out */
+ if (curctx->parent == NULL)
+ break;
+
+ subinterp = curctx->interp;
+
+ /* Continue parent */
+ curctx->include = NULL;
+ curctx->returned = FALSE;
+
+ result = sieve_interpreter_continue(
+ subinterp, &interrupted);
+ } else {
+ if (curctx->include != NULL) {
+ /* Sub-include requested */
+
+ if (result == SIEVE_EXEC_OK) {
+ struct sieve_execute_env eenv_new = *eenv;
+
+ if (curctx->include->location != EXT_INCLUDE_LOCATION_GLOBAL)
+ eenv_new.flags |= SIEVE_EXECUTE_FLAG_NOGLOBAL;
+ else {
+ eenv_new.flags &=
+ ENUM_NEGATE(SIEVE_EXECUTE_FLAG_NOGLOBAL);
+ }
+
+ /* Create sub-interpreter */
+ subinterp = sieve_interpreter_create_for_block(
+ curctx->include->block, curctx->include->script,
+ curctx->interp, &eenv_new, ehandler);
+ if (subinterp != NULL) {
+ curctx = ext_include_interpreter_context_init_child(
+ this_ext, subinterp, curctx,
+ curctx->include->script, curctx->include);
+
+ /* Start the sub-include's interpreter */
+ curctx->include = NULL;
+ curctx->returned = FALSE;
+ result = sieve_interpreter_start(
+ subinterp, renv->result, &interrupted);
+ } else {
+ result = SIEVE_EXEC_BIN_CORRUPT;
+ }
+ }
+ } else {
+ /* Sub-interpreter was interrupted outside
+ this extension, probably stop command was
+ executed. Generate an interrupt ourselves,
+ ending all script execution. */
+ sieve_interpreter_interrupt(renv->interp);
+ break;
+ }
+ }
+ }
+ }
+
+ /* Free any sub-interpreters that might still be active */
+ while (curctx != NULL && curctx->parent != NULL) {
+ struct ext_include_interpreter_context *nextctx =
+ curctx->parent;
+ struct sieve_interpreter *killed_interp = curctx->interp;
+ const struct ext_include_script_info *ended_script =
+ curctx->script_info;
+
+ /* This kills curctx too */
+ sieve_interpreter_free(&killed_interp);
+
+ sieve_runtime_trace(
+ renv, SIEVE_TRLVL_NONE,
+ "include: script '%s' ended [id: %d, block: %d]",
+ sieve_script_name(ended_script->script),
+ ended_script->id,
+ sieve_binary_block_get_id(ended_script->block));
+
+ /* Luckily we recorded the parent earlier */
+ curctx = nextctx;
+ }
+
+ } else {
+ /* We are an included script already, defer inclusion to main
+ interpreter */
+ ctx->include = included;
+ sieve_interpreter_interrupt(renv->interp);
+ }
+
+ return result;
+}
+
+void ext_include_execute_return(const struct sieve_runtime_env *renv)
+{
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ struct ext_include_interpreter_context *ctx =
+ ext_include_get_interpreter_context(this_ext, renv->interp);
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
+ "return: exiting included script");
+ ctx->returned = TRUE;
+ sieve_interpreter_interrupt(renv->interp);
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/include/ext-include-common.h b/pigeonhole/src/lib-sieve/plugins/include/ext-include-common.h
new file mode 100644
index 0000000..44bfe9a
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/include/ext-include-common.h
@@ -0,0 +1,170 @@
+#ifndef EXT_INCLUDE_COMMON_H
+#define EXT_INCLUDE_COMMON_H
+
+#include "lib.h"
+#include "hash.h"
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+
+/*
+ * Forward declarations
+ */
+
+struct ext_include_script_info;
+struct ext_include_binary_context;
+
+/*
+ * Types
+ */
+
+enum ext_include_flags { // stored in one byte
+ EXT_INCLUDE_FLAG_ONCE = 0x01,
+ EXT_INCLUDE_FLAG_OPTIONAL = 0x02,
+ EXT_INCLUDE_FLAG_MISSING_AT_UPLOAD = 0x04
+};
+
+enum ext_include_script_location {
+ EXT_INCLUDE_LOCATION_PERSONAL,
+ EXT_INCLUDE_LOCATION_GLOBAL,
+ EXT_INCLUDE_LOCATION_INVALID
+};
+
+static inline const char *
+ext_include_script_location_name(enum ext_include_script_location location)
+{
+ switch (location) {
+ case EXT_INCLUDE_LOCATION_PERSONAL:
+ return "personal";
+ case EXT_INCLUDE_LOCATION_GLOBAL:
+ return "global";
+ default:
+ break;
+ }
+
+ return "[INVALID LOCATION]";
+}
+
+
+/*
+ * Extension
+ */
+
+extern const struct sieve_extension_def include_extension;
+extern const struct sieve_binary_extension include_binary_ext;
+
+bool ext_include_load(const struct sieve_extension *ext, void **context);
+void ext_include_unload(const struct sieve_extension *ext);
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def cmd_include;
+extern const struct sieve_command_def cmd_return;
+extern const struct sieve_command_def cmd_global;
+
+/* DEPRICATED */
+extern const struct sieve_command_def cmd_import;
+extern const struct sieve_command_def cmd_export;
+
+/*
+ * Operations
+ */
+
+enum ext_include_opcode {
+ EXT_INCLUDE_OPERATION_INCLUDE,
+ EXT_INCLUDE_OPERATION_RETURN,
+ EXT_INCLUDE_OPERATION_GLOBAL
+};
+
+extern const struct sieve_operation_def include_operation;
+extern const struct sieve_operation_def return_operation;
+extern const struct sieve_operation_def global_operation;
+
+/*
+ * Script access
+ */
+
+struct sieve_storage *
+ext_include_get_script_storage(const struct sieve_extension *ext,
+ enum ext_include_script_location location,
+ const char *script_name,
+ enum sieve_error *error_r);
+/*
+ * Context
+ */
+
+/* Extension context */
+
+struct ext_include_context {
+ /* Extension dependencies */
+ const struct sieve_extension *var_ext;
+
+ /* Configuration */
+ char *global_location;
+
+ struct sieve_storage *global_storage;
+ struct sieve_storage *personal_storage;
+
+ unsigned int max_nesting_depth;
+ unsigned int max_includes;
+};
+
+static inline struct ext_include_context *
+ext_include_get_context(const struct sieve_extension *ext)
+{
+ return (struct ext_include_context *) ext->context;
+}
+
+/* AST Context */
+
+struct ext_include_ast_context {
+ struct sieve_variable_scope *global_vars;
+
+ ARRAY(struct sieve_script *) included_scripts;
+};
+
+struct ext_include_ast_context *
+ext_include_create_ast_context(const struct sieve_extension *this_ext,
+ struct sieve_ast *ast, struct sieve_ast *parent);
+struct ext_include_ast_context *
+ext_include_get_ast_context(const struct sieve_extension *this_ext,
+ struct sieve_ast *ast);
+
+void ext_include_ast_link_included_script(
+ const struct sieve_extension *this_ext, struct sieve_ast *ast,
+ struct sieve_script *script);
+
+bool ext_include_validator_have_variables(
+ const struct sieve_extension *this_ext, struct sieve_validator *valdtr);
+
+/* Generator context */
+
+void ext_include_register_generator_context(
+ const struct sieve_extension *this_ext,
+ const struct sieve_codegen_env *cgenv);
+
+int ext_include_generate_include(
+ const struct sieve_codegen_env *cgenv, struct sieve_command *cmd,
+ enum ext_include_script_location location, enum ext_include_flags flags,
+ struct sieve_script *script,
+ const struct ext_include_script_info **included_r);
+
+/* Interpreter context */
+
+void ext_include_interpreter_context_init(
+ const struct sieve_extension *this_ext,
+ struct sieve_interpreter *interp);
+
+int ext_include_execute_include(const struct sieve_runtime_env *renv,
+ unsigned int block_id,
+ enum ext_include_flags flags);
+void ext_include_execute_return(const struct sieve_runtime_env *renv);
+
+struct sieve_variable_storage *
+ext_include_interpreter_get_global_variables(
+ const struct sieve_extension *this_ext,
+ struct sieve_interpreter *interp);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/include/ext-include-limits.h b/pigeonhole/src/lib-sieve/plugins/include/ext-include-limits.h
new file mode 100644
index 0000000..37246c0
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/include/ext-include-limits.h
@@ -0,0 +1,9 @@
+#ifndef EXT_INCLUDE_LIMITS_H
+#define EXT_INCLUDE_LIMITS_H
+
+#include "sieve-common.h"
+
+#define EXT_INCLUDE_DEFAULT_MAX_NESTING_DEPTH 10
+#define EXT_INCLUDE_DEFAULT_MAX_INCLUDES 255
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/include/ext-include-variables.c b/pigeonhole/src/lib-sieve/plugins/include/ext-include-variables.c
new file mode 100644
index 0000000..28cd803
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/include/ext-include-variables.c
@@ -0,0 +1,254 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-script.h"
+#include "sieve-ast.h"
+#include "sieve-binary.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "sieve-ext-variables.h"
+
+#include "ext-include-common.h"
+#include "ext-include-binary.h"
+#include "ext-include-variables.h"
+
+/*
+ * Variable import-export
+ */
+
+struct sieve_variable *ext_include_variable_import_global
+(struct sieve_validator *valdtr, struct sieve_command *cmd,
+ const char *variable)
+{
+ const struct sieve_extension *this_ext = cmd->ext;
+ struct sieve_ast *ast = cmd->ast_node->ast;
+ struct ext_include_ast_context *ctx =
+ ext_include_get_ast_context(this_ext, ast);
+ struct ext_include_context *ectx = ext_include_get_context(this_ext);
+ struct sieve_variable_scope *local_scope;
+ struct sieve_variable_scope *global_scope = ctx->global_vars;
+ struct sieve_variable *global_var = NULL, *local_var;
+
+ /* Sanity safeguard */
+ i_assert ( ctx->global_vars != NULL );
+
+ if ( !sieve_variable_identifier_is_valid(variable) ) {
+ sieve_command_validate_error(valdtr, cmd,
+ "invalid variable identifier '%s'", str_sanitize(variable,80));
+ return NULL;
+ }
+
+ /* Get/Declare the variable in the global scope */
+ global_var = sieve_variable_scope_declare(global_scope, variable);
+
+ /* Check whether scope is over its size limit */
+ if ( global_var == NULL ) {
+ sieve_command_validate_error(valdtr, cmd,
+ "declaration of new global variable '%s' exceeds the limit "
+ "(max variables: %u)", variable,
+ sieve_variables_get_max_scope_size(ectx->var_ext));
+ return NULL;
+ }
+
+ /* Import the global variable into the local script scope */
+ local_scope = sieve_ext_variables_get_local_scope(ectx->var_ext, valdtr);
+
+ local_var = sieve_variable_scope_get_variable(local_scope, variable);
+ if ( local_var != NULL && local_var->ext != this_ext ) {
+ /* FIXME: indicate location of conflicting set statement */
+ sieve_command_validate_error(valdtr, cmd,
+ "declaration of new global variable '%s' conflicts with earlier local "
+ "use", variable);
+ return NULL;
+ }
+
+ return sieve_variable_scope_import(local_scope, global_var);
+}
+
+/*
+ * Binary symbol table
+ */
+
+bool ext_include_variables_save
+(struct sieve_binary_block *sblock,
+ struct sieve_variable_scope_binary *global_vars,
+ enum sieve_error *error_r ATTR_UNUSED)
+{
+ struct sieve_variable_scope *global_scope =
+ sieve_variable_scope_binary_get(global_vars);
+ unsigned int count = sieve_variable_scope_size(global_scope);
+ sieve_size_t jump;
+
+ sieve_binary_emit_unsigned(sblock, count);
+
+ jump = sieve_binary_emit_offset(sblock, 0);
+
+ if ( count > 0 ) {
+ unsigned int size, i;
+ struct sieve_variable *const *vars =
+ sieve_variable_scope_get_variables(global_scope, &size);
+
+ for ( i = 0; i < size; i++ ) {
+ sieve_binary_emit_cstring(sblock, vars[i]->identifier);
+ }
+ }
+
+ sieve_binary_resolve_offset(sblock, jump);
+
+ return TRUE;
+}
+
+bool ext_include_variables_load
+(const struct sieve_extension *this_ext, struct sieve_binary_block *sblock,
+ sieve_size_t *offset, struct sieve_variable_scope_binary **global_vars_r)
+{
+ struct ext_include_context *ectx =
+ ext_include_get_context(this_ext);
+
+ /* Sanity assert */
+ i_assert( *global_vars_r == NULL );
+
+ *global_vars_r = sieve_variable_scope_binary_read
+ (this_ext->svinst, ectx->var_ext, this_ext, sblock, offset);
+
+ return ( *global_vars_r != NULL );
+}
+
+bool ext_include_variables_dump
+(struct sieve_dumptime_env *denv,
+ struct sieve_variable_scope_binary *global_vars)
+{
+ struct sieve_variable_scope *global_scope =
+ sieve_variable_scope_binary_get(global_vars);
+ unsigned int size;
+ struct sieve_variable *const *vars;
+
+ i_assert(global_scope != NULL);
+
+ vars = sieve_variable_scope_get_variables(global_scope, &size);
+
+ if ( size > 0 ) {
+ unsigned int i;
+
+ sieve_binary_dump_sectionf(denv, "Global variables");
+
+ for ( i = 0; i < size; i++ ) {
+ sieve_binary_dumpf(denv, "%3d: '%s' \n", i, vars[i]->identifier);
+ }
+ }
+
+ return TRUE;
+}
+
+/*
+ * Global variables namespace
+ */
+
+bool vnspc_global_variables_validate
+ (struct sieve_validator *valdtr, const struct sieve_variables_namespace *nspc,
+ struct sieve_ast_argument *arg, struct sieve_command *cmd,
+ ARRAY_TYPE(sieve_variable_name) *var_name, void **var_data,
+ bool assignment);
+bool vnspc_global_variables_generate
+ (const struct sieve_codegen_env *cgenv,
+ const struct sieve_variables_namespace *nspc,
+ struct sieve_ast_argument *arg, struct sieve_command *cmd, void *var_data);
+
+static const struct sieve_variables_namespace_def
+global_variables_namespace = {
+ SIEVE_OBJECT("global", NULL, 0),
+ .validate = vnspc_global_variables_validate,
+ .generate = vnspc_global_variables_generate
+};
+
+bool vnspc_global_variables_validate
+(struct sieve_validator *valdtr,
+ const struct sieve_variables_namespace *nspc, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd ATTR_UNUSED,
+ ARRAY_TYPE(sieve_variable_name) *var_name, void **var_data,
+ bool assignment ATTR_UNUSED)
+{
+ const struct sieve_extension *this_ext = SIEVE_OBJECT_EXTENSION(nspc);
+ struct sieve_ast *ast = arg->ast;
+ struct ext_include_context *ectx =
+ ext_include_get_context(this_ext);
+ struct ext_include_ast_context *ctx =
+ ext_include_get_ast_context(this_ext, ast);
+ struct sieve_variable *var = NULL;
+ const struct sieve_variable_name *name_element;
+ const char *variable;
+
+ /* Sanity safeguard */
+ i_assert ( ctx->global_vars != NULL );
+
+ /* Check variable name */
+
+ if ( array_count(var_name) != 2 ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "invalid variable name within global namespace: "
+ "encountered sub-namespace");
+ return FALSE;
+ }
+
+ name_element = array_idx(var_name, 1);
+ if ( name_element->num_variable >= 0 ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "invalid variable name within global namespace: "
+ "encountered numeric variable name");
+ return FALSE;
+ }
+
+ variable = str_c(name_element->identifier);
+
+ /* Get/Declare the variable in the global scope */
+
+ var = sieve_variable_scope_declare(ctx->global_vars, variable);
+
+ if ( var == NULL ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "(implicit) declaration of new global variable '%s' exceeds the limit "
+ "(max variables: %u)", variable,
+ sieve_variables_get_max_scope_size(ectx->var_ext));
+ return FALSE;
+ }
+
+ *var_data = (void *) var;
+
+ return TRUE;
+}
+
+bool vnspc_global_variables_generate
+(const struct sieve_codegen_env *cgenv,
+ const struct sieve_variables_namespace *nspc,
+ struct sieve_ast_argument *arg ATTR_UNUSED,
+ struct sieve_command *cmd ATTR_UNUSED, void *var_data)
+{
+ const struct sieve_extension *this_ext = SIEVE_OBJECT_EXTENSION(nspc);
+ struct ext_include_context *ectx = ext_include_get_context(this_ext);
+ struct sieve_variable *var = (struct sieve_variable *) var_data;
+
+ sieve_variables_opr_variable_emit(cgenv->sblock, ectx->var_ext, var);
+
+ return TRUE;
+}
+
+void ext_include_variables_global_namespace_init
+(const struct sieve_extension *this_ext, struct sieve_validator *valdtr)
+{
+ struct ext_include_context *ectx = ext_include_get_context(this_ext);
+
+ sieve_variables_namespace_register
+ (ectx->var_ext, valdtr, this_ext, &global_variables_namespace);
+}
+
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/include/ext-include-variables.h b/pigeonhole/src/lib-sieve/plugins/include/ext-include-variables.h
new file mode 100644
index 0000000..d5927b2
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/include/ext-include-variables.h
@@ -0,0 +1,41 @@
+#ifndef EXT_INCLUDE_VARIABLES_H
+#define EXT_INCLUDE_VARIABLES_H
+
+#include "sieve-common.h"
+
+#include "sieve-ext-variables.h"
+
+#include "ext-include-common.h"
+
+/*
+ * Variable import-export
+ */
+
+struct sieve_variable *ext_include_variable_import_global
+ (struct sieve_validator *valdtr, struct sieve_command *cmd,
+ const char *variable);
+
+/*
+ * Binary symbol table
+ */
+
+bool ext_include_variables_save
+ (struct sieve_binary_block *sblock,
+ struct sieve_variable_scope_binary *global_vars,
+ enum sieve_error *error_r);
+bool ext_include_variables_load
+ (const struct sieve_extension *this_ext, struct sieve_binary_block *sblock,
+ sieve_size_t *offset, struct sieve_variable_scope_binary **global_vars_r);
+bool ext_include_variables_dump
+ (struct sieve_dumptime_env *denv,
+ struct sieve_variable_scope_binary *global_vars);
+
+/*
+ * Validation
+ */
+
+void ext_include_variables_global_namespace_init
+ (const struct sieve_extension *this_ext, struct sieve_validator *valdtr);
+
+#endif
+
diff --git a/pigeonhole/src/lib-sieve/plugins/include/ext-include.c b/pigeonhole/src/lib-sieve/plugins/include/ext-include.c
new file mode 100644
index 0000000..0a38687
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/include/ext-include.c
@@ -0,0 +1,121 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension include
+ * -----------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 6609
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+/* FIXME: Current include implementation does not allow for parts of the script
+ * to be located in external binaries; all included scripts are recompiled and
+ * the resulting byte code is imported into the main binary in separate blocks.
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+
+#include "sieve-extensions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+
+#include "sieve-ext-variables.h"
+
+#include "ext-include-common.h"
+#include "ext-include-binary.h"
+#include "ext-include-variables.h"
+
+/*
+ * Operations
+ */
+
+static const struct sieve_operation_def *ext_include_operations[] = {
+ &include_operation,
+ &return_operation,
+ &global_operation
+};
+
+/*
+ * Extension
+ */
+
+/* Forward declaration */
+
+static bool ext_include_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *validator);
+static bool ext_include_generator_load
+ (const struct sieve_extension *ext, const struct sieve_codegen_env *cgenv);
+static bool ext_include_interpreter_load
+ (const struct sieve_extension *ext, const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+static bool ext_include_binary_load
+ (const struct sieve_extension *ext, struct sieve_binary *binary);
+
+/* Extension objects */
+
+const struct sieve_extension_def include_extension = {
+ .name = "include",
+ .version = 1,
+
+ .load = ext_include_load,
+ .unload = ext_include_unload,
+ .validator_load = ext_include_validator_load,
+ .generator_load = ext_include_generator_load,
+ .interpreter_load = ext_include_interpreter_load,
+ .binary_load = ext_include_binary_load,
+ .binary_dump = ext_include_binary_dump,
+ .code_dump = ext_include_code_dump,
+
+ SIEVE_EXT_DEFINE_OPERATIONS(ext_include_operations)
+};
+
+static bool ext_include_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Register new commands */
+ sieve_validator_register_command(valdtr, ext, &cmd_include);
+ sieve_validator_register_command(valdtr, ext, &cmd_return);
+ sieve_validator_register_command(valdtr, ext, &cmd_global);
+
+ /* DEPRICATED */
+ sieve_validator_register_command(valdtr, ext, &cmd_import);
+ sieve_validator_register_command(valdtr, ext, &cmd_export);
+
+ /* Initialize global variables namespace */
+ ext_include_variables_global_namespace_init(ext, valdtr);
+
+ return TRUE;
+}
+
+static bool ext_include_generator_load
+(const struct sieve_extension *ext, const struct sieve_codegen_env *cgenv)
+{
+ ext_include_register_generator_context(ext, cgenv);
+
+ return TRUE;
+}
+
+static bool ext_include_interpreter_load
+(const struct sieve_extension *ext, const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ ext_include_interpreter_context_init(ext, renv->interp);
+
+ return TRUE;
+}
+
+static bool ext_include_binary_load
+(const struct sieve_extension *ext, struct sieve_binary *sbin)
+{
+ (void)ext_include_binary_get_context(ext, sbin);
+
+ return TRUE;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/index/Makefile.am b/pigeonhole/src/lib-sieve/plugins/index/Makefile.am
new file mode 100644
index 0000000..434ca1c
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/index/Makefile.am
@@ -0,0 +1,13 @@
+noinst_LTLIBRARIES = libsieve_ext_index.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+libsieve_ext_index_la_SOURCES = \
+ ext-index-common.c \
+ ext-index.c \
+ tag-index.c
+
+noinst_HEADERS = \
+ ext-index-common.h
diff --git a/pigeonhole/src/lib-sieve/plugins/index/Makefile.in b/pigeonhole/src/lib-sieve/plugins/index/Makefile.in
new file mode 100644
index 0000000..852316c
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/index/Makefile.in
@@ -0,0 +1,688 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/index
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_index_la_LIBADD =
+am_libsieve_ext_index_la_OBJECTS = ext-index-common.lo ext-index.lo \
+ tag-index.lo
+libsieve_ext_index_la_OBJECTS = $(am_libsieve_ext_index_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ext-index-common.Plo \
+ ./$(DEPDIR)/ext-index.Plo ./$(DEPDIR)/tag-index.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_index_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_index_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_index.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+libsieve_ext_index_la_SOURCES = \
+ ext-index-common.c \
+ ext-index.c \
+ tag-index.c
+
+noinst_HEADERS = \
+ ext-index-common.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/index/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/index/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_index.la: $(libsieve_ext_index_la_OBJECTS) $(libsieve_ext_index_la_DEPENDENCIES) $(EXTRA_libsieve_ext_index_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_index_la_OBJECTS) $(libsieve_ext_index_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-index-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-index.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tag-index.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ext-index-common.Plo
+ -rm -f ./$(DEPDIR)/ext-index.Plo
+ -rm -f ./$(DEPDIR)/tag-index.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ext-index-common.Plo
+ -rm -f ./$(DEPDIR)/ext-index.Plo
+ -rm -f ./$(DEPDIR)/tag-index.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/index/ext-index-common.c b/pigeonhole/src/lib-sieve/plugins/index/ext-index-common.c
new file mode 100644
index 0000000..26fb706
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/index/ext-index-common.c
@@ -0,0 +1,15 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "utc-offset.h"
+#include "str.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-interpreter.h"
+#include "sieve-message.h"
+
+#include "ext-index-common.h"
+
diff --git a/pigeonhole/src/lib-sieve/plugins/index/ext-index-common.h b/pigeonhole/src/lib-sieve/plugins/index/ext-index-common.h
new file mode 100644
index 0000000..7ce3244
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/index/ext-index-common.h
@@ -0,0 +1,29 @@
+#ifndef EXT_INDEX_COMMON_H
+#define EXT_INDEX_COMMON_H
+
+#include "sieve-common.h"
+
+#include <time.h>
+
+#define SIEVE_EXT_INDEX_HDR_OVERRIDE_SEQUENCE 100
+
+/*
+ * Tagged arguments
+ */
+
+extern const struct sieve_argument_def index_tag;
+extern const struct sieve_argument_def last_tag;
+
+/*
+ * Operands
+ */
+
+extern const struct sieve_operand_def index_operand;
+
+/*
+ * Extension
+ */
+
+extern const struct sieve_extension_def index_extension;
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/index/ext-index.c b/pigeonhole/src/lib-sieve/plugins/index/ext-index.c
new file mode 100644
index 0000000..33e7771
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/index/ext-index.c
@@ -0,0 +1,69 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension index
+ * ------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5260
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "lib.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-message.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-index-common.h"
+
+/*
+ * Extension
+ */
+
+static bool ext_index_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *validator);
+
+const struct sieve_extension_def index_extension = {
+ .name = "index",
+ .validator_load = ext_index_validator_load,
+ SIEVE_EXT_DEFINE_OPERAND(index_operand)
+};
+
+static bool ext_index_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Register :index and :last tags with header, address and date test commands
+ * and we don't care whether these command are registered or even whether
+ * these will be registered at all. The validator handles either situation
+ * gracefully.
+ */
+ sieve_validator_register_external_tag
+ (valdtr, "header", ext, &index_tag, SIEVE_OPT_MESSAGE_OVERRIDE);
+ sieve_validator_register_external_tag
+ (valdtr, "header", ext, &last_tag, 0);
+
+ sieve_validator_register_external_tag
+ (valdtr, "address", ext, &index_tag, SIEVE_OPT_MESSAGE_OVERRIDE);
+ sieve_validator_register_external_tag
+ (valdtr, "address", ext, &last_tag, 0);
+
+ sieve_validator_register_external_tag
+ (valdtr, "date", ext, &index_tag, SIEVE_OPT_MESSAGE_OVERRIDE);
+ sieve_validator_register_external_tag
+ (valdtr, "date", ext, &last_tag, 0);
+
+ return TRUE;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/index/tag-index.c b/pigeonhole/src/lib-sieve/plugins/index/tag-index.c
new file mode 100644
index 0000000..d8938a5
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/index/tag-index.c
@@ -0,0 +1,278 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "mail-storage.h"
+#include "mail-namespace.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-binary.h"
+#include "sieve-code.h"
+#include "sieve-message.h"
+#include "sieve-result.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+
+#include "ext-index-common.h"
+
+/*
+ * Tagged argument
+ */
+
+static bool
+tag_index_validate(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg, struct sieve_command *cmd);
+static bool
+tag_index_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_argument *arg,
+ struct sieve_command *context);
+
+const struct sieve_argument_def index_tag = {
+ .identifier = "index",
+ .validate = tag_index_validate,
+ .generate = tag_index_generate
+};
+
+static bool
+tag_last_validate(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg, struct sieve_command *cmd);
+
+const struct sieve_argument_def last_tag = {
+ .identifier = "last",
+ .validate = tag_last_validate,
+};
+
+/*
+ * Header override
+ */
+
+static bool
+svmo_index_dump_context(const struct sieve_message_override *svmo,
+ const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+svmo_index_read_context(const struct sieve_message_override *svmo,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address, void **ho_context);
+static int
+svmo_index_header_override(const struct sieve_message_override *svmo,
+ const struct sieve_runtime_env *renv,
+ bool mime_decode, struct sieve_stringlist **headers);
+
+const struct sieve_message_override_def index_header_override = {
+ SIEVE_OBJECT("index", &index_operand, 0),
+ .sequence = SIEVE_EXT_INDEX_HDR_OVERRIDE_SEQUENCE,
+ .dump_context = svmo_index_dump_context,
+ .read_context = svmo_index_read_context,
+ .header_override = svmo_index_header_override
+};
+
+/*
+ * Operand
+ */
+
+static const struct sieve_extension_objects ext_header_overrides =
+ SIEVE_EXT_DEFINE_MESSAGE_OVERRIDE(index_header_override);
+
+const struct sieve_operand_def index_operand = {
+ .name = "index operand",
+ .ext_def = &index_extension,
+ .class = &sieve_message_override_operand_class,
+ .interface = &ext_header_overrides
+};
+
+/*
+ * Tag data
+ */
+
+struct tag_index_data {
+ sieve_number_t fieldno;
+ bool last:1;
+};
+
+/*
+ * Tag validation
+ */
+
+static bool
+tag_index_validate(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_ast_argument **arg, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+ struct tag_index_data *data;
+
+ /* Skip the tag itself */
+ *arg = sieve_ast_argument_next(*arg);
+
+ /* Check syntax:
+ * ":index" <fieldno: number>
+ */
+ if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0,
+ SAAT_NUMBER, FALSE))
+ return FALSE;
+
+ if (tag->argument->data == NULL) {
+ data = p_new(sieve_command_pool(cmd), struct tag_index_data, 1);
+ tag->argument->data = (void *)data;
+ } else {
+ data = (struct tag_index_data *)tag->argument->data;
+ }
+
+ data->fieldno = sieve_ast_argument_number(*arg);
+ if (data->fieldno == 0) {
+ sieve_argument_validate_error(valdtr, *arg,
+ "the :index tag for the %s %s cannot be zero",
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd));
+ return FALSE;
+ }
+
+ /* Detach parameter */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+ return TRUE;
+}
+
+static bool
+tag_last_validate(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_ast_argument **arg, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *index_arg;
+ struct tag_index_data *data;
+
+ index_arg = sieve_command_find_argument(cmd, &index_tag);
+ if (index_arg == NULL) {
+ sieve_argument_validate_error(
+ valdtr, *arg,
+ "the :last tag for the %s %s cannot be specified "
+ "without the :index tag",
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd));
+ return FALSE;
+ }
+
+ /* Set :last flag */
+ if (index_arg->argument->data == NULL) {
+ data = p_new(sieve_command_pool(cmd), struct tag_index_data, 1);
+ index_arg->argument->data = (void*)data;
+ } else {
+ data = (struct tag_index_data *)index_arg->argument->data;
+ }
+ data->last = TRUE;
+
+ /* Detach */
+ *arg = sieve_ast_arguments_detach(*arg, 1);
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+tag_index_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_argument *arg,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ struct tag_index_data *data =
+ (struct tag_index_data *)arg->argument->data;
+
+ if (sieve_ast_argument_type(arg) != SAAT_TAG)
+ return FALSE;
+
+ sieve_opr_message_override_emit(cgenv->sblock, arg->argument->ext,
+ &index_header_override);
+
+ (void)sieve_binary_emit_integer (cgenv->sblock, data->fieldno);
+ (void)sieve_binary_emit_byte(cgenv->sblock, (data->last ? 1 : 0));
+ return TRUE;
+}
+
+/*
+ * Header override implementation
+ */
+
+/* Context data */
+
+struct svmo_index_context {
+ unsigned int fieldno;
+ bool last:1;
+};
+
+/* Context coding */
+
+static bool
+svmo_index_dump_context(const struct sieve_message_override *svmo ATTR_UNUSED,
+ const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ sieve_number_t fieldno = 0;
+ unsigned int last;
+
+ if (!sieve_binary_read_integer(denv->sblock, address, &fieldno) ||
+ fieldno == 0)
+ return FALSE;
+
+ sieve_code_dumpf(denv, "fieldno: %llu", (unsigned long long) fieldno);
+
+ if (!sieve_binary_read_byte(denv->sblock, address, &last))
+ return FALSE;
+
+ if (last > 0)
+ sieve_code_dumpf(denv, "last");
+ return TRUE;
+}
+
+static int
+svmo_index_read_context(const struct sieve_message_override *svmo ATTR_UNUSED,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address, void **ho_context)
+{
+ pool_t pool = sieve_result_pool(renv->result);
+ struct svmo_index_context *ctx;
+ sieve_number_t fieldno;
+ unsigned int last = 0;
+
+ if (!sieve_binary_read_integer(renv->sblock, address, &fieldno)) {
+ sieve_runtime_trace_error(renv, "fieldno: invalid number");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ if (fieldno == 0) {
+ sieve_runtime_trace_error(renv, "fieldno: index is zero");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ if (!sieve_binary_read_byte(renv->sblock, address, &last)) {
+ sieve_runtime_trace_error(renv, "last: invalid byte");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ ctx = p_new(pool, struct svmo_index_context, 1);
+ ctx->fieldno = fieldno;
+ ctx->last = (last == 0 ? FALSE : TRUE);
+
+ *ho_context = (void *) ctx;
+ return SIEVE_EXEC_OK;
+}
+
+/* Override */
+
+static int
+svmo_index_header_override(const struct sieve_message_override *svmo,
+ const struct sieve_runtime_env *renv,
+ bool mime_decode ATTR_UNUSED,
+ struct sieve_stringlist **headers)
+{
+ struct svmo_index_context *ctx =
+ (struct svmo_index_context *)svmo->context;
+
+ sieve_runtime_trace(
+ renv, SIEVE_TRLVL_MATCHING,
+ "header index override: only returning index %d%s",
+ ctx->fieldno, (ctx->last ? " (from last)" : ""));
+
+ *headers = sieve_index_stringlist_create(
+ renv, *headers, (int)ctx->fieldno * (ctx->last ? -1 : 1));
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/mailbox/Makefile.am b/pigeonhole/src/lib-sieve/plugins/mailbox/Makefile.am
new file mode 100644
index 0000000..b627735
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mailbox/Makefile.am
@@ -0,0 +1,26 @@
+noinst_LTLIBRARIES = libsieve_ext_mailbox.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+tags = \
+ tag-mailbox-create.c
+
+tests = \
+ tst-mailboxexists.c
+
+libsieve_ext_mailbox_la_SOURCES = \
+ $(tags) \
+ $(tests) \
+ ext-mailbox.c
+
+public_headers = \
+ sieve-ext-mailbox.h
+
+headers = \
+ ext-mailbox-common.h
+
+pkginc_libdir=$(dovecot_pkgincludedir)/sieve
+pkginc_lib_HEADERS = $(public_headers)
+noinst_HEADERS = $(headers)
diff --git a/pigeonhole/src/lib-sieve/plugins/mailbox/Makefile.in b/pigeonhole/src/lib-sieve/plugins/mailbox/Makefile.in
new file mode 100644
index 0000000..6d5ed09
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mailbox/Makefile.in
@@ -0,0 +1,757 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/mailbox
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(pkginc_lib_HEADERS) $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_mailbox_la_LIBADD =
+am__objects_1 = tag-mailbox-create.lo
+am__objects_2 = tst-mailboxexists.lo
+am_libsieve_ext_mailbox_la_OBJECTS = $(am__objects_1) $(am__objects_2) \
+ ext-mailbox.lo
+libsieve_ext_mailbox_la_OBJECTS = \
+ $(am_libsieve_ext_mailbox_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ext-mailbox.Plo \
+ ./$(DEPDIR)/tag-mailbox-create.Plo \
+ ./$(DEPDIR)/tst-mailboxexists.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_mailbox_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_mailbox_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkginc_libdir)"
+HEADERS = $(noinst_HEADERS) $(pkginc_lib_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_mailbox.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+tags = \
+ tag-mailbox-create.c
+
+tests = \
+ tst-mailboxexists.c
+
+libsieve_ext_mailbox_la_SOURCES = \
+ $(tags) \
+ $(tests) \
+ ext-mailbox.c
+
+public_headers = \
+ sieve-ext-mailbox.h
+
+headers = \
+ ext-mailbox-common.h
+
+pkginc_libdir = $(dovecot_pkgincludedir)/sieve
+pkginc_lib_HEADERS = $(public_headers)
+noinst_HEADERS = $(headers)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/mailbox/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/mailbox/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_mailbox.la: $(libsieve_ext_mailbox_la_OBJECTS) $(libsieve_ext_mailbox_la_DEPENDENCIES) $(EXTRA_libsieve_ext_mailbox_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_mailbox_la_OBJECTS) $(libsieve_ext_mailbox_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-mailbox.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tag-mailbox-create.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-mailboxexists.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
+ done
+
+uninstall-pkginc_libHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(pkginc_libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ext-mailbox.Plo
+ -rm -f ./$(DEPDIR)/tag-mailbox-create.Plo
+ -rm -f ./$(DEPDIR)/tst-mailboxexists.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkginc_libHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ext-mailbox.Plo
+ -rm -f ./$(DEPDIR)/tag-mailbox-create.Plo
+ -rm -f ./$(DEPDIR)/tst-mailboxexists.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkginc_libHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-pkginc_libHEADERS install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-pkginc_libHEADERS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/mailbox/ext-mailbox-common.h b/pigeonhole/src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
new file mode 100644
index 0000000..96cff39
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mailbox/ext-mailbox-common.h
@@ -0,0 +1,39 @@
+#ifndef EXT_MAILBOX_COMMON_H
+#define EXT_MAILBOX_COMMON_H
+
+#include "sieve-common.h"
+
+#include "sieve-ext-mailbox.h"
+
+/*
+ * Tagged arguments
+ */
+
+extern const struct sieve_argument_def mailbox_create_tag;
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def mailboxexists_test;
+
+/*
+ * Operands
+ */
+
+extern const struct sieve_operand_def mailbox_create_operand;
+
+/*
+ * Operations
+ */
+
+extern const struct sieve_operation_def mailboxexists_operation;
+
+/*
+ * Extension
+ */
+
+extern const struct sieve_extension_def mailbox_extension;
+
+#endif
+
diff --git a/pigeonhole/src/lib-sieve/plugins/mailbox/ext-mailbox.c b/pigeonhole/src/lib-sieve/plugins/mailbox/ext-mailbox.c
new file mode 100644
index 0000000..a2dcd88
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mailbox/ext-mailbox.c
@@ -0,0 +1,72 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension mailbox
+ * ------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5490
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "sieve-common.h"
+
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-actions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-result.h"
+
+#include "ext-mailbox-common.h"
+
+/*
+ * Tag registration
+ */
+
+void sieve_ext_mailbox_register_create_tag
+(struct sieve_validator *valdtr, const struct sieve_extension *mailbox_ext,
+ const char *command)
+{
+ if ( sieve_validator_extension_loaded(valdtr, mailbox_ext) ) {
+ sieve_validator_register_external_tag(valdtr, command,
+ mailbox_ext, &mailbox_create_tag, SIEVE_OPT_SIDE_EFFECT);
+ }
+}
+
+
+/*
+ * Extension
+ */
+
+static bool ext_mailbox_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def mailbox_extension = {
+ .name = "mailbox",
+ .validator_load = ext_mailbox_validator_load,
+ SIEVE_EXT_DEFINE_OPERATION(mailboxexists_operation),
+ SIEVE_EXT_DEFINE_OPERAND(mailbox_create_operand)
+};
+
+static bool ext_mailbox_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Register :create tag with fileinto command and we don't care whether this
+ * command is registered or even whether it will be registered at all. The
+ * validator handles either situation gracefully
+ */
+ sieve_validator_register_external_tag
+ (valdtr, "fileinto", ext, &mailbox_create_tag, SIEVE_OPT_SIDE_EFFECT);
+
+ /* Register new test */
+ sieve_validator_register_command(valdtr, ext, &mailboxexists_test);
+
+ return TRUE;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/mailbox/sieve-ext-mailbox.h b/pigeonhole/src/lib-sieve/plugins/mailbox/sieve-ext-mailbox.h
new file mode 100644
index 0000000..f7fa4cf
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mailbox/sieve-ext-mailbox.h
@@ -0,0 +1,21 @@
+#ifndef SIEVE_EXT_MAILBOX_H
+#define SIEVE_EXT_MAILBOX_H
+
+/* sieve_ext_mailbox_get_extension():
+ * Get the extension struct for the mailbox extension.
+ */
+static inline const struct sieve_extension *sieve_ext_mailbox_get_extension
+(struct sieve_instance *svinst)
+{
+ return sieve_extension_get_by_name(svinst, "mailbox");
+}
+
+/* sieve_ext_mailbox_register_create_tag():
+ * Register the :create tagged argument for a command other than fileinto and
+ * redirect.
+ */
+void sieve_ext_mailbox_register_create_tag
+ (struct sieve_validator *valdtr, const struct sieve_extension *mailbox_ext,
+ const char *command);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/mailbox/tag-mailbox-create.c b/pigeonhole/src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
new file mode 100644
index 0000000..f3c64cf
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mailbox/tag-mailbox-create.c
@@ -0,0 +1,186 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "mail-storage.h"
+#include "mail-namespace.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-actions.h"
+#include "sieve-code.h"
+#include "sieve-actions.h"
+#include "sieve-result.h"
+#include "sieve-generator.h"
+
+#include "ext-mailbox-common.h"
+
+/*
+ * Tagged argument
+ */
+
+static bool
+tag_mailbox_create_validate(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool
+tag_mailbox_create_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_argument *arg,
+ struct sieve_command *context);
+
+const struct sieve_argument_def mailbox_create_tag = {
+ .identifier = "create",
+ .validate = tag_mailbox_create_validate,
+ .generate = tag_mailbox_create_generate
+};
+
+/*
+ * Side effect
+ */
+
+static void
+seff_mailbox_create_print(const struct sieve_side_effect *seffect,
+ const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv,
+ bool *keep);
+static int
+seff_mailbox_create_pre_execute(const struct sieve_side_effect *seffect,
+ const struct sieve_action_exec_env *aenv,
+ void *tr_context,
+ void **se_tr_context ATTR_UNUSED);
+
+const struct sieve_side_effect_def mailbox_create_side_effect = {
+ SIEVE_OBJECT("create", &mailbox_create_operand, 0),
+ .precedence = 100,
+ .to_action = &act_store,
+ .print = seff_mailbox_create_print,
+ .pre_execute = seff_mailbox_create_pre_execute
+};
+
+/*
+ * Operand
+ */
+
+static const struct sieve_extension_objects ext_side_effects =
+ SIEVE_EXT_DEFINE_SIDE_EFFECT(mailbox_create_side_effect);
+
+const struct sieve_operand_def mailbox_create_operand = {
+ .name = "create operand",
+ .ext_def = &mailbox_extension,
+ .class = &sieve_side_effect_operand_class,
+ .interface = &ext_side_effects
+};
+
+/*
+ * Tag validation
+ */
+
+static bool
+tag_mailbox_create_validate(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+tag_mailbox_create_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_argument *arg,
+ struct sieve_command *context ATTR_UNUSED)
+{
+ if (sieve_ast_argument_type(arg) != SAAT_TAG)
+ return FALSE;
+
+ sieve_opr_side_effect_emit(cgenv->sblock, arg->argument->ext,
+ &mailbox_create_side_effect);
+ return TRUE;
+}
+
+/*
+ * Side effect implementation
+ */
+
+static void
+seff_mailbox_create_print(const struct sieve_side_effect *seffect ATTR_UNUSED,
+ const struct sieve_action *action ATTR_UNUSED,
+ const struct sieve_result_print_env *rpenv,
+ bool *keep ATTR_UNUSED)
+{
+ sieve_result_seffect_printf(
+ rpenv, "create mailbox if it does not exist");
+}
+
+static int
+seff_mailbox_create_pre_execute(
+ const struct sieve_side_effect *seffect ATTR_UNUSED,
+ const struct sieve_action_exec_env *aenv, void *tr_context,
+ void **se_tr_context ATTR_UNUSED)
+{
+ struct act_store_transaction *trans = tr_context;
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct mailbox *box = trans->box;
+
+ /* Check whether creation is necessary */
+ if (box == NULL || trans->disabled)
+ return SIEVE_EXEC_OK;
+
+ eenv->exec_status->last_storage = mailbox_get_storage(box);
+
+ /* Open the mailbox (may already be open) */
+ if (trans->error_code == MAIL_ERROR_NONE) {
+ if (mailbox_open(box) < 0)
+ sieve_act_store_get_storage_error(aenv, trans);
+ }
+
+ /* Check whether creation has a chance of working */
+ switch (trans->error_code) {
+ case MAIL_ERROR_NONE:
+ return SIEVE_EXEC_OK;
+ case MAIL_ERROR_NOTFOUND:
+ break;
+ case MAIL_ERROR_TEMP:
+ return SIEVE_EXEC_TEMP_FAILURE;
+ default:
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ trans->error = NULL;
+ trans->error_code = MAIL_ERROR_NONE;
+
+ /* Create mailbox */
+ if (mailbox_create(box, NULL, FALSE) < 0) {
+ sieve_act_store_get_storage_error(aenv, trans);
+ if (trans->error_code == MAIL_ERROR_EXISTS) {
+ trans->error = NULL;
+ trans->error_code = MAIL_ERROR_NONE;
+ } else {
+ return (trans->error_code == MAIL_ERROR_TEMP ?
+ SIEVE_EXEC_TEMP_FAILURE : SIEVE_EXEC_FAILURE);
+ }
+ }
+
+ /* Subscribe to it if necessary */
+ if (eenv->scriptenv->mailbox_autosubscribe) {
+ (void)mailbox_list_set_subscribed(
+ mailbox_get_namespace(box)->list,
+ mailbox_get_name(box), TRUE);
+ }
+
+ /* Try opening again */
+ if (mailbox_open(box) < 0) {
+ /* Failed definitively */
+ sieve_act_store_get_storage_error(aenv, trans);
+ return (trans->error_code == MAIL_ERROR_TEMP ?
+ SIEVE_EXEC_TEMP_FAILURE : SIEVE_EXEC_FAILURE);
+ }
+ return SIEVE_EXEC_OK;
+}
+
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/mailbox/tst-mailboxexists.c b/pigeonhole/src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
new file mode 100644
index 0000000..e0fd33d
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mailbox/tst-mailboxexists.c
@@ -0,0 +1,284 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+#include "mail-storage.h"
+#include "mail-namespace.h"
+
+#include "sieve-common.h"
+#include "sieve-actions.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-mailbox-common.h"
+
+/*
+ * Mailboxexists command
+ *
+ * Syntax:
+ * mailboxexists <mailbox-names: string-list>
+ */
+
+static bool
+tst_mailboxexists_validate(struct sieve_validator *valdtr,
+ struct sieve_command *tst);
+static bool
+tst_mailboxexists_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+const struct sieve_command_def mailboxexists_test = {
+ .identifier = "mailboxexists",
+ .type = SCT_TEST,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = tst_mailboxexists_validate,
+ .generate = tst_mailboxexists_generate,
+};
+
+/*
+ * Mailboxexists operation
+ */
+
+static bool
+tst_mailboxexists_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+tst_mailboxexists_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def mailboxexists_operation = {
+ .mnemonic = "MAILBOXEXISTS",
+ .ext_def = &mailbox_extension,
+ .dump = tst_mailboxexists_operation_dump,
+ .execute = tst_mailboxexists_operation_execute,
+};
+
+/*
+ * Test validation
+ */
+
+struct _validate_context {
+ struct sieve_validator *valdtr;
+ struct sieve_command *tst;
+};
+
+static int
+tst_mailboxexists_mailbox_validate(void *context,
+ struct sieve_ast_argument *arg)
+{
+ struct _validate_context *valctx =
+ (struct _validate_context *)context;
+
+ if (sieve_argument_is_string_literal(arg)) {
+ const char *mailbox = sieve_ast_argument_strc(arg), *error;
+
+ if (!sieve_mailbox_check_name(mailbox, &error)) {
+ sieve_argument_validate_warning(
+ valctx->valdtr, arg, "%s test: "
+ "invalid mailbox name `%s' specified: %s",
+ sieve_command_identifier(valctx->tst),
+ str_sanitize(mailbox, 256), error);
+ }
+ }
+
+ return 1;
+}
+
+static bool
+tst_mailboxexists_validate(struct sieve_validator *valdtr,
+ struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+ struct sieve_ast_argument *aarg;
+ struct _validate_context valctx;
+
+ if (!sieve_validate_positional_argument(
+ valdtr, tst, arg, "mailbox-names", 1, SAAT_STRING_LIST))
+ return FALSE;
+
+ if (!sieve_validator_argument_activate(valdtr, tst, arg, FALSE))
+ return FALSE;
+
+ aarg = arg;
+ i_zero(&valctx);
+ valctx.valdtr = valdtr;
+ valctx.tst = tst;
+
+ return (sieve_ast_stringlist_map(
+ &aarg, (void*)&valctx,
+ tst_mailboxexists_mailbox_validate) >= 0);
+}
+
+/*
+ * Test generation
+ */
+
+static bool
+tst_mailboxexists_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *tst)
+{
+ sieve_operation_emit(cgenv->sblock, tst->ext, &mailboxexists_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, tst, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+tst_mailboxexists_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "MAILBOXEXISTS");
+ sieve_code_descend(denv);
+
+ return sieve_opr_stringlist_dump(denv, address, "mailbox-names");
+}
+
+/*
+ * Code execution
+ */
+
+static int
+tst_mailboxexists_test_mailbox(const struct sieve_runtime_env *renv,
+ const char *mailbox, bool trace,
+ bool *all_exist_r)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ struct mailbox *box;
+ const char *error;
+
+ /* Check validity of mailbox name */
+ if (!sieve_mailbox_check_name(mailbox, &error)) {
+ sieve_runtime_warning(
+ renv, NULL, "mailboxexists test: "
+ "invalid mailbox name `%s' specified: %s",
+ str_sanitize(mailbox, 256), error);
+ *all_exist_r = FALSE;
+ return SIEVE_EXEC_OK;
+ }
+
+ /* Open the box */
+ box = mailbox_alloc_for_user(eenv->scriptenv->user,
+ mailbox,
+ MAILBOX_FLAG_POST_SESSION);
+
+ if (mailbox_open(box) < 0) {
+ if (trace) {
+ sieve_runtime_trace(
+ renv, 0,
+ "mailbox `%s' cannot be opened",
+ str_sanitize(mailbox, 80));
+ }
+ mailbox_free(&box);
+ *all_exist_r = FALSE;
+ return SIEVE_EXEC_OK;
+ }
+
+ /* Also fail when it is readonly */
+ if (mailbox_is_readonly(box)) {
+ if (trace) {
+ sieve_runtime_trace(
+ renv, 0,
+ "mailbox `%s' is read-only",
+ str_sanitize(mailbox, 80));
+ }
+ mailbox_free(&box);
+ *all_exist_r = FALSE;
+ return SIEVE_EXEC_OK;
+ }
+
+ /* FIXME: check acl for 'p' or 'i' ACL permissions as
+ required by RFC */
+
+ if (trace) {
+ sieve_runtime_trace(
+ renv, 0, "mailbox `%s' exists",
+ str_sanitize(mailbox, 80));
+ }
+
+ /* Close mailbox */
+ mailbox_free(&box);
+ return SIEVE_EXEC_OK;
+}
+
+static int
+tst_mailboxexists_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ struct sieve_stringlist *mailbox_names;
+ string_t *mailbox_item;
+ bool trace = FALSE;
+ bool all_exist = TRUE;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Read notify uris */
+ ret = sieve_opr_stringlist_read(renv, address, "mailbox-names",
+ &mailbox_names);
+ if (ret <= 0)
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_TESTS)) {
+ sieve_runtime_trace(renv, 0, "mailboxexists test");
+ sieve_runtime_trace_descend(renv);
+
+ trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING);
+ }
+
+ if (eenv->scriptenv->user == NULL) {
+ sieve_runtime_trace(renv, 0, "no mail user; yield true");
+ sieve_interpreter_set_test_result(renv->interp, TRUE);
+ return SIEVE_EXEC_OK;
+ }
+
+ mailbox_item = NULL;
+ while (all_exist &&
+ (ret = sieve_stringlist_next_item(mailbox_names,
+ &mailbox_item)) > 0) {
+ const char *mailbox = str_c(mailbox_item);
+
+ ret = tst_mailboxexists_test_mailbox(renv, mailbox,
+ trace, &all_exist);
+ if (ret <= 0)
+ return ret;
+ }
+
+ if (ret < 0) {
+ sieve_runtime_trace_error(
+ renv, "invalid mailbox name item");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if (trace) {
+ if (all_exist) {
+ sieve_runtime_trace(renv, 0,
+ "all mailboxes are available");
+ } else {
+ sieve_runtime_trace(renv, 0,
+ "some mailboxes are unavailable");
+ }
+ }
+
+ sieve_interpreter_set_test_result(renv->interp, all_exist);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/metadata/Makefile.am b/pigeonhole/src/lib-sieve/plugins/metadata/Makefile.am
new file mode 100644
index 0000000..6d69ba8
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/metadata/Makefile.am
@@ -0,0 +1,24 @@
+noinst_LTLIBRARIES = libsieve_ext_metadata.la
+
+libsieve_ext_metadata_la_LDFLAGS = -module -avoid-version
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../variables \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_STORAGE_INCLUDE)
+
+tests = \
+ tst-metadata.c \
+ tst-metadataexists.c
+
+extensions = \
+ ext-metadata.c
+
+libsieve_ext_metadata_la_SOURCES = \
+ $(tests) \
+ $(extensions)
+
+noinst_HEADERS = \
+ ext-metadata-common.h
+
diff --git a/pigeonhole/src/lib-sieve/plugins/metadata/Makefile.in b/pigeonhole/src/lib-sieve/plugins/metadata/Makefile.in
new file mode 100644
index 0000000..0b95819
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/metadata/Makefile.in
@@ -0,0 +1,705 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/metadata
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_metadata_la_LIBADD =
+am__objects_1 = tst-metadata.lo tst-metadataexists.lo
+am__objects_2 = ext-metadata.lo
+am_libsieve_ext_metadata_la_OBJECTS = $(am__objects_1) \
+ $(am__objects_2)
+libsieve_ext_metadata_la_OBJECTS = \
+ $(am_libsieve_ext_metadata_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libsieve_ext_metadata_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libsieve_ext_metadata_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ext-metadata.Plo \
+ ./$(DEPDIR)/tst-metadata.Plo \
+ ./$(DEPDIR)/tst-metadataexists.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_metadata_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_metadata_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_metadata.la
+libsieve_ext_metadata_la_LDFLAGS = -module -avoid-version
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../variables \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_STORAGE_INCLUDE)
+
+tests = \
+ tst-metadata.c \
+ tst-metadataexists.c
+
+extensions = \
+ ext-metadata.c
+
+libsieve_ext_metadata_la_SOURCES = \
+ $(tests) \
+ $(extensions)
+
+noinst_HEADERS = \
+ ext-metadata-common.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/metadata/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/metadata/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_metadata.la: $(libsieve_ext_metadata_la_OBJECTS) $(libsieve_ext_metadata_la_DEPENDENCIES) $(EXTRA_libsieve_ext_metadata_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libsieve_ext_metadata_la_LINK) $(libsieve_ext_metadata_la_OBJECTS) $(libsieve_ext_metadata_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-metadata.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-metadata.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-metadataexists.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ext-metadata.Plo
+ -rm -f ./$(DEPDIR)/tst-metadata.Plo
+ -rm -f ./$(DEPDIR)/tst-metadataexists.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ext-metadata.Plo
+ -rm -f ./$(DEPDIR)/tst-metadata.Plo
+ -rm -f ./$(DEPDIR)/tst-metadataexists.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/metadata/ext-metadata-common.h b/pigeonhole/src/lib-sieve/plugins/metadata/ext-metadata-common.h
new file mode 100644
index 0000000..a4b25a0
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/metadata/ext-metadata-common.h
@@ -0,0 +1,40 @@
+#ifndef EXT_METADATA_COMMON_H
+#define EXT_METADATA_COMMON_H
+
+#include "lib.h"
+#include "mail-storage.h"
+#include "imap-metadata.h"
+
+#include "sieve-common.h"
+
+/*
+ * Extension
+ */
+
+extern const struct sieve_extension_def mboxmetadata_extension;
+extern const struct sieve_extension_def servermetadata_extension;
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def metadata_test;
+extern const struct sieve_command_def servermetadata_test;
+extern const struct sieve_command_def metadataexists_test;
+extern const struct sieve_command_def servermetadataexists_test;
+
+/*
+ * Operations
+ */
+
+enum ext_metadata_opcode {
+ EXT_METADATA_OPERATION_METADATA,
+ EXT_METADATA_OPERATION_METADATAEXISTS
+};
+
+extern const struct sieve_operation_def metadata_operation;
+extern const struct sieve_operation_def servermetadata_operation;
+extern const struct sieve_operation_def metadataexists_operation;
+extern const struct sieve_operation_def servermetadataexists_operation;
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/metadata/ext-metadata.c b/pigeonhole/src/lib-sieve/plugins/metadata/ext-metadata.c
new file mode 100644
index 0000000..882116b
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/metadata/ext-metadata.c
@@ -0,0 +1,83 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-binary.h"
+
+#include "sieve-validator.h"
+#include "sieve-interpreter.h"
+
+#include "ext-metadata-common.h"
+
+/*
+ * Extension mboxmetadata
+ * -----------------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5490; Section 3
+ * Implementation: skeleton
+ * Status: development
+ *
+ */
+
+const struct sieve_operation_def *mboxmetadata_operations[] = {
+ &metadata_operation,
+ &metadataexists_operation,
+};
+
+static bool ext_mboxmetadata_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def mboxmetadata_extension = {
+ .name = "mboxmetadata",
+ .validator_load = ext_mboxmetadata_validator_load,
+ SIEVE_EXT_DEFINE_OPERATIONS(mboxmetadata_operations)
+};
+
+static bool ext_mboxmetadata_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ sieve_validator_register_command(valdtr, ext, &metadata_test);
+ sieve_validator_register_command(valdtr, ext, &metadataexists_test);
+
+ return TRUE;
+}
+
+/*
+ * Extension servermetadata
+ * -----------------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5490; Section 4
+ * Implementation: skeleton
+ * Status: development
+ *
+ */
+
+const struct sieve_operation_def *servermetadata_operations[] = {
+ &servermetadata_operation,
+ &servermetadataexists_operation,
+};
+
+static bool ext_servermetadata_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def servermetadata_extension = {
+ .name = "servermetadata",
+ .validator_load = ext_servermetadata_validator_load,
+ SIEVE_EXT_DEFINE_OPERATIONS(servermetadata_operations)
+};
+
+static bool ext_servermetadata_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ sieve_validator_register_command(valdtr, ext, &servermetadata_test);
+ sieve_validator_register_command(valdtr, ext, &servermetadataexists_test);
+
+ return TRUE;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/metadata/tst-metadata.c b/pigeonhole/src/lib-sieve/plugins/metadata/tst-metadata.c
new file mode 100644
index 0000000..2e14535
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/metadata/tst-metadata.c
@@ -0,0 +1,433 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+#include "istream.h"
+
+#include "sieve-common.h"
+#include "sieve-limits.h"
+#include "sieve-commands.h"
+#include "sieve-actions.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-match.h"
+
+#include "ext-metadata-common.h"
+
+#define TST_METADATA_MAX_MATCH_SIZE SIEVE_MAX_STRING_LEN
+
+/*
+ * Test definitions
+ */
+
+/* Forward declarations */
+
+static bool
+tst_metadata_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool
+tst_metadata_validate(struct sieve_validator *valdtr,
+ struct sieve_command *tst);
+static bool
+tst_metadata_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd);
+
+/* Metadata test
+ *
+ * Syntax:
+ * metadata [MATCH-TYPE] [COMPARATOR]
+ * <mailbox: string>
+ * <annotation-name: string> <key-list: string-list>
+ */
+
+const struct sieve_command_def metadata_test = {
+ .identifier = "metadata",
+ .type = SCT_TEST,
+ .positional_args = 3,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_metadata_registered,
+ .validate = tst_metadata_validate,
+ .generate = tst_metadata_generate,
+};
+
+/* Servermetadata test
+ *
+ * Syntax:
+ * servermetadata [MATCH-TYPE] [COMPARATOR]
+ * <annotation-name: string> <key-list: string-list>
+ */
+
+const struct sieve_command_def servermetadata_test = {
+ .identifier = "servermetadata",
+ .type = SCT_TEST,
+ .positional_args = 2,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_metadata_registered,
+ .validate = tst_metadata_validate,
+ .generate = tst_metadata_generate,
+};
+
+/*
+ * Opcode definitions
+ */
+
+static bool
+tst_metadata_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+tst_metadata_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+/* Metadata operation */
+
+const struct sieve_operation_def metadata_operation = {
+ .mnemonic = "METADATA",
+ .ext_def = &mboxmetadata_extension,
+ .code = EXT_METADATA_OPERATION_METADATA,
+ .dump = tst_metadata_operation_dump,
+ .execute = tst_metadata_operation_execute,
+};
+
+/* Servermetadata operation */
+
+const struct sieve_operation_def servermetadata_operation = {
+ .mnemonic = "SERVERMETADATA",
+ .ext_def = &servermetadata_extension,
+ .code = EXT_METADATA_OPERATION_METADATA,
+ .dump = tst_metadata_operation_dump,
+ .execute = tst_metadata_operation_execute,
+};
+
+/*
+ * Test registration
+ */
+
+static bool
+tst_metadata_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_command_registration *cmd_reg)
+{
+ /* The order of these is not significant */
+ sieve_comparators_link_tag(valdtr, cmd_reg,
+ SIEVE_MATCH_OPT_COMPARATOR);
+ sieve_match_types_link_tags(valdtr, cmd_reg,
+ SIEVE_MATCH_OPT_MATCH_TYPE);
+ return TRUE;
+}
+
+/*
+ * Test validation
+ */
+
+static bool
+tst_metadata_validate(struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+ const struct sieve_match_type mcht_default =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ const struct sieve_comparator cmp_default =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+ unsigned int arg_index = 1;
+ const char *error;
+
+ /* mailbox */
+ if (sieve_command_is(tst, metadata_test)) {
+ if (!sieve_validate_positional_argument(
+ valdtr, tst, arg, "mailbox", arg_index++,
+ SAAT_STRING))
+ return FALSE;
+
+ if (!sieve_validator_argument_activate(valdtr, tst, arg, FALSE))
+ return FALSE;
+
+ /* Check name validity when mailbox argument is not a variable
+ */
+ if (sieve_argument_is_string_literal(arg)) {
+ const char *mailbox = sieve_ast_argument_strc(arg);
+ const char *error;
+
+ if (!sieve_mailbox_check_name(mailbox, &error)) {
+ sieve_argument_validate_warning(
+ valdtr, arg, "%s test: "
+ "invalid mailbox name `%s' specified: %s",
+ sieve_command_identifier(tst),
+ str_sanitize(mailbox, 256), error);
+ }
+ }
+ arg = sieve_ast_argument_next(arg);
+ }
+
+ /* annotation-name */
+ if (!sieve_validate_positional_argument(valdtr, tst, arg,
+ "annotation-name", arg_index++,
+ SAAT_STRING))
+ return FALSE;
+
+ if (!sieve_validator_argument_activate(valdtr, tst, arg, FALSE))
+ return FALSE;
+
+ if (sieve_argument_is_string_literal(arg)) {
+ string_t *aname = sieve_ast_argument_str(arg);
+
+ if (!imap_metadata_verify_entry_name(str_c(aname), &error)) {
+ sieve_argument_validate_warning(
+ valdtr, arg, "%s test: "
+ "specified annotation name `%s' is invalid: %s",
+ sieve_command_identifier(tst),
+ str_sanitize(str_c(aname), 256),
+ sieve_error_from_external(error));
+ }
+ }
+
+ arg = sieve_ast_argument_next(arg);
+
+ /* key-list */
+ if (!sieve_validate_positional_argument(valdtr, tst, arg,
+ "key-list", arg_index++,
+ SAAT_STRING_LIST))
+ return FALSE;
+
+ if (!sieve_validator_argument_activate(valdtr, tst, arg, FALSE))
+ return FALSE;
+
+ /* Validate the key argument to a specified match type */
+ return sieve_match_type_validate(valdtr, tst, arg,
+ &mcht_default, &cmp_default);
+}
+
+/*
+ * Test generation
+ */
+
+static bool
+tst_metadata_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *tst)
+{
+ if (sieve_command_is(tst, metadata_test)) {
+ sieve_operation_emit(cgenv->sblock, tst->ext,
+ &metadata_operation);
+ } else if (sieve_command_is(tst, servermetadata_test)) {
+ sieve_operation_emit(cgenv->sblock, tst->ext,
+ &servermetadata_operation);
+ } else {
+ i_unreached();
+ }
+
+ /* Generate arguments */
+ if (!sieve_generate_arguments(cgenv, tst, NULL))
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+tst_metadata_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ bool metadata = sieve_operation_is(denv->oprtn, metadata_operation);
+
+ if (metadata)
+ sieve_code_dumpf(denv, "METADATA");
+ else
+ sieve_code_dumpf(denv, "SERVERMETADATA");
+
+ sieve_code_descend(denv);
+
+ /* Handle any optional arguments */
+ if (sieve_match_opr_optional_dump(denv, address, NULL) != 0)
+ return FALSE;
+ if (metadata && !sieve_opr_string_dump(denv, address, "mailbox"))
+ return FALSE;
+
+ return (sieve_opr_string_dump(denv, address, "annotation-name") &&
+ sieve_opr_stringlist_dump(denv, address, "key list"));
+}
+
+/*
+ * Code execution
+ */
+
+static int
+tst_metadata_get_annotation(const struct sieve_runtime_env *renv,
+ const char *mailbox, const char *aname,
+ const char **annotation_r)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ struct mail_user *user = eenv->scriptenv->user;
+ struct mailbox *box;
+ struct imap_metadata_transaction *imtrans;
+ struct mail_attribute_value avalue;
+ int status, ret;
+
+ *annotation_r = NULL;
+
+ if (user == NULL)
+ return SIEVE_EXEC_OK;
+
+ if (mailbox != NULL) {
+ struct mail_namespace *ns;
+ ns = mail_namespace_find(user->namespaces, mailbox);
+ box = mailbox_alloc(ns->list, mailbox, 0);
+ imtrans = imap_metadata_transaction_begin(box);
+ } else {
+ box = NULL;
+ imtrans = imap_metadata_transaction_begin_server(user);
+ }
+
+ status = SIEVE_EXEC_OK;
+ ret = imap_metadata_get(imtrans, aname, &avalue);
+ if (ret < 0) {
+ enum mail_error error_code;
+ const char *error;
+
+ error = imap_metadata_transaction_get_last_error(
+ imtrans, &error_code);
+
+ sieve_runtime_error(
+ renv, NULL, "%s test: "
+ "failed to retrieve annotation `%s': %s%s",
+ (mailbox != NULL ? "metadata" : "servermetadata"),
+ str_sanitize(aname, 256),
+ sieve_error_from_external(error),
+ (error_code == MAIL_ERROR_TEMP ?
+ " (temporary failure)" : ""));
+
+ status = (error_code == MAIL_ERROR_TEMP ?
+ SIEVE_EXEC_TEMP_FAILURE : SIEVE_EXEC_FAILURE);
+
+ } else if (avalue.value != NULL) {
+ *annotation_r = avalue.value;
+ }
+ (void)imap_metadata_transaction_commit(&imtrans, NULL, NULL);
+ if (box != NULL)
+ mailbox_free(&box);
+ return status;
+}
+
+static int
+tst_metadata_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ bool metadata = sieve_operation_is(renv->oprtn, metadata_operation);
+ struct sieve_match_type mcht =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ struct sieve_comparator cmp =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+ string_t *mailbox, *aname;
+ struct sieve_stringlist *value_list, *key_list;
+ const char *annotation = NULL, *error;
+ int match, ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Handle match-type and comparator operands */
+ if (sieve_match_opr_optional_read(renv, address, NULL,
+ &ret, &cmp, &mcht) < 0)
+ return ret;
+
+ /* Read mailbox */
+ if (metadata) {
+ ret = sieve_opr_string_read(renv, address, "mailbox", &mailbox);
+ if (ret <= 0)
+ return ret;
+ }
+
+ /* Read annotation-name */
+ ret = sieve_opr_string_read(renv, address, "annotation-name", &aname);
+ if (ret <= 0)
+ return ret;
+
+ /* Read key-list */
+ ret = sieve_opr_stringlist_read(renv, address, "key-list", &key_list);
+ if (ret <= 0)
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ if (metadata) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "metadata test");
+ } else {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "servermetadata test");
+ }
+ sieve_runtime_trace_descend(renv);
+
+ if (!imap_metadata_verify_entry_name(str_c(aname), &error)) {
+ sieve_runtime_warning(
+ renv, NULL, "%s test: "
+ "specified annotation name `%s' is invalid: %s",
+ (metadata ? "metadata" : "servermetadata"),
+ str_sanitize(str_c(aname), 256),
+ sieve_error_from_external(error));
+ sieve_interpreter_set_test_result(renv->interp, FALSE);
+ return SIEVE_EXEC_OK;
+ }
+
+ if (metadata) {
+ if (!sieve_mailbox_check_name(str_c(mailbox), &error)) {
+ sieve_runtime_warning(
+ renv, NULL, "metadata test: "
+ "invalid mailbox name `%s' specified: %s",
+ str_sanitize(str_c(mailbox), 256), error);
+ sieve_interpreter_set_test_result(renv->interp, FALSE);
+ return SIEVE_EXEC_OK;
+ }
+
+ sieve_runtime_trace(
+ renv, SIEVE_TRLVL_TESTS,
+ "retrieving annotation `%s' from mailbox `%s'",
+ str_sanitize(str_c(aname), 256),
+ str_sanitize(str_c(mailbox), 80));
+ } else {
+ sieve_runtime_trace(
+ renv, SIEVE_TRLVL_TESTS,
+ "retrieving server annotation `%s'",
+ str_sanitize(str_c(aname), 256));
+ }
+
+ /* Get annotation */
+ ret = tst_metadata_get_annotation(renv,
+ (metadata ? str_c(mailbox) : NULL),
+ str_c(aname), &annotation);
+ if (ret == SIEVE_EXEC_OK) {
+ /* Perform match */
+ if (annotation != NULL) {
+ /* Create value stringlist */
+ value_list = sieve_single_stringlist_create_cstr(
+ renv, annotation, FALSE);
+
+ /* Perform match */
+ match = sieve_match(renv, &mcht, &cmp,
+ value_list, key_list, &ret);
+ if (ret < 0)
+ return ret;
+ } else {
+ match = 0;
+ }
+ }
+
+ /* Set test result for subsequent conditional jump */
+ if (ret == SIEVE_EXEC_OK)
+ sieve_interpreter_set_test_result(renv->interp, match > 0);
+ return ret;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/metadata/tst-metadataexists.c b/pigeonhole/src/lib-sieve/plugins/metadata/tst-metadataexists.c
new file mode 100644
index 0000000..e11d692
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/metadata/tst-metadataexists.c
@@ -0,0 +1,431 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+#include "mail-storage.h"
+#include "mail-namespace.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-actions.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-metadata-common.h"
+
+/*
+ * Command definitions
+ */
+
+/* Forward declarations */
+
+static bool
+tst_metadataexists_validate(struct sieve_validator *valdtr,
+ struct sieve_command *tst);
+static bool
+tst_metadataexists_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+/* Metadataexists command
+ *
+ * Syntax:
+ * metadataexists <mailbox: string> <annotation-names: string-list>
+ */
+
+static bool
+tst_metadataexists_validate(struct sieve_validator *valdtr,
+ struct sieve_command *tst);
+static bool
+tst_metadataexists_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+const struct sieve_command_def metadataexists_test = {
+ .identifier = "metadataexists",
+ .type = SCT_TEST,
+ .positional_args = 2,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = tst_metadataexists_validate,
+ .generate = tst_metadataexists_generate,
+};
+
+/* Servermetadataexists command
+ *
+ * Syntax:
+ * servermetadataexists <annotation-names: string-list>
+ */
+
+const struct sieve_command_def servermetadataexists_test = {
+ .identifier = "servermetadataexists",
+ .type = SCT_TEST,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = tst_metadataexists_validate,
+ .generate = tst_metadataexists_generate,
+};
+
+/*
+ * Opcode definitions
+ */
+
+static bool
+tst_metadataexists_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+tst_metadataexists_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+/* Metadata operation */
+
+const struct sieve_operation_def metadataexists_operation = {
+ .mnemonic = "METADATAEXISTS",
+ .ext_def = &mboxmetadata_extension,
+ .code = EXT_METADATA_OPERATION_METADATAEXISTS,
+ .dump = tst_metadataexists_operation_dump,
+ .execute = tst_metadataexists_operation_execute,
+};
+
+/* Mailboxexists operation */
+
+const struct sieve_operation_def servermetadataexists_operation = {
+ .mnemonic = "SERVERMETADATAEXISTS",
+ .ext_def = &servermetadata_extension,
+ .code = EXT_METADATA_OPERATION_METADATAEXISTS,
+ .dump = tst_metadataexists_operation_dump,
+ .execute = tst_metadataexists_operation_execute,
+};
+
+/*
+ * Test validation
+ */
+
+struct _validate_context {
+ struct sieve_validator *valdtr;
+ struct sieve_command *tst;
+};
+
+static int
+tst_metadataexists_annotation_validate(void *context,
+ struct sieve_ast_argument *arg)
+{
+ struct _validate_context *valctx =
+ (struct _validate_context *)context;
+
+ if (sieve_argument_is_string_literal(arg)) {
+ const char *aname = sieve_ast_strlist_strc(arg);
+ const char *error;
+
+ if (!imap_metadata_verify_entry_name(aname, &error)) {
+ sieve_argument_validate_warning(
+ valctx->valdtr, arg, "%s test: "
+ "specified annotation name `%s' is invalid: %s",
+ sieve_command_identifier(valctx->tst),
+ str_sanitize(aname, 256),
+ sieve_error_from_external(error));
+ }
+ }
+ return 1; /* Can't check at compile time */
+}
+
+static bool
+tst_metadataexists_validate(struct sieve_validator *valdtr,
+ struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+ struct sieve_ast_argument *aarg;
+ struct _validate_context valctx;
+ unsigned int arg_index = 1;
+
+ if (sieve_command_is(tst, metadataexists_test)) {
+ if (!sieve_validate_positional_argument(valdtr, tst, arg,
+ "mailbox", arg_index++,
+ SAAT_STRING))
+ return FALSE;
+
+ if (!sieve_validator_argument_activate(valdtr, tst, arg, FALSE))
+ return FALSE;
+
+ /* Check name validity when mailbox argument is not a variable */
+ if (sieve_argument_is_string_literal(arg)) {
+ const char *mailbox = sieve_ast_argument_strc(arg);
+ const char *error;
+
+ if (!sieve_mailbox_check_name(mailbox, &error)) {
+ sieve_argument_validate_warning(
+ valdtr, arg, "%s test: "
+ "invalid mailbox name `%s' specified: %s",
+ sieve_command_identifier(tst),
+ str_sanitize(mailbox, 256), error);
+ }
+ }
+ arg = sieve_ast_argument_next(arg);
+ }
+
+ if (!sieve_validate_positional_argument(valdtr, tst, arg,
+ "annotation-names", arg_index++,
+ SAAT_STRING_LIST))
+ return FALSE;
+ if (!sieve_validator_argument_activate(valdtr, tst, arg, FALSE))
+ return FALSE;
+
+ aarg = arg;
+ i_zero(&valctx);
+ valctx.valdtr = valdtr;
+ valctx.tst = tst;
+
+ return (sieve_ast_stringlist_map(
+ &aarg, (void*)&valctx,
+ tst_metadataexists_annotation_validate) >= 0);
+}
+
+/*
+ * Test generation
+ */
+
+static bool
+tst_metadataexists_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *tst)
+{
+ if (sieve_command_is(tst, metadataexists_test)) {
+ sieve_operation_emit(cgenv->sblock, tst->ext,
+ &metadataexists_operation);
+ } else if (sieve_command_is(tst, servermetadataexists_test)) {
+ sieve_operation_emit(cgenv->sblock, tst->ext,
+ &servermetadataexists_operation);
+ } else {
+ i_unreached();
+ }
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, tst, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+tst_metadataexists_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ bool metadata = sieve_operation_is(denv->oprtn,
+ metadataexists_operation);
+
+ if (metadata)
+ sieve_code_dumpf(denv, "METADATAEXISTS");
+ else
+ sieve_code_dumpf(denv, "SERVERMETADATAEXISTS");
+
+ sieve_code_descend(denv);
+
+ if (metadata && !sieve_opr_string_dump(denv, address, "mailbox"))
+ return FALSE;
+
+ return sieve_opr_stringlist_dump(denv, address, "annotation-names");
+}
+
+/*
+ * Code execution
+ */
+
+static int
+tst_metadataexists_check_annotation(const struct sieve_runtime_env *renv,
+ struct imap_metadata_transaction *imtrans,
+ const char *mailbox, const char *aname,
+ bool *all_exist_r)
+{
+ struct mail_attribute_value avalue;
+ const char *error;
+ int ret;
+
+ if (!imap_metadata_verify_entry_name(aname, &error)) {
+ sieve_runtime_warning(
+ renv, NULL, "%s test: "
+ "specified annotation name `%s' is invalid: %s",
+ (mailbox != NULL ?
+ "metadataexists" : "servermetadataexists"),
+ str_sanitize(aname, 256),
+ sieve_error_from_external(error));
+ *all_exist_r = FALSE;
+ return SIEVE_EXEC_OK;
+ }
+
+ ret = imap_metadata_get(imtrans, aname, &avalue);
+ if (ret < 0) {
+ enum mail_error error_code;
+ const char *error;
+
+ error = imap_metadata_transaction_get_last_error(
+ imtrans, &error_code);
+ sieve_runtime_error(
+ renv, NULL, "%s test: "
+ "failed to retrieve annotation `%s': %s%s",
+ (mailbox != NULL ?
+ "metadataexists" : "servermetadataexists"),
+ str_sanitize(aname, 256),
+ sieve_error_from_external(error),
+ (error_code == MAIL_ERROR_TEMP ?
+ " (temporary failure)" : ""));
+
+ *all_exist_r = FALSE;
+ return (error_code == MAIL_ERROR_TEMP ?
+ SIEVE_EXEC_TEMP_FAILURE : SIEVE_EXEC_FAILURE);
+ }
+ if (avalue.value == NULL && avalue.value_stream == NULL) {
+ sieve_runtime_trace(renv, 0,
+ "annotation `%s': not found", aname);
+ *all_exist_r = FALSE;
+ }
+
+ sieve_runtime_trace(renv, 0, "annotation `%s': found", aname);
+ return SIEVE_EXEC_OK;
+}
+
+static int
+tst_metadataexists_check_annotations(const struct sieve_runtime_env *renv,
+ const char *mailbox,
+ struct sieve_stringlist *anames,
+ bool *all_exist_r)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ struct mail_user *user = eenv->scriptenv->user;
+ struct mailbox *box = NULL;
+ struct imap_metadata_transaction *imtrans;
+ string_t *aname;
+ bool all_exist = TRUE;
+ int ret, sret, status;
+
+ *all_exist_r = FALSE;
+
+ if (user == NULL)
+ return SIEVE_EXEC_OK;
+
+ if (mailbox != NULL) {
+ struct mail_namespace *ns;
+ ns = mail_namespace_find(user->namespaces, mailbox);
+ box = mailbox_alloc(ns->list, mailbox, 0);
+ imtrans = imap_metadata_transaction_begin(box);
+ } else {
+ imtrans = imap_metadata_transaction_begin_server(user);
+ }
+
+ if (mailbox != NULL) {
+ sieve_runtime_trace(
+ renv, SIEVE_TRLVL_TESTS,
+ "checking annotations of mailbox `%s':",
+ str_sanitize(mailbox, 80));
+ } else {
+ sieve_runtime_trace(
+ renv, SIEVE_TRLVL_TESTS,
+ "checking server annotations");
+ }
+
+ aname = NULL;
+ status = SIEVE_EXEC_OK;
+ while (all_exist &&
+ (sret = sieve_stringlist_next_item(anames, &aname)) > 0) {
+ ret = tst_metadataexists_check_annotation(
+ renv, imtrans, mailbox, str_c(aname), &all_exist);
+ if (ret <= 0) {
+ status = ret;
+ break;
+ }
+ }
+
+ if (sret < 0) {
+ sieve_runtime_trace_error(
+ renv, "invalid annotation name stringlist item");
+ status = SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ (void)imap_metadata_transaction_commit(&imtrans, NULL, NULL);
+ if (box != NULL)
+ mailbox_free(&box);
+
+ *all_exist_r = all_exist;
+ return status;
+}
+
+static int
+tst_metadataexists_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ bool metadata = sieve_operation_is(renv->oprtn,
+ metadataexists_operation);
+ struct sieve_stringlist *anames;
+ string_t *mailbox;
+ bool trace = FALSE, all_exist = TRUE;
+ const char *error;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Read mailbox */
+ if (metadata) {
+ ret = sieve_opr_string_read(renv, address, "mailbox", &mailbox);
+ if (ret <= 0)
+ return ret;
+ }
+
+ /* Read annotation names */
+ ret = sieve_opr_stringlist_read(renv, address, "annotation-names",
+ &anames);
+ if (ret <= 0)
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ if (metadata &&
+ !sieve_mailbox_check_name(str_c(mailbox), &error)) {
+ sieve_runtime_warning(
+ renv, NULL, "metadataexists test: "
+ "invalid mailbox name `%s' specified: %s",
+ str_sanitize(str_c(mailbox), 256), error);
+ sieve_interpreter_set_test_result(renv->interp, FALSE);
+ return SIEVE_EXEC_OK;
+ }
+
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_TESTS)) {
+ if (metadata) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "metadataexists test");
+ } else {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "servermetadataexists test");
+ }
+
+ sieve_runtime_trace_descend(renv);
+
+ trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING);
+ }
+
+ ret = tst_metadataexists_check_annotations(
+ renv, (metadata ? str_c(mailbox) : NULL), anames, &all_exist);
+ if (ret <= 0)
+ return ret;
+
+ if (trace) {
+ if (all_exist) {
+ sieve_runtime_trace(renv, 0,
+ "all annotations exist");
+ } else {
+ sieve_runtime_trace(renv, 0,
+ "some annotations do not exist");
+ }
+ }
+
+ sieve_interpreter_set_test_result(renv->interp, all_exist);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/mime/Makefile.am b/pigeonhole/src/lib-sieve/plugins/mime/Makefile.am
new file mode 100644
index 0000000..8ded659
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mime/Makefile.am
@@ -0,0 +1,30 @@
+noinst_LTLIBRARIES = libsieve_ext_mime.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../../util \
+ -I$(srcdir)/../variables \
+ $(LIBDOVECOT_INCLUDE)
+
+commands = \
+ cmd-foreverypart.c \
+ cmd-break.c \
+ cmd-extracttext.c
+
+tags = \
+ tag-mime.c
+
+extensions = \
+ ext-mime.c \
+ ext-foreverypart.c \
+ ext-extracttext.c
+
+libsieve_ext_mime_la_SOURCES = \
+ ext-mime-common.c \
+ $(commands) \
+ $(tags) \
+ $(extensions)
+
+noinst_HEADERS = \
+ ext-mime-common.h
+
diff --git a/pigeonhole/src/lib-sieve/plugins/mime/Makefile.in b/pigeonhole/src/lib-sieve/plugins/mime/Makefile.in
new file mode 100644
index 0000000..cfe25ff
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mime/Makefile.in
@@ -0,0 +1,727 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/mime
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_mime_la_LIBADD =
+am__objects_1 = cmd-foreverypart.lo cmd-break.lo cmd-extracttext.lo
+am__objects_2 = tag-mime.lo
+am__objects_3 = ext-mime.lo ext-foreverypart.lo ext-extracttext.lo
+am_libsieve_ext_mime_la_OBJECTS = ext-mime-common.lo $(am__objects_1) \
+ $(am__objects_2) $(am__objects_3)
+libsieve_ext_mime_la_OBJECTS = $(am_libsieve_ext_mime_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cmd-break.Plo \
+ ./$(DEPDIR)/cmd-extracttext.Plo \
+ ./$(DEPDIR)/cmd-foreverypart.Plo \
+ ./$(DEPDIR)/ext-extracttext.Plo \
+ ./$(DEPDIR)/ext-foreverypart.Plo \
+ ./$(DEPDIR)/ext-mime-common.Plo ./$(DEPDIR)/ext-mime.Plo \
+ ./$(DEPDIR)/tag-mime.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_mime_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_mime_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_mime.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../../util \
+ -I$(srcdir)/../variables \
+ $(LIBDOVECOT_INCLUDE)
+
+commands = \
+ cmd-foreverypart.c \
+ cmd-break.c \
+ cmd-extracttext.c
+
+tags = \
+ tag-mime.c
+
+extensions = \
+ ext-mime.c \
+ ext-foreverypart.c \
+ ext-extracttext.c
+
+libsieve_ext_mime_la_SOURCES = \
+ ext-mime-common.c \
+ $(commands) \
+ $(tags) \
+ $(extensions)
+
+noinst_HEADERS = \
+ ext-mime-common.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/mime/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/mime/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_mime.la: $(libsieve_ext_mime_la_OBJECTS) $(libsieve_ext_mime_la_DEPENDENCIES) $(EXTRA_libsieve_ext_mime_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_mime_la_OBJECTS) $(libsieve_ext_mime_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-break.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-extracttext.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-foreverypart.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-extracttext.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-foreverypart.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-mime-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-mime.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tag-mime.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/cmd-break.Plo
+ -rm -f ./$(DEPDIR)/cmd-extracttext.Plo
+ -rm -f ./$(DEPDIR)/cmd-foreverypart.Plo
+ -rm -f ./$(DEPDIR)/ext-extracttext.Plo
+ -rm -f ./$(DEPDIR)/ext-foreverypart.Plo
+ -rm -f ./$(DEPDIR)/ext-mime-common.Plo
+ -rm -f ./$(DEPDIR)/ext-mime.Plo
+ -rm -f ./$(DEPDIR)/tag-mime.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/cmd-break.Plo
+ -rm -f ./$(DEPDIR)/cmd-extracttext.Plo
+ -rm -f ./$(DEPDIR)/cmd-foreverypart.Plo
+ -rm -f ./$(DEPDIR)/ext-extracttext.Plo
+ -rm -f ./$(DEPDIR)/ext-foreverypart.Plo
+ -rm -f ./$(DEPDIR)/ext-mime-common.Plo
+ -rm -f ./$(DEPDIR)/ext-mime.Plo
+ -rm -f ./$(DEPDIR)/tag-mime.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/mime/cmd-break.c b/pigeonhole/src/lib-sieve/plugins/mime/cmd-break.c
new file mode 100644
index 0000000..e6ade4c
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mime/cmd-break.c
@@ -0,0 +1,273 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+
+#include "ext-mime-common.h"
+
+#include <ctype.h>
+
+/* break
+ *
+ * Syntax:
+ * break [":name" <name: string>]
+ *
+ */
+
+static bool cmd_break_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool cmd_break_pre_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool cmd_break_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool cmd_break_generate
+ (const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+const struct sieve_command_def cmd_break = {
+ .identifier = "break",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = cmd_break_registered,
+ .pre_validate = cmd_break_pre_validate,
+ .validate = cmd_break_validate,
+ .generate = cmd_break_generate,
+};
+
+/*
+ * Tagged arguments
+ */
+
+/* Forward declarations */
+
+static bool cmd_break_validate_name_tag
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+/* Argument objects */
+
+static const struct sieve_argument_def break_name_tag = {
+ .identifier = "name",
+ .validate = cmd_break_validate_name_tag
+};
+
+/*
+ * Break operation
+ */
+
+static bool cmd_break_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int cmd_break_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def break_operation = {
+ .mnemonic = "BREAK",
+ .ext_def = &foreverypart_extension,
+ .code = EXT_FOREVERYPART_OPERATION_BREAK,
+ .dump = cmd_break_operation_dump,
+ .execute = cmd_break_operation_execute
+};
+
+/*
+ * Validation data
+ */
+
+struct cmd_break_data {
+ struct sieve_ast_argument *name;
+ struct sieve_command *loop_cmd;
+};
+
+/*
+ * Tag validation
+ */
+
+static bool cmd_break_validate_name_tag
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct cmd_break_data *data =
+ (struct cmd_break_data *)cmd->data;
+ struct sieve_ast_argument *tag = *arg;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg, 1);
+
+ /* Check syntax:
+ * :name <string>
+ */
+ if ( !sieve_validate_tag_parameter
+ (valdtr, cmd, tag, *arg, NULL, 0, SAAT_STRING, TRUE) )
+ return FALSE;
+ data->name = *arg;
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+ return TRUE;
+}
+
+/*
+ * Command registration
+ */
+
+static bool cmd_break_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, ext, &break_name_tag, 0);
+
+ return TRUE;
+}
+
+/*
+ * Command validation
+ */
+
+static bool cmd_break_pre_validate
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *cmd)
+{
+ struct cmd_break_data *data;
+ pool_t pool = sieve_command_pool(cmd);
+
+ data = p_new(pool, struct cmd_break_data, 1);
+ cmd->data = data;
+ return TRUE;
+}
+
+static bool cmd_break_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ struct cmd_break_data *data =
+ (struct cmd_break_data *)cmd->data;
+ struct sieve_ast_node *node = cmd->ast_node;
+ const char *name = ( data->name == NULL ?
+ NULL : sieve_ast_argument_strc(data->name) );
+
+ i_assert(node != NULL);
+ while ( node != NULL && node->command != NULL ) {
+ if ( sieve_command_is(node->command, cmd_foreverypart) ) {
+ struct ext_foreverypart_loop *loop =
+ (struct ext_foreverypart_loop *)node->command->data;
+ if ( name == NULL ||
+ (name != NULL && loop->name != NULL &&
+ strcmp(name, loop->name) == 0) ) {
+ data->loop_cmd = node->command;
+ break;
+ }
+ }
+ node = sieve_ast_node_parent(node);
+ }
+
+ if ( data->loop_cmd == NULL ) {
+ if ( name == NULL ) {
+ sieve_command_validate_error(valdtr, cmd,
+ "the break command is not placed inside "
+ "a foreverypart loop");
+ } else {
+ sieve_command_validate_error(valdtr, cmd,
+ "the break command is not placed inside "
+ "a foreverypart loop named `%s'",
+ name);
+ }
+ return FALSE;
+ }
+
+ sieve_command_exit_block_unconditionally(cmd);
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool cmd_break_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ struct cmd_break_data *data =
+ (struct cmd_break_data *)cmd->data;
+ struct ext_foreverypart_loop *loop;
+
+ i_assert( data->loop_cmd != NULL );
+ loop = (struct ext_foreverypart_loop *)data->loop_cmd->data;
+
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &break_operation);
+ sieve_jumplist_add(loop->exit_jumps,
+ sieve_binary_emit_offset(cgenv->sblock, 0));
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool cmd_break_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ unsigned int pc = *address;
+ sieve_offset_t offset;
+
+ sieve_code_dumpf(denv, "BREAK");
+ sieve_code_descend(denv);
+
+ if ( !sieve_binary_read_offset(denv->sblock, address, &offset) )
+ return FALSE;
+
+ sieve_code_dumpf(denv, "END: %d [%08x]", offset, pc + offset);
+ return TRUE;
+}
+
+/*
+ * Code execution
+ */
+
+static int cmd_break_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ struct sieve_interpreter_loop *loop;
+ unsigned int pc = *address;
+ sieve_offset_t offset;
+ sieve_size_t loop_end;
+
+ /*
+ * Read operands
+ */
+
+ if ( !sieve_binary_read_offset(renv->sblock, address, &offset) )
+ {
+ sieve_runtime_trace_error(renv, "invalid loop end offset");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ loop_end = pc + offset;
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "break command");
+ sieve_runtime_trace_descend(renv);
+
+ loop = sieve_interpreter_loop_get
+ (renv->interp, loop_end, &foreverypart_extension);
+ if ( loop == NULL ) {
+ sieve_runtime_trace_error(renv, "no matching loop found");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ sieve_interpreter_loop_break(renv->interp, loop);
+ return SIEVE_EXEC_OK;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/mime/cmd-extracttext.c b/pigeonhole/src/lib-sieve/plugins/mime/cmd-extracttext.c
new file mode 100644
index 0000000..d9b31a2
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mime/cmd-extracttext.c
@@ -0,0 +1,370 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+#include "sieve-code.h"
+#include "sieve-ast.h"
+#include "sieve-commands.h"
+#include "sieve-binary.h"
+#include "sieve-message.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "sieve-ext-variables.h"
+
+#include "ext-mime-common.h"
+
+/*
+ * Extracttext command
+ *
+ * Syntax:
+ * extracttext [MODIFIER] [":first" number] <varname: string>
+ */
+
+static bool cmd_extracttext_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool cmd_extracttext_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool cmd_extracttext_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+const struct sieve_command_def cmd_extracttext = {
+ .identifier = "extracttext",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = cmd_extracttext_registered,
+ .validate = cmd_extracttext_validate,
+ .generate = cmd_extracttext_generate
+};
+
+/*
+ * Extracttext command tags
+ */
+
+enum cmd_extracttext_optional {
+ CMD_EXTRACTTEXT_OPT_END,
+ CMD_EXTRACTTEXT_OPT_FIRST
+};
+
+static bool cmd_extracttext_validate_first_tag
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+static const struct sieve_argument_def extracttext_from_tag = {
+ .identifier = "first",
+ .validate = cmd_extracttext_validate_first_tag
+};
+
+/*
+ * Extracttext operation
+ */
+
+static bool cmd_extracttext_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int cmd_extracttext_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def extracttext_operation = {
+ .mnemonic = "EXTRACTTEXT",
+ .ext_def = &extracttext_extension,
+ .dump = cmd_extracttext_operation_dump,
+ .execute = cmd_extracttext_operation_execute
+};
+
+/*
+ * Compiler context
+ */
+
+struct cmd_extracttext_context {
+ ARRAY_TYPE(sieve_variables_modifier) modifiers;
+};
+
+/*
+ * Tag validation
+ */
+
+static bool cmd_extracttext_validate_first_tag
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ /* Check syntax:
+ * :first <number>
+ */
+ if ( !sieve_validate_tag_parameter
+ (valdtr, cmd, tag, *arg, NULL, 0, SAAT_NUMBER, FALSE) )
+ return FALSE;
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+/* Command registration */
+
+static bool cmd_extracttext_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ struct ext_extracttext_context *ectx =
+ (struct ext_extracttext_context *)ext->context;
+
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &extracttext_from_tag, CMD_EXTRACTTEXT_OPT_FIRST);
+ sieve_variables_modifiers_link_tag
+ (valdtr, ectx->var_ext, cmd_reg);
+ return TRUE;
+}
+
+/*
+ * Command validation
+ */
+
+static bool cmd_extracttext_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd)
+{
+ const struct sieve_extension *this_ext = cmd->ext;
+ struct ext_extracttext_context *ectx =
+ (struct ext_extracttext_context *)this_ext->context;
+ struct sieve_ast_node *node = cmd->ast_node;
+ struct sieve_ast_argument *arg = cmd->first_positional;
+ pool_t pool = sieve_command_pool(cmd);
+ struct cmd_extracttext_context *sctx;
+
+ /* Create command context */
+ sctx = p_new(pool, struct cmd_extracttext_context, 1);
+ p_array_init(&sctx->modifiers, pool, 4);
+ cmd->data = (void *) sctx;
+
+ /* Validate modifiers */
+ if ( !sieve_variables_modifiers_validate
+ (valdtr, cmd, &sctx->modifiers) )
+ return FALSE;
+
+ /* Validate varname argument */
+ if ( !sieve_validate_positional_argument
+ (valdtr, cmd, arg, "varname", 1, SAAT_STRING) ) {
+ return FALSE;
+ }
+ if ( !sieve_variable_argument_activate
+ (ectx->var_ext, ectx->var_ext, valdtr, cmd, arg, TRUE) )
+ return FALSE;
+
+ /* Check foreverypart context */
+ i_assert(node != NULL);
+ while ( node != NULL ) {
+ if ( node->command != NULL &&
+ sieve_command_is(node->command, cmd_foreverypart) )
+ break;
+ node = sieve_ast_node_parent(node);
+ }
+
+ if ( node == NULL ) {
+ sieve_command_validate_error(valdtr, cmd,
+ "the extracttext command is not placed inside "
+ "a foreverypart loop");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool cmd_extracttext_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ const struct sieve_extension *this_ext = cmd->ext;
+ struct sieve_binary_block *sblock = cgenv->sblock;
+ struct cmd_extracttext_context *sctx =
+ (struct cmd_extracttext_context *) cmd->data;
+
+ sieve_operation_emit(sblock, this_ext, &extracttext_operation);
+
+ /* Generate arguments */
+ if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
+ return FALSE;
+
+ /* Generate modifiers */
+ if ( !sieve_variables_modifiers_generate
+ (cgenv, &sctx->modifiers) )
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool cmd_extracttext_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "EXTRACTTEXT");
+ sieve_code_descend(denv);
+
+ /* Dump optional operands */
+
+ for (;;) {
+ int opt;
+ bool opok = TRUE;
+
+ if ( (opt=sieve_opr_optional_dump(denv, address, &opt_code)) < 0 )
+ return FALSE;
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case CMD_EXTRACTTEXT_OPT_FIRST:
+ opok = sieve_opr_number_dump(denv, address, "first");
+ break;
+ default:
+ return FALSE;
+ }
+ if ( !opok ) return FALSE;
+ }
+
+ /* Print both variable name and string value */
+ if ( !sieve_opr_string_dump(denv, address, "varname") )
+ return FALSE;
+
+ return sieve_variables_modifiers_code_dump(denv, address);
+}
+
+/*
+ * Code execution
+ */
+
+static int cmd_extracttext_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ struct ext_extracttext_context *ectx =
+ (struct ext_extracttext_context *)this_ext->context;
+ struct sieve_variable_storage *storage;
+ ARRAY_TYPE(sieve_variables_modifier) modifiers;
+ struct ext_foreverypart_runtime_loop *sfploop;
+ struct sieve_message_part *mpart;
+ struct sieve_message_part_data mpart_data;
+ int opt_code = 0;
+ sieve_number_t first = 0;
+ string_t *value;
+ unsigned int var_index;
+ bool have_first = FALSE;
+ int ret = SIEVE_EXEC_OK;
+
+ /*
+ * Read the normal operands
+ */
+
+ /* Optional operands */
+
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_opr_optional_read
+ (renv, address, &opt_code)) < 0 )
+ return SIEVE_EXEC_BIN_CORRUPT;
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case CMD_EXTRACTTEXT_OPT_FIRST:
+ ret = sieve_opr_number_read
+ (renv, address, "first", &first);
+ have_first = TRUE;
+ break;
+ default:
+ sieve_runtime_trace_error(renv, "unknown optional operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ if ( ret <= 0 ) return ret;
+ }
+
+ /* Varname operand */
+
+ if ( (ret=sieve_variable_operand_read
+ (renv, address, "varname", &storage, &var_index)) <= 0 )
+ return ret;
+
+ /* Modifiers */
+
+ if ( (ret=sieve_variables_modifiers_code_read
+ (renv, ectx->var_ext, address, &modifiers)) <= 0 )
+ return ret;
+
+ /*
+ * Determine and assign the value
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "extracttext command");
+ sieve_runtime_trace_descend(renv);
+
+ sfploop = ext_foreverypart_runtime_loop_get_current(renv);
+ if ( sfploop == NULL ) {
+ sieve_runtime_trace_error(renv,
+ "outside foreverypart context");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ /* Get current message part */
+ mpart = sieve_message_part_iter_current(&sfploop->part_iter);
+ i_assert( mpart != NULL );
+
+ /* Get message part content */
+ sieve_message_part_get_data(mpart, &mpart_data, TRUE);
+
+ /* Apply ":first" limit, if any */
+ if ( !have_first || (size_t)first > mpart_data.size ) {
+ value = t_str_new_const(mpart_data.content, mpart_data.size);
+ } else {
+ value = t_str_new((size_t)first);
+ str_append_data(value, mpart_data.content, (size_t)first);
+ }
+
+ /* Apply modifiers */
+ if ( (ret=sieve_variables_modifiers_apply
+ (renv, ectx->var_ext, &modifiers, &value)) <= 0 )
+ return ret;
+
+ /* Actually assign the value if all is well */
+ i_assert ( value != NULL );
+ if ( !sieve_variable_assign(storage, var_index, value) )
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ /* Trace */
+ if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+ const char *var_name, *var_id;
+
+ (void)sieve_variable_get_identifier(storage, var_index, &var_name);
+ var_id = sieve_variable_get_varid(storage, var_index);
+
+ sieve_runtime_trace_here(renv, 0, "assign `%s' [%s] = \"%s\"",
+ var_name, var_id, str_c(value));
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+
+
+
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/mime/cmd-foreverypart.c b/pigeonhole/src/lib-sieve/plugins/mime/cmd-foreverypart.c
new file mode 100644
index 0000000..435cb5c
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mime/cmd-foreverypart.c
@@ -0,0 +1,377 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-limits.h"
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+#include "sieve-message.h"
+
+#include "ext-mime-common.h"
+
+#include <ctype.h>
+
+/* Foreverypart
+ *
+ * Syntax:
+ * foreverypart [":name" <name: string>] <block>
+ *
+ */
+
+static bool cmd_foreverypart_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool cmd_foreverypart_pre_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool cmd_foreverypart_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool cmd_foreverypart_generate
+ (const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+const struct sieve_command_def cmd_foreverypart = {
+ .identifier = "foreverypart",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = TRUE,
+ .block_required = TRUE,
+ .registered = cmd_foreverypart_registered,
+ .pre_validate = cmd_foreverypart_pre_validate,
+ .validate = cmd_foreverypart_validate,
+ .generate = cmd_foreverypart_generate
+};
+
+/*
+ * Tagged arguments
+ */
+
+/* Forward declarations */
+
+static bool cmd_foreverypart_validate_name_tag
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+/* Argument objects */
+
+static const struct sieve_argument_def foreverypart_name_tag = {
+ .identifier = "name",
+ .validate = cmd_foreverypart_validate_name_tag,
+};
+
+/*
+ * foreverypart operation
+ */
+
+static bool cmd_foreverypart_begin_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int cmd_foreverypart_begin_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def foreverypart_begin_operation = {
+ .mnemonic = "FOREVERYPART_BEGIN",
+ .ext_def = &foreverypart_extension,
+ .code = EXT_FOREVERYPART_OPERATION_FOREVERYPART_BEGIN,
+ .dump = cmd_foreverypart_begin_operation_dump,
+ .execute = cmd_foreverypart_begin_operation_execute
+};
+
+static bool cmd_foreverypart_end_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int cmd_foreverypart_end_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def foreverypart_end_operation = {
+ .mnemonic = "FOREVERYPART_END",
+ .ext_def = &foreverypart_extension,
+ .code = EXT_FOREVERYPART_OPERATION_FOREVERYPART_END,
+ .dump = cmd_foreverypart_end_operation_dump,
+ .execute = cmd_foreverypart_end_operation_execute
+};
+
+/*
+ * Tag validation
+ */
+
+static bool cmd_foreverypart_validate_name_tag
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct ext_foreverypart_loop *loop =
+ (struct ext_foreverypart_loop *)cmd->data;
+ struct sieve_ast_argument *tag = *arg;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg, 1);
+
+ /* Check syntax:
+ * :name <string>
+ */
+ if ( !sieve_validate_tag_parameter
+ (valdtr, cmd, tag, *arg, NULL, 0, SAAT_STRING, TRUE) )
+ return FALSE;
+ loop->name = sieve_ast_argument_strc(*arg);
+
+ /* Detach parameter */
+ *arg = sieve_ast_arguments_detach(*arg, 1);
+ return TRUE;
+}
+
+/*
+ * Command registration
+ */
+
+static bool cmd_foreverypart_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, ext, &foreverypart_name_tag, 0);
+ return TRUE;
+}
+
+/*
+ * Command validation
+ */
+
+static bool cmd_foreverypart_pre_validate
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *cmd)
+{
+ struct ext_foreverypart_loop *loop;
+ pool_t pool = sieve_command_pool(cmd);
+
+ loop = p_new(pool, struct ext_foreverypart_loop, 1);
+ cmd->data = loop;
+
+ return TRUE;
+}
+
+static bool cmd_foreverypart_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ struct sieve_ast_node *node = cmd->ast_node;
+ unsigned int nesting = 0;
+
+ /* Determine nesting depth of foreverypart commands at this point. */
+ i_assert(node != NULL);
+ node = sieve_ast_node_parent(node);
+ while ( node != NULL && node->command != NULL ) {
+ if ( sieve_command_is(node->command, cmd_foreverypart) )
+ nesting++;
+ node = sieve_ast_node_parent(node);
+ }
+
+ /* Enforce nesting limit
+ NOTE: this only recognizes the foreverypart command as a loop; if
+ new loop commands are introduced in the future, these must be
+ recognized somehow. */
+ if ( nesting + 1 > SIEVE_MAX_LOOP_DEPTH ) {
+ sieve_command_validate_error(valdtr, cmd,
+ "the nested foreverypart loop exceeds "
+ "the nesting limit (<= %u levels)",
+ SIEVE_MAX_LOOP_DEPTH);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool cmd_foreverypart_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ struct ext_foreverypart_loop *loop =
+ (struct ext_foreverypart_loop *)cmd->data;
+ sieve_size_t block_begin, loop_jump;
+
+ /* Emit FOREVERYPART_BEGIN operation */
+ sieve_operation_emit(cgenv->sblock,
+ cmd->ext, &foreverypart_begin_operation);
+
+ /* Emit exit address */
+ loop->exit_jumps = sieve_jumplist_create
+ (sieve_command_pool(cmd), cgenv->sblock);
+ sieve_jumplist_add(loop->exit_jumps,
+ sieve_binary_emit_offset(cgenv->sblock, 0));
+ block_begin = sieve_binary_block_get_size(cgenv->sblock);
+
+ /* Generate loop block */
+ if ( !sieve_generate_block(cgenv, cmd->ast_node) )
+ return FALSE;
+
+ /* Emit FOREVERYPART_END operation */
+ sieve_operation_emit(cgenv->sblock,
+ cmd->ext, &foreverypart_end_operation);
+ loop_jump = sieve_binary_block_get_size(cgenv->sblock);
+ i_assert(loop_jump > block_begin);
+ (void)sieve_binary_emit_offset
+ (cgenv->sblock, (loop_jump - block_begin));
+
+ /* Resolve exit address */
+ sieve_jumplist_resolve(loop->exit_jumps);
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool cmd_foreverypart_begin_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ unsigned int pc = *address;
+ sieve_offset_t offset;
+
+ sieve_code_dumpf(denv, "FOREVERYPART_BEGIN");
+ sieve_code_descend(denv);
+
+ if ( !sieve_binary_read_offset(denv->sblock, address, &offset) )
+ return FALSE;
+
+ sieve_code_dumpf(denv, "END: %d [%08x]", offset, pc + offset);
+ return TRUE;
+}
+
+static bool cmd_foreverypart_end_operation_dump
+(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ unsigned int pc = *address;
+ sieve_offset_t offset;
+
+ sieve_code_dumpf(denv, "FOREVERYPART_END");
+ sieve_code_descend(denv);
+
+ if ( !sieve_binary_read_offset(denv->sblock, address, &offset) )
+ return FALSE;
+
+ sieve_code_dumpf(denv, "BEGIN: -%d [%08x]", offset, pc - offset);
+ return TRUE;
+}
+
+/*
+ * Code execution
+ */
+
+static int cmd_foreverypart_begin_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ struct sieve_interpreter_loop *loop;
+ struct ext_foreverypart_runtime_loop *fploop, *sfploop;
+ unsigned int pc = *address;
+ sieve_offset_t offset;
+ sieve_size_t loop_end;
+ pool_t pool;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ if ( !sieve_binary_read_offset(renv->sblock, address, &offset) )
+ {
+ sieve_runtime_trace_error(renv, "invalid loop end offset");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ loop_end = pc + offset;
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
+ "foreverypart loop begin");
+ sieve_runtime_trace_descend(renv);
+
+ sfploop = ext_foreverypart_runtime_loop_get_current(renv);
+
+ if ( (ret=sieve_interpreter_loop_start(renv->interp,
+ loop_end, &foreverypart_extension, &loop)) <= 0 )
+ return ret;
+
+ pool = sieve_interpreter_loop_get_pool(loop);
+ fploop = p_new(pool, struct ext_foreverypart_runtime_loop, 1);
+
+ if ( sfploop == NULL ) {
+ if ( (ret=sieve_message_part_iter_init
+ (&fploop->part_iter, renv)) <= 0 )
+ return ret;
+ } else {
+ sieve_message_part_iter_children(&sfploop->part_iter,
+ &fploop->part_iter);
+ }
+ fploop->part = sieve_message_part_iter_current(&fploop->part_iter);
+ if (fploop->part != NULL) {
+ sieve_interpreter_loop_set_context(loop, (void*)fploop);
+ } else {
+ /* No children parts to iterate */
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
+ "no children at this level");
+ sieve_interpreter_loop_break(renv->interp, loop);
+ }
+ return SIEVE_EXEC_OK;
+}
+
+static int cmd_foreverypart_end_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ struct sieve_interpreter_loop *loop;
+ struct ext_foreverypart_runtime_loop *fploop;
+ unsigned int pc = *address;
+ sieve_offset_t offset;
+ sieve_size_t loop_begin;
+
+ /*
+ * Read operands
+ */
+
+ if ( !sieve_binary_read_offset(renv->sblock, address, &offset) )
+ {
+ sieve_runtime_trace_error(renv, "invalid loop begin offset");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ loop_begin = pc - offset;
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv,
+ SIEVE_TRLVL_COMMANDS, "foreverypart loop end");
+ sieve_runtime_trace_descend(renv);
+
+ loop = sieve_interpreter_loop_get
+ (renv->interp, *address, &foreverypart_extension);
+ if ( loop == NULL ) {
+ sieve_runtime_trace_error(renv, "no matching loop found");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ fploop = (struct ext_foreverypart_runtime_loop *)
+ sieve_interpreter_loop_get_context(loop);
+ i_assert(fploop->part != NULL);
+ fploop->part = sieve_message_part_iter_next(&fploop->part_iter);
+ if ( fploop->part == NULL ) {
+ sieve_runtime_trace(renv,
+ SIEVE_TRLVL_COMMANDS, "no more message parts");
+ return sieve_interpreter_loop_break(renv->interp, loop);
+ }
+
+ sieve_runtime_trace(renv,
+ SIEVE_TRLVL_COMMANDS, "switched to next message part");
+ return sieve_interpreter_loop_next(renv->interp, loop, loop_begin);
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/mime/ext-extracttext.c b/pigeonhole/src/lib-sieve/plugins/mime/ext-extracttext.c
new file mode 100644
index 0000000..4eab76b
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mime/ext-extracttext.c
@@ -0,0 +1,130 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension extracttext
+ * ---------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5703, Section 7
+ * Implementation: full
+ * Status: experimental
+ *
+ */
+
+#include "sieve-common.h"
+
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-actions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-result.h"
+
+#include "sieve-ext-variables.h"
+
+#include "ext-mime-common.h"
+
+/*
+ * Extension
+ */
+
+static bool ext_extracttext_load
+ (const struct sieve_extension *ext, void **context);
+static void ext_extracttext_unload
+ (const struct sieve_extension *ext);
+static bool ext_extracttext_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def extracttext_extension = {
+ .name = "extracttext",
+ .load = ext_extracttext_load,
+ .unload = ext_extracttext_unload,
+ .validator_load = ext_extracttext_validator_load,
+ SIEVE_EXT_DEFINE_OPERATION(extracttext_operation)
+};
+
+static bool ext_extracttext_load
+(const struct sieve_extension *ext, void **context)
+{
+ struct sieve_instance *svinst = ext->svinst;
+ struct ext_extracttext_context *ectx;
+
+ if ( *context != NULL )
+ ext_extracttext_unload(ext);
+
+ ectx = i_new(struct ext_extracttext_context, 1);
+ ectx->var_ext = sieve_ext_variables_get_extension(ext->svinst);
+ ectx->fep_ext = sieve_extension_register
+ (svinst, &foreverypart_extension, FALSE);
+ *context = (void *)ectx;
+ return TRUE;
+}
+
+static void ext_extracttext_unload
+(const struct sieve_extension *ext)
+{
+ struct ext_extracttext_context *ctx =
+ (struct ext_extracttext_context *) ext->context;
+
+ i_free(ctx);
+}
+
+/*
+ * Extension validation
+ */
+
+static bool ext_extracttext_validator_validate
+ (const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context,
+ struct sieve_ast_argument *require_arg,
+ bool required);
+
+const struct sieve_validator_extension
+extracttext_validator_extension = {
+ .ext = &extracttext_extension,
+ .validate = ext_extracttext_validator_validate
+};
+
+static bool ext_extracttext_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Register validator extension to check for conflict with eextracttext */
+ sieve_validator_extension_register
+ (valdtr, ext, &extracttext_validator_extension, NULL);
+
+ /* Register new commands */
+ sieve_validator_register_command(valdtr, ext, &cmd_extracttext);
+
+ return TRUE;
+}
+
+static bool ext_extracttext_validator_validate
+(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context ATTR_UNUSED,
+ struct sieve_ast_argument *require_arg,
+ bool required ATTR_UNUSED)
+{
+ struct ext_extracttext_context *ectx =
+ (struct ext_extracttext_context *)ext->context;
+
+ if ( ectx->var_ext == NULL ||
+ !sieve_ext_variables_is_active
+ (ectx->var_ext, valdtr) ) {
+ sieve_argument_validate_error(valdtr, require_arg,
+ "extracttext extension cannot be used "
+ "without variables extension");
+ return FALSE;
+ }
+ if ( ectx->fep_ext == NULL ||
+ !sieve_validator_extension_loaded
+ (valdtr, ectx->fep_ext) ) {
+ sieve_argument_validate_error(valdtr, require_arg,
+ "extracttext extension cannot be used "
+ "without foreverypart extension");
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/mime/ext-foreverypart.c b/pigeonhole/src/lib-sieve/plugins/mime/ext-foreverypart.c
new file mode 100644
index 0000000..6bca199
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mime/ext-foreverypart.c
@@ -0,0 +1,62 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension foreverypart
+ * ----------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5703, Section 3
+ * Implementation: full
+ * Status: experimental
+ *
+ */
+
+#include "sieve-common.h"
+
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-actions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-result.h"
+
+#include "ext-mime-common.h"
+
+/*
+ * Operations
+ */
+
+const struct sieve_operation_def *ext_foreverypart_operations[] = {
+ &foreverypart_begin_operation,
+ &foreverypart_end_operation,
+ &break_operation
+};
+
+/*
+ * Extension
+ */
+
+static bool ext_foreverypart_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def foreverypart_extension = {
+ .name = "foreverypart",
+ .validator_load = ext_foreverypart_validator_load,
+ SIEVE_EXT_DEFINE_OPERATIONS(ext_foreverypart_operations)
+};
+
+/*
+ * Extension validation
+ */
+
+static bool ext_foreverypart_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Register new commands */
+ sieve_validator_register_command(valdtr, ext, &cmd_foreverypart);
+ sieve_validator_register_command(valdtr, ext, &cmd_break);
+
+ return TRUE;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/mime/ext-mime-common.c b/pigeonhole/src/lib-sieve/plugins/mime/ext-mime-common.c
new file mode 100644
index 0000000..5b38bcb
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mime/ext-mime-common.c
@@ -0,0 +1,27 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-interpreter.h"
+
+#include "ext-mime-common.h"
+
+struct ext_foreverypart_runtime_loop *
+ext_foreverypart_runtime_loop_get_current
+(const struct sieve_runtime_env *renv)
+{
+ struct sieve_interpreter_loop *loop;
+ struct ext_foreverypart_runtime_loop *fploop;
+
+ loop = sieve_interpreter_loop_get_global
+ (renv->interp, NULL, &foreverypart_extension);
+ if ( loop == NULL ) {
+ fploop = NULL;
+ } else {
+ fploop = (struct ext_foreverypart_runtime_loop *)
+ sieve_interpreter_loop_get_context(loop);
+ i_assert(fploop->part != NULL);
+ }
+
+ return fploop;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/mime/ext-mime-common.h b/pigeonhole/src/lib-sieve/plugins/mime/ext-mime-common.h
new file mode 100644
index 0000000..8b0054d
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mime/ext-mime-common.h
@@ -0,0 +1,85 @@
+#ifndef EXT_FOREVERYPART_COMMON_H
+#define EXT_FOREVERYPART_COMMON_H
+
+#include "sieve-message.h"
+
+/*
+ * Extension
+ */
+
+struct ext_extracttext_context {
+ const struct sieve_extension *var_ext;
+ const struct sieve_extension *fep_ext;
+};
+
+extern const struct sieve_extension_def foreverypart_extension;
+extern const struct sieve_extension_def mime_extension;
+extern const struct sieve_extension_def extracttext_extension;
+
+/*
+ * Tagged arguments
+ */
+
+extern const struct sieve_argument_def mime_tag;
+extern const struct sieve_argument_def mime_anychild_tag;
+extern const struct sieve_argument_def mime_type_tag;
+extern const struct sieve_argument_def mime_subtype_tag;
+extern const struct sieve_argument_def mime_contenttype_tag;
+extern const struct sieve_argument_def mime_param_tag;
+
+/*
+ * Commands
+ */
+
+struct ext_foreverypart_loop {
+ const char *name;
+ struct sieve_jumplist *exit_jumps;
+};
+
+extern const struct sieve_command_def cmd_foreverypart;
+extern const struct sieve_command_def cmd_break;
+extern const struct sieve_command_def cmd_extracttext;
+
+/*
+ * Operations
+ */
+
+extern const struct sieve_operation_def foreverypart_begin_operation;
+extern const struct sieve_operation_def foreverypart_end_operation;
+extern const struct sieve_operation_def break_operation;
+extern const struct sieve_operation_def extracttext_operation;
+
+enum ext_foreverypart_opcode {
+ EXT_FOREVERYPART_OPERATION_FOREVERYPART_BEGIN,
+ EXT_FOREVERYPART_OPERATION_FOREVERYPART_END,
+ EXT_FOREVERYPART_OPERATION_BREAK,
+};
+
+/*
+ * Operands
+ */
+
+enum ext_mime_option {
+ EXT_MIME_OPTION_NONE = 0,
+ EXT_MIME_OPTION_TYPE,
+ EXT_MIME_OPTION_SUBTYPE,
+ EXT_MIME_OPTION_CONTENTTYPE,
+ EXT_MIME_OPTION_PARAM
+};
+
+extern const struct sieve_operand_def mime_operand;
+
+/*
+ * Foreverypart loop
+ */
+
+struct ext_foreverypart_runtime_loop {
+ struct sieve_message_part_iter part_iter;
+ struct sieve_message_part *part;
+};
+
+struct ext_foreverypart_runtime_loop *
+ext_foreverypart_runtime_loop_get_current
+(const struct sieve_runtime_env *renv);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/mime/ext-mime.c b/pigeonhole/src/lib-sieve/plugins/mime/ext-mime.c
new file mode 100644
index 0000000..da9963f
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mime/ext-mime.c
@@ -0,0 +1,77 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension mime
+ * --------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5703, Section 4
+ * Implementation: full
+ * Status: experimental
+ *
+ */
+
+#include "sieve-common.h"
+
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-actions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-message.h"
+#include "sieve-result.h"
+
+#include "ext-mime-common.h"
+
+/*
+ * Extension
+ */
+
+static bool ext_mime_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def mime_extension = {
+ .name = "mime",
+ .validator_load = ext_mime_validator_load,
+ SIEVE_EXT_DEFINE_OPERAND(mime_operand)
+};
+
+/*
+ * Extension validation
+ */
+
+static bool ext_mime_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Register :mime tag and friends with header, address and exists test
+ * commands and we don't care whether these command are registered or
+ * even whether these will be registered at all. The validator handles
+ * either situation gracefully.
+ */
+ sieve_validator_register_external_tag
+ (valdtr, "header", ext, &mime_tag, SIEVE_OPT_MESSAGE_OVERRIDE);
+ sieve_validator_register_external_tag
+ (valdtr, "header", ext, &mime_anychild_tag, 0);
+ sieve_validator_register_external_tag
+ (valdtr, "header", ext, &mime_type_tag, 0);
+ sieve_validator_register_external_tag
+ (valdtr, "header", ext, &mime_subtype_tag, 0);
+ sieve_validator_register_external_tag
+ (valdtr, "header", ext, &mime_contenttype_tag, 0);
+ sieve_validator_register_external_tag
+ (valdtr, "header", ext, &mime_param_tag, 0);
+
+ sieve_validator_register_external_tag
+ (valdtr, "address", ext, &mime_tag, SIEVE_OPT_MESSAGE_OVERRIDE);
+ sieve_validator_register_external_tag
+ (valdtr, "address", ext, &mime_anychild_tag, 0);
+
+ sieve_validator_register_external_tag
+ (valdtr, "exists", ext, &mime_tag, SIEVE_OPT_MESSAGE_OVERRIDE);
+ sieve_validator_register_external_tag
+ (valdtr, "exists", ext, &mime_anychild_tag, 0);
+
+ return TRUE;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/mime/tag-mime.c b/pigeonhole/src/lib-sieve/plugins/mime/tag-mime.c
new file mode 100644
index 0000000..379365e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/mime/tag-mime.c
@@ -0,0 +1,757 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "rfc822-parser.h"
+#include "rfc2231-parser.h"
+#include "mail-storage.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-binary.h"
+#include "sieve-code.h"
+#include "sieve-message.h"
+#include "sieve-result.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+
+#include "ext-mime-common.h"
+
+/*
+ * Tagged argument
+ */
+
+static bool tag_mime_validate
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool tag_mime_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *context);
+
+const struct sieve_argument_def mime_tag = {
+ .identifier = "mime",
+ .validate = tag_mime_validate,
+ .generate = tag_mime_generate
+};
+
+static bool tag_mime_option_validate
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+const struct sieve_argument_def mime_anychild_tag = {
+ .identifier = "anychild",
+ .validate = tag_mime_option_validate
+};
+
+const struct sieve_argument_def mime_type_tag = {
+ .identifier = "type",
+ .validate = tag_mime_option_validate
+};
+
+const struct sieve_argument_def mime_subtype_tag = {
+ .identifier = "subtype",
+ .validate = tag_mime_option_validate
+};
+
+const struct sieve_argument_def mime_contenttype_tag = {
+ .identifier = "contenttype",
+ .validate = tag_mime_option_validate
+};
+
+const struct sieve_argument_def mime_param_tag = {
+ .identifier = "param",
+ .validate = tag_mime_option_validate
+};
+
+/*
+ * Header override
+ */
+
+static bool svmo_mime_dump_context
+ (const struct sieve_message_override *svmo,
+ const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int svmo_mime_read_context
+ (const struct sieve_message_override *svmo,
+ const struct sieve_runtime_env *renv, sieve_size_t *address,
+ void **ho_context);
+static int svmo_mime_header_override
+ (const struct sieve_message_override *svmo,
+ const struct sieve_runtime_env *renv,
+ bool mime_decode, struct sieve_stringlist **headers);
+
+const struct sieve_message_override_def mime_header_override = {
+ SIEVE_OBJECT("mime", &mime_operand, 0),
+ .sequence = 0, /* Completely replace header source */
+ .dump_context = svmo_mime_dump_context,
+ .read_context = svmo_mime_read_context,
+ .header_override = svmo_mime_header_override
+};
+
+/*
+ * Operand
+ */
+
+static const struct sieve_extension_objects ext_header_overrides =
+ SIEVE_EXT_DEFINE_MESSAGE_OVERRIDE(mime_header_override);
+
+const struct sieve_operand_def mime_operand = {
+ .name = "mime operand",
+ .ext_def = &mime_extension,
+ .class = &sieve_message_override_operand_class,
+ .interface = &ext_header_overrides
+};
+
+/*
+ * Tag data
+ */
+
+struct tag_mime_data {
+ enum ext_mime_option mimeopt;
+ struct sieve_ast_argument *param_arg;
+ bool anychild:1;
+};
+
+/*
+ * Tag validation
+ */
+
+static struct tag_mime_data *
+tag_mime_get_data(struct sieve_command *cmd,
+ struct sieve_ast_argument *tag)
+{
+ struct tag_mime_data *data;
+
+ if (tag->argument->data == NULL) {
+ data = p_new(sieve_command_pool(cmd), struct tag_mime_data, 1);
+ tag->argument->data = (void *)data;
+ } else {
+ data = (struct tag_mime_data *)tag->argument->data;
+ }
+
+ return data;
+}
+
+static bool tag_mime_validate
+(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_ast_argument **arg, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+
+ /* Skip the tag itself */
+ *arg = sieve_ast_argument_next(*arg);
+
+ (void)tag_mime_get_data(cmd, tag);
+ return TRUE;
+}
+
+static bool tag_mime_option_validate
+(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_ast_argument **arg, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+ struct sieve_ast_argument *mime_arg;
+ struct tag_mime_data *data;
+
+ i_assert(tag != NULL);
+
+ /* Detach tag itself */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ /* Find required ":mime" tag */
+ mime_arg = sieve_command_find_argument(cmd, &mime_tag);
+ if ( mime_arg == NULL ) {
+ sieve_argument_validate_error(valdtr, tag,
+ "the :%s tag for the %s %s cannot be specified "
+ "without the :mime tag", sieve_ast_argument_tag(tag),
+ sieve_command_identifier(cmd), sieve_command_type_name(cmd));
+ return FALSE;
+ }
+
+ /* Annotate ":mime" tag with the data provided by this option tag */
+ data = tag_mime_get_data(cmd, mime_arg);
+ if ( sieve_argument_is(tag, mime_anychild_tag) )
+ data->anychild = TRUE;
+ else {
+ if ( data->mimeopt != EXT_MIME_OPTION_NONE ) {
+ sieve_argument_validate_error(valdtr, *arg,
+ "the :type, :subtype, :contenttype, and :param "
+ "arguments for the %s test are mutually exclusive, "
+ "but more than one was specified",
+ sieve_command_identifier(cmd));
+ return FALSE;
+ }
+ if ( sieve_argument_is(tag, mime_type_tag) )
+ data->mimeopt = EXT_MIME_OPTION_TYPE;
+ else if ( sieve_argument_is(tag, mime_subtype_tag) )
+ data->mimeopt = EXT_MIME_OPTION_SUBTYPE;
+ else if ( sieve_argument_is(tag, mime_contenttype_tag) )
+ data->mimeopt = EXT_MIME_OPTION_CONTENTTYPE;
+ else if ( sieve_argument_is(tag, mime_param_tag) ) {
+ /* Check syntax:
+ * ":param" <param-list: string-list>
+ */
+ if ( !sieve_validate_tag_parameter
+ (valdtr, cmd, tag, *arg, NULL, 0, SAAT_STRING_LIST, FALSE) ) {
+ return FALSE;
+ }
+
+ data->mimeopt = EXT_MIME_OPTION_PARAM;
+ data->param_arg = *arg;
+
+ /* Detach parameter */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+ } else
+ i_unreached();
+ }
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool tag_mime_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd)
+{
+ struct tag_mime_data *data =
+ (struct tag_mime_data *)arg->argument->data;
+
+ if ( sieve_ast_argument_type(arg) != SAAT_TAG )
+ return FALSE;
+
+ sieve_opr_message_override_emit
+ (cgenv->sblock, arg->argument->ext, &mime_header_override);
+
+ (void)sieve_binary_emit_byte
+ (cgenv->sblock, ( data->anychild ? 1 : 0 ));
+ (void)sieve_binary_emit_byte
+ (cgenv->sblock, data->mimeopt);
+ if ( data->mimeopt == EXT_MIME_OPTION_PARAM &&
+ !sieve_generate_argument(cgenv, data->param_arg, cmd) )
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Content-type stringlist
+ */
+
+enum content_type_part {
+ CONTENT_TYPE_PART_NONE = 0,
+ CONTENT_TYPE_PART_TYPE,
+ CONTENT_TYPE_PART_SUBTYPE,
+ CONTENT_TYPE_PART_CONTENTTYPE,
+};
+
+/* Object */
+
+static int content_header_stringlist_next_item
+ (struct sieve_stringlist *_strlist, string_t **str_r);
+static void content_header_stringlist_reset
+ (struct sieve_stringlist *_strlist);
+static int content_header_stringlist_get_length
+ (struct sieve_stringlist *_strlist);
+static void content_header_stringlist_set_trace
+ (struct sieve_stringlist *strlist, bool trace);
+
+struct content_header_stringlist {
+ struct sieve_stringlist strlist;
+
+ struct sieve_header_list *source;
+
+ enum ext_mime_option option;
+ const char *const *params;
+
+ const char *const *param_values;
+};
+
+static struct sieve_stringlist *content_header_stringlist_create
+(const struct sieve_runtime_env *renv,
+ struct sieve_header_list *source,
+ enum ext_mime_option option, const char *const *params)
+{
+ struct content_header_stringlist *strlist;
+
+ strlist = t_new(struct content_header_stringlist, 1);
+ strlist->strlist.runenv = renv;
+ strlist->strlist.exec_status = SIEVE_EXEC_OK;
+ strlist->strlist.next_item = content_header_stringlist_next_item;
+ strlist->strlist.reset = content_header_stringlist_reset;
+ strlist->strlist.set_trace = content_header_stringlist_set_trace;
+ strlist->source = source;
+ strlist->option = option;
+ strlist->params = params;
+
+ if ( option != EXT_MIME_OPTION_PARAM ) {
+ /* One header can have multiple parameters, so we cannot rely
+ on the source length for the :param option. */
+ strlist->strlist.get_length = content_header_stringlist_get_length;
+ }
+
+ return &strlist->strlist;
+}
+
+/* Implementation */
+
+static inline int _decode_hex_digit(const unsigned char digit)
+{
+ switch ( digit ) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ return digit - '0';
+
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ return digit - 'a' + 0x0a;
+
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ return digit - 'A' + 0x0A;
+ }
+ return -1;
+}
+
+static string_t *
+content_type_param_decode(const char *value)
+{
+ const unsigned char *p, *plast;
+
+ string_t *str = t_str_new(64);
+ plast = p = (const unsigned char *)value;
+ while ( *p != '\0' ) {
+ unsigned char ch;
+ int digit;
+
+ if ( *p == '%' ) {
+ if ( p - plast > 0 )
+ str_append_data(str, plast, (p - plast));
+ p++;
+ if ( *p == '\0' || (digit=_decode_hex_digit(*p)) < 0 )
+ return NULL;
+ ch = (unsigned char)digit;
+ p++;
+ if ( *p == '\0' || (digit=_decode_hex_digit(*p)) < 0 )
+ return NULL;
+ ch = (ch << 4) + (unsigned char)digit;
+ str_append_data(str, &ch, 1);
+ plast = p + 1;
+ }
+ p++;
+ }
+ if ( p - plast > 0 )
+ str_append_data(str, plast, (p - plast));
+ return str;
+}
+
+static string_t *
+content_type_param_next(struct content_header_stringlist *strlist)
+{
+ const struct sieve_runtime_env *renv = strlist->strlist.runenv;
+ const char *const *values = strlist->param_values;
+ bool trace = strlist->strlist.trace;
+
+ i_assert( strlist->params != NULL );
+
+ /* Iterate over all parsed parameter values */
+ for ( ; *values != NULL; values += 2 ) {
+ const char *const *params = strlist->params;
+ const char *name = values[0], *value = values[1];
+ size_t nlen = strlen(name);
+
+ /* Iterate over all interesting parameter names */
+ for ( ; *params != NULL; params++ ) {
+ size_t plen = strlen(*params);
+
+ if ( plen != nlen &&
+ (nlen != plen + 1 || name[nlen-1] != '*') )
+ continue;
+
+ if ( plen == nlen ) {
+ if ( strcasecmp(name, *params) == 0 ) {
+ /* Return raw value */
+ if ( trace ) {
+ sieve_runtime_trace(renv, 0,
+ "found mime parameter `%s' in mime header",
+ *params);
+ }
+
+ strlist->param_values = values + 2;
+ return t_str_new_const(value, strlen(value));
+ }
+ } else {
+ if ( trace ) {
+ sieve_runtime_trace(renv, 0,
+ "found encoded parameter `%s' in mime header",
+ *params);
+ }
+
+ if ( strncasecmp(name, *params, plen) == 0 ) {
+ string_t *result = NULL;
+
+ strlist->param_values = values + 2;
+
+ /* Decode value first */
+ // FIXME: transcode charset
+ value = strchr(value, '\'');
+ if (value != NULL)
+ value = strchr(value+1, '\'');
+ if (value != NULL)
+ result = content_type_param_decode(value + 1);
+ if (result == NULL)
+ strlist->param_values = NULL;
+ return result;
+ }
+ }
+ }
+ }
+
+ strlist->param_values = NULL;
+ return NULL;
+}
+
+// FIXME: not too happy with the use of string_t like this.
+// Sieve should have a special runtime string type (TODO)
+static string_t *
+content_header_parse(struct content_header_stringlist *strlist,
+ const char *hdr_name, string_t *str)
+{
+ const struct sieve_runtime_env *renv = strlist->strlist.runenv;
+ bool trace = strlist->strlist.trace;
+ struct rfc822_parser_context parser;
+ const char *type, *p;
+ bool is_ctype = FALSE;
+ string_t *content;
+
+ if ( strlist->option == EXT_MIME_OPTION_NONE )
+ return str;
+
+ if ( strcasecmp(hdr_name, "content-type") == 0 )
+ is_ctype = TRUE;
+ else if ( strcasecmp(hdr_name, "content-disposition") != 0 ) {
+ if ( trace ) {
+ sieve_runtime_trace(renv, 0,
+ "non-mime header yields empty string");
+ }
+ return t_str_new(0);
+ }
+
+ /* Initialize parsing */
+ rfc822_parser_init(&parser, str_data(str), str_len(str), NULL);
+ (void)rfc822_skip_lwsp(&parser);
+
+ /* Parse content type/disposition */
+ content = t_str_new(64);
+ if ( is_ctype ){
+ if (rfc822_parse_content_type(&parser, content) < 0) {
+ str_truncate(content, 0);
+ return content;
+ }
+ } else {
+ if (rfc822_parse_mime_token(&parser, content) < 0) {
+ str_truncate(content, 0);
+ return content;
+ }
+ }
+
+ /* Content-type value must end here, otherwise it is invalid after all */
+ (void)rfc822_skip_lwsp(&parser);
+ if ( parser.data != parser.end && *parser.data != ';' ) {
+ str_truncate(content, 0);
+ return content;
+ }
+
+ if ( strlist->option == EXT_MIME_OPTION_PARAM ) {
+ string_t *param_val;
+
+ /* MIME parameter */
+ i_assert( strlist->params != NULL );
+
+ // FIXME: not very nice when multiple parameters in the same header
+ // are queried in successive tests.
+ str_truncate(content, 0);
+ rfc2231_parse(&parser, &strlist->param_values);
+
+ param_val = content_type_param_next(strlist);
+ if ( param_val != NULL )
+ content = param_val;
+ } else {
+ /* Get :type/:subtype:/:contenttype value */
+ type = str_c(content);
+ p = strchr(type, '/');
+ switch ( strlist->option ) {
+ case EXT_MIME_OPTION_TYPE:
+ if ( trace ) {
+ sieve_runtime_trace(renv, 0,
+ "extracted MIME type");
+ }
+ if ( p != NULL ) {
+ i_assert( is_ctype );
+ str_truncate(content, (p - type));
+ }
+ break;
+ case EXT_MIME_OPTION_SUBTYPE:
+ if ( p == NULL ) {
+ i_assert( !is_ctype );
+ if ( trace ) {
+ sieve_runtime_trace(renv, 0,
+ "no MIME sub-type for content-disposition");
+ }
+ str_truncate(content, 0);
+ break;
+ }
+
+ i_assert( is_ctype );
+ if ( trace ) {
+ sieve_runtime_trace(renv, 0,
+ "extracted MIME sub-type");
+ }
+ str_delete(content, 0, (p - type) + 1);
+ break;
+ case EXT_MIME_OPTION_CONTENTTYPE:
+ sieve_runtime_trace(renv, 0,
+ "extracted full MIME contenttype");
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Success */
+ return content;
+}
+
+static int content_header_stringlist_next_item
+(struct sieve_stringlist *_strlist, string_t **str_r)
+{
+ struct content_header_stringlist *strlist =
+ (struct content_header_stringlist *)_strlist;
+ const char *hdr_name;
+ int ret;
+
+ if ( strlist->param_values != NULL ) {
+ string_t *param_val;
+
+ i_assert( strlist->option == EXT_MIME_OPTION_PARAM );
+ param_val = content_type_param_next(strlist);
+ if ( param_val != NULL ) {
+ *str_r = param_val;
+ return 1;
+ }
+ }
+
+ if ( (ret=sieve_header_list_next_item
+ (strlist->source, &hdr_name, str_r)) <= 0 ) {
+ if (ret < 0) {
+ _strlist->exec_status =
+ strlist->source->strlist.exec_status;
+ }
+ return ret;
+ }
+
+ *str_r = content_header_parse(strlist, hdr_name, *str_r);
+ return 1;
+}
+
+static void content_header_stringlist_reset
+(struct sieve_stringlist *_strlist)
+{
+ struct content_header_stringlist *strlist =
+ (struct content_header_stringlist *)_strlist;
+ sieve_header_list_reset(strlist->source);
+}
+
+static int content_header_stringlist_get_length
+(struct sieve_stringlist *_strlist)
+{
+ struct content_header_stringlist *strlist =
+ (struct content_header_stringlist *)_strlist;
+ return sieve_header_list_get_length(strlist->source);
+}
+
+static void content_header_stringlist_set_trace
+(struct sieve_stringlist *_strlist, bool trace)
+{
+ struct content_header_stringlist *strlist =
+ (struct content_header_stringlist *)_strlist;
+ sieve_header_list_set_trace(strlist->source, trace);
+}
+
+/*
+ * Header override implementation
+ */
+
+/* Context data */
+
+struct svmo_mime_context {
+ enum ext_mime_option mimeopt;
+ const char *const *params;
+ bool anychild:1;
+};
+
+/* Context coding */
+
+static bool svmo_mime_dump_context
+(const struct sieve_message_override *svmo ATTR_UNUSED,
+ const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ unsigned int anychild, mimeopt;
+
+ if ( !sieve_binary_read_byte(denv->sblock, address, &anychild) )
+ return FALSE;
+ if ( anychild > 0 )
+ sieve_code_dumpf(denv, "anychild");
+
+ if ( !sieve_binary_read_byte(denv->sblock, address, &mimeopt) )
+ return FALSE;
+
+ switch ( mimeopt ) {
+ case EXT_MIME_OPTION_NONE:
+ break;
+ case EXT_MIME_OPTION_TYPE:
+ sieve_code_dumpf(denv, "option: type");
+ break;
+ case EXT_MIME_OPTION_SUBTYPE:
+ sieve_code_dumpf(denv, "option: subtype");
+ break;
+ case EXT_MIME_OPTION_CONTENTTYPE:
+ sieve_code_dumpf(denv, "option: contenttype");
+ break;
+ case EXT_MIME_OPTION_PARAM:
+ sieve_code_dumpf(denv, "option: param");
+ sieve_code_descend(denv);
+ if ( !sieve_opr_stringlist_dump(denv, address, "param-list") )
+ return FALSE;
+ sieve_code_ascend(denv);
+ break;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static int svmo_mime_read_context
+(const struct sieve_message_override *svmo ATTR_UNUSED,
+ const struct sieve_runtime_env *renv, sieve_size_t *address,
+ void **ho_context)
+{
+ pool_t pool = sieve_result_pool(renv->result); // FIXME: investigate
+ struct svmo_mime_context *ctx;
+ unsigned int anychild = 0, mimeopt = EXT_MIME_OPTION_NONE;
+ struct sieve_stringlist *param_list = NULL;
+ int ret;
+
+ if ( !sieve_binary_read_byte
+ (renv->sblock, address, &anychild) ) {
+ sieve_runtime_trace_error(renv,
+ "anychild: invalid byte");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if ( !sieve_binary_read_byte
+ (renv->sblock, address, &mimeopt) ||
+ mimeopt > EXT_MIME_OPTION_PARAM ) {
+ sieve_runtime_trace_error(renv,
+ "option: invalid mime option code");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if ( mimeopt == EXT_MIME_OPTION_PARAM &&
+ (ret=sieve_opr_stringlist_read
+ (renv, address, "param-list", &param_list)) <= 0 )
+ return ret;
+
+ ctx = p_new(pool, struct svmo_mime_context, 1);
+ ctx->anychild = (anychild == 0 ? FALSE : TRUE);
+ ctx->mimeopt = (enum ext_mime_option)mimeopt;
+
+ if ( param_list != NULL && sieve_stringlist_read_all
+ (param_list, pool, &ctx->params) < 0 ) {
+ sieve_runtime_trace_error(renv,
+ "failed to read param-list operand");
+ return param_list->exec_status;
+ }
+
+ *ho_context = (void *) ctx;
+ return SIEVE_EXEC_OK;
+}
+
+/* Override */
+
+static int svmo_mime_header_override
+(const struct sieve_message_override *svmo,
+ const struct sieve_runtime_env *renv, bool mime_decode,
+ struct sieve_stringlist **headers_r)
+{
+ struct svmo_mime_context *ctx =
+ (struct svmo_mime_context *)svmo->context;
+ struct ext_foreverypart_runtime_loop *sfploop;
+ struct sieve_header_list *headers;
+ struct sieve_stringlist *values;
+ int ret;
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
+ "header mime override:");
+ sieve_runtime_trace_descend(renv);
+
+ if ( ctx->anychild ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
+ "headers from current mime part and children");
+ } else {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
+ "headers from current mime part");
+ }
+
+ sfploop = ext_foreverypart_runtime_loop_get_current(renv);
+ if ( sfploop != NULL ) {
+ headers = sieve_mime_header_list_create
+ (renv, *headers_r, &sfploop->part_iter,
+ mime_decode, ctx->anychild);
+ } else if ( ctx->anychild ) {
+ struct sieve_message_part_iter part_iter;
+
+ if ( (ret=sieve_message_part_iter_init
+ (&part_iter, renv)) <= 0 )
+ return ret;
+
+ headers = sieve_mime_header_list_create
+ (renv, *headers_r, &part_iter, mime_decode, TRUE);
+ } else {
+ headers = sieve_message_header_list_create
+ (renv, *headers_r, mime_decode);
+ }
+ values = &headers->strlist;
+
+ switch ( ctx->mimeopt ) {
+ case EXT_MIME_OPTION_NONE:
+ break;
+ case EXT_MIME_OPTION_TYPE:
+ sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
+ "extract mime type from header value");
+ break;
+ case EXT_MIME_OPTION_SUBTYPE:
+ sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
+ "extract mime subtype from header value");
+ break;
+ case EXT_MIME_OPTION_CONTENTTYPE:
+ sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
+ "extract mime contenttype from header value");
+ break;
+ case EXT_MIME_OPTION_PARAM:
+ sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
+ "extract mime parameters from header value");
+ break;
+ default:
+ i_unreached();
+ }
+
+ if ( ctx->mimeopt != EXT_MIME_OPTION_NONE ) {
+ values = content_header_stringlist_create
+ (renv, headers, ctx->mimeopt, ctx->params);
+ }
+ *headers_r = values;
+
+ sieve_runtime_trace_ascend(renv);
+ return SIEVE_EXEC_OK;
+}
+
diff --git a/pigeonhole/src/lib-sieve/plugins/notify/Makefile.am b/pigeonhole/src/lib-sieve/plugins/notify/Makefile.am
new file mode 100644
index 0000000..aaa76b3
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/notify/Makefile.am
@@ -0,0 +1,20 @@
+noinst_LTLIBRARIES = libsieve_ext_notify.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../../util \
+ $(LIBDOVECOT_INCLUDE)
+
+commands = \
+ cmd-notify.c \
+ cmd-denotify.c
+
+libsieve_ext_notify_la_SOURCES = \
+ ext-notify.c \
+ ext-notify-common.c \
+ $(commands)
+
+noinst_HEADERS = \
+ ext-notify-common.h \
+ ext-notify-limits.h
+
diff --git a/pigeonhole/src/lib-sieve/plugins/notify/Makefile.in b/pigeonhole/src/lib-sieve/plugins/notify/Makefile.in
new file mode 100644
index 0000000..910007d
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/notify/Makefile.in
@@ -0,0 +1,699 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/notify
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_notify_la_LIBADD =
+am__objects_1 = cmd-notify.lo cmd-denotify.lo
+am_libsieve_ext_notify_la_OBJECTS = ext-notify.lo ext-notify-common.lo \
+ $(am__objects_1)
+libsieve_ext_notify_la_OBJECTS = $(am_libsieve_ext_notify_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cmd-denotify.Plo \
+ ./$(DEPDIR)/cmd-notify.Plo ./$(DEPDIR)/ext-notify-common.Plo \
+ ./$(DEPDIR)/ext-notify.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_notify_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_notify_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_notify.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../../util \
+ $(LIBDOVECOT_INCLUDE)
+
+commands = \
+ cmd-notify.c \
+ cmd-denotify.c
+
+libsieve_ext_notify_la_SOURCES = \
+ ext-notify.c \
+ ext-notify-common.c \
+ $(commands)
+
+noinst_HEADERS = \
+ ext-notify-common.h \
+ ext-notify-limits.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/notify/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/notify/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_notify.la: $(libsieve_ext_notify_la_OBJECTS) $(libsieve_ext_notify_la_DEPENDENCIES) $(EXTRA_libsieve_ext_notify_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_notify_la_OBJECTS) $(libsieve_ext_notify_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-denotify.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-notify.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-notify-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-notify.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/cmd-denotify.Plo
+ -rm -f ./$(DEPDIR)/cmd-notify.Plo
+ -rm -f ./$(DEPDIR)/ext-notify-common.Plo
+ -rm -f ./$(DEPDIR)/ext-notify.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/cmd-denotify.Plo
+ -rm -f ./$(DEPDIR)/cmd-notify.Plo
+ -rm -f ./$(DEPDIR)/ext-notify-common.Plo
+ -rm -f ./$(DEPDIR)/ext-notify.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/notify/cmd-denotify.c b/pigeonhole/src/lib-sieve/plugins/notify/cmd-denotify.c
new file mode 100644
index 0000000..8769808
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/notify/cmd-denotify.c
@@ -0,0 +1,389 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-ast.h"
+#include "sieve-commands.h"
+#include "sieve-match-types.h"
+#include "sieve-comparators.h"
+#include "sieve-match.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-result.h"
+
+#include "ext-notify-common.h"
+
+/*
+ * Denotify command
+ *
+ * Syntax:
+ * denotify [MATCH-TYPE string] [<":low" / ":normal" / ":high">]
+ */
+
+static bool cmd_denotify_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool cmd_denotify_pre_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool cmd_denotify_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool cmd_denotify_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
+
+const struct sieve_command_def cmd_denotify = {
+ .identifier = "denotify",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = cmd_denotify_registered,
+ .pre_validate = cmd_denotify_pre_validate,
+ .validate = cmd_denotify_validate,
+ .generate = cmd_denotify_generate
+};
+
+/*
+ * Tagged arguments
+ */
+
+/* Forward declarations */
+
+static bool tag_match_type_is_instance_of
+ (struct sieve_validator *validator, struct sieve_command *cmd,
+ const struct sieve_extension *ext, const char *identifier, void **data);
+static bool tag_match_type_validate
+ (struct sieve_validator *validator, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+/* Argument object */
+
+const struct sieve_argument_def denotify_match_tag = {
+ .identifier = "MATCH-TYPE-STRING",
+ .is_instance_of = tag_match_type_is_instance_of,
+ .validate = tag_match_type_validate
+};
+
+/* Codes for optional operands */
+
+enum cmd_denotify_optional {
+ OPT_END,
+ OPT_IMPORTANCE,
+ OPT_MATCH_TYPE,
+ OPT_MATCH_KEY
+};
+
+/*
+ * Denotify operation
+ */
+
+static bool cmd_denotify_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int cmd_denotify_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def denotify_operation = {
+ .mnemonic = "DENOTIFY",
+ .ext_def = &notify_extension,
+ .code = EXT_NOTIFY_OPERATION_DENOTIFY,
+ .dump = cmd_denotify_operation_dump,
+ .execute = cmd_denotify_operation_execute
+};
+
+/*
+ * Command validation context
+ */
+
+struct cmd_denotify_context_data {
+ struct sieve_ast_argument *match_key_arg;
+};
+
+/*
+ * Tag validation
+ */
+
+static bool tag_match_type_is_instance_of
+(struct sieve_validator *valdtr, struct sieve_command *cmd,
+ const struct sieve_extension *ext, const char *identifier, void **data)
+{
+ return match_type_tag.is_instance_of(valdtr, cmd, ext, identifier, data);
+}
+
+static bool tag_match_type_validate
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct cmd_denotify_context_data *cmd_data =
+ (struct cmd_denotify_context_data *) cmd->data;
+ struct sieve_ast_argument *tag = *arg;
+
+ i_assert(tag != NULL);
+
+ if ( !match_type_tag.validate(valdtr, arg, cmd) )
+ return FALSE;
+
+ if ( *arg == NULL ) {
+ sieve_argument_validate_error(valdtr, tag,
+ "the MATCH-TYPE argument (:%s) for the denotify command requires "
+ "an additional key-string parameter, but no more arguments were found",
+ sieve_ast_argument_tag(tag));
+ return FALSE;
+ }
+
+ if ( sieve_ast_argument_type(*arg) != SAAT_STRING )
+ {
+ sieve_argument_validate_error(valdtr, *arg,
+ "the MATCH-TYPE argument (:%s) for the denotify command requires "
+ "an additional key-string parameter, but %s was found",
+ sieve_ast_argument_tag(tag), sieve_ast_argument_name(*arg));
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, cmd, *arg, FALSE) )
+ return FALSE;
+
+ tag->argument->def = &match_type_tag;
+ tag->argument->ext = NULL;
+
+ (*arg)->argument->id_code = OPT_MATCH_KEY;
+ cmd_data->match_key_arg = *arg;
+
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+/*
+ * Command registration
+ */
+
+static bool cmd_denotify_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, ext, &denotify_match_tag, OPT_MATCH_TYPE);
+
+ ext_notify_register_importance_tags(valdtr, cmd_reg, ext, OPT_IMPORTANCE);
+
+ return TRUE;
+}
+
+/*
+ * Command validation
+ */
+
+static bool cmd_denotify_pre_validate
+(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_command *cmd)
+{
+ struct cmd_denotify_context_data *ctx_data;
+
+ /* Assign context */
+ ctx_data = p_new(sieve_command_pool(cmd),
+ struct cmd_denotify_context_data, 1);
+ cmd->data = (void *) ctx_data;
+
+ return TRUE;
+}
+
+static bool cmd_denotify_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ struct cmd_denotify_context_data *ctx_data =
+ (struct cmd_denotify_context_data *) cmd->data;
+ struct sieve_ast_argument *key_arg = ctx_data->match_key_arg;
+ const struct sieve_match_type mcht_default =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ const struct sieve_comparator cmp_default =
+ SIEVE_COMPARATOR_DEFAULT(i_octet_comparator);
+
+ if ( key_arg != NULL ) {
+ if ( !sieve_match_type_validate
+ (valdtr, cmd, key_arg, &mcht_default, &cmp_default) )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool cmd_denotify_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &denotify_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, cmd, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool cmd_denotify_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ const struct sieve_operation *op = denv->oprtn;
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "%s", sieve_operation_mnemonic(op));
+ sieve_code_descend(denv);
+
+ for (;;) {
+ int opt;
+ bool opok = TRUE;
+
+ if ( (opt=sieve_opr_optional_dump(denv, address, &opt_code)) < 0 )
+ return FALSE;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_MATCH_KEY:
+ opok = sieve_opr_string_dump(denv, address, "key-string");
+ break;
+ case OPT_MATCH_TYPE:
+ opok = sieve_opr_match_type_dump(denv, address);
+ break;
+ case OPT_IMPORTANCE:
+ opok = sieve_opr_number_dump(denv, address, "importance");
+ break;
+ default:
+ return FALSE;
+ }
+
+ if ( !opok ) return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Code execution
+ */
+
+static int cmd_denotify_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ int opt_code = 0;
+ struct sieve_match_type mcht =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ const struct sieve_comparator cmp =
+ SIEVE_COMPARATOR_DEFAULT(i_octet_comparator);
+ struct sieve_stringlist *match_key = NULL;
+ sieve_number_t importance = 0;
+ struct sieve_match_context *mctx;
+ struct sieve_result_iterate_context *rictx;
+ const struct sieve_action *action;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Optional operands */
+
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_opr_optional_read(renv, address, &opt_code)) < 0 )
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_MATCH_TYPE:
+ ret = sieve_opr_match_type_read(renv, address, &mcht);
+ break;
+ case OPT_MATCH_KEY:
+ ret = sieve_opr_stringlist_read(renv, address, "match key", &match_key);
+ break;
+ case OPT_IMPORTANCE:
+ ret = sieve_opr_number_read(renv, address, "importance", &importance);
+ break;
+ default:
+ sieve_runtime_trace_error(renv, "unknown optional operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if ( ret <= 0 ) return ret;
+ }
+
+ /*
+ * Perform operation
+ */
+
+ /* Enforce 0 < importance < 4 (just to be sure) */
+
+ if ( importance < 1 )
+ importance = 1;
+ else if ( importance > 3 )
+ importance = 3;
+
+ /* Trace */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "denotify action");
+
+ /* Either do string matching or just kill all notify actions */
+ if ( match_key != NULL ) {
+ /* Initialize match */
+ mctx = sieve_match_begin(renv, &mcht, &cmp);
+
+ /* Iterate through all notify actions and delete those that match */
+ rictx = sieve_result_iterate_init(renv->result);
+
+ while ( (action=sieve_result_iterate_next(rictx, NULL)) != NULL ) {
+ if ( sieve_action_is(action, act_notify_old) ) {
+ struct ext_notify_action *nact =
+ (struct ext_notify_action *) action->context;
+
+ if ( importance == 0 || nact->importance == importance ) {
+ int match;
+
+ if ( (match=sieve_match_value
+ (mctx, nact->id, strlen(nact->id), match_key)) < 0 )
+ break;
+
+ if ( match > 0 )
+ sieve_result_iterate_delete(rictx);
+ }
+ }
+ }
+
+ /* Finish match */
+ if ( sieve_match_end(&mctx, &ret) < 0 )
+ return ret;
+
+ } else {
+ /* Delete all notify actions */
+ rictx = sieve_result_iterate_init(renv->result);
+
+ while ( (action=sieve_result_iterate_next(rictx, NULL)) != NULL ) {
+
+ if ( sieve_action_is(action, act_notify_old) ) {
+ struct ext_notify_action *nact =
+ (struct ext_notify_action *) action->context;
+
+ if ( importance == 0 || nact->importance == importance )
+ sieve_result_iterate_delete(rictx);
+ }
+ }
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/notify/cmd-notify.c b/pigeonhole/src/lib-sieve/plugins/notify/cmd-notify.c
new file mode 100644
index 0000000..a683c31
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/notify/cmd-notify.c
@@ -0,0 +1,900 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "ioloop.h"
+#include "str-sanitize.h"
+#include "ostream.h"
+#include "message-date.h"
+#include "mail-storage.h"
+
+#include "rfc2822.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-result.h"
+#include "sieve-address.h"
+#include "sieve-message.h"
+#include "sieve-smtp.h"
+
+#include "ext-notify-common.h"
+#include "ext-notify-limits.h"
+
+#include <ctype.h>
+
+/* Notify command (DEPRECATED)
+ *
+ * Syntax:
+ * notify [":method" string] [":id" string] [":options" string-list]
+ * [<":low" / ":normal" / ":high">] ["message:" string]
+ *
+ */
+
+static bool
+cmd_notify_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool
+cmd_notify_pre_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd);
+static bool
+cmd_notify_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd);
+static bool
+cmd_notify_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+const struct sieve_command_def cmd_notify_old = {
+ .identifier = "notify",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = cmd_notify_registered,
+ .pre_validate = cmd_notify_pre_validate,
+ .validate = cmd_notify_validate,
+ .generate = cmd_notify_generate
+};
+
+/*
+ * Tagged arguments
+ */
+
+/* Forward declarations */
+
+static bool
+cmd_notify_validate_string_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool
+cmd_notify_validate_stringlist_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+/* Argument objects */
+
+static const struct sieve_argument_def notify_method_tag = {
+ .identifier = "method",
+ .validate = cmd_notify_validate_string_tag
+};
+
+static const struct sieve_argument_def notify_options_tag = {
+ .identifier = "options",
+ .validate = cmd_notify_validate_stringlist_tag
+};
+
+static const struct sieve_argument_def notify_id_tag = {
+ .identifier = "id",
+ .validate = cmd_notify_validate_string_tag
+};
+
+static const struct sieve_argument_def notify_message_tag = {
+ .identifier = "message",
+ .validate = cmd_notify_validate_string_tag
+};
+
+/*
+ * Notify operation
+ */
+
+static bool
+cmd_notify_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_notify_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def notify_old_operation = {
+ .mnemonic = "NOTIFY",
+ .ext_def = &notify_extension,
+ .code = EXT_NOTIFY_OPERATION_NOTIFY,
+ .dump = cmd_notify_operation_dump,
+ .execute = cmd_notify_operation_execute
+};
+
+/* Codes for optional operands */
+
+enum cmd_notify_optional {
+ OPT_END,
+ OPT_MESSAGE,
+ OPT_IMPORTANCE,
+ OPT_OPTIONS,
+ OPT_ID
+};
+
+/*
+ * Notify action
+ */
+
+/* Forward declarations */
+
+static int
+act_notify_check_duplicate(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other);
+static void
+act_notify_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv, bool *keep);
+static int
+act_notify_commit(const struct sieve_action_exec_env *aenv,
+ void *tr_context);
+
+/* Action object */
+
+const struct sieve_action_def act_notify_old = {
+ .name = "notify",
+ .check_duplicate = act_notify_check_duplicate,
+ .print = act_notify_print,
+ .commit = act_notify_commit
+};
+
+/*
+ * Command validation context
+ */
+
+struct cmd_notify_context_data {
+ struct sieve_ast_argument *id;
+ struct sieve_ast_argument *method;
+ struct sieve_ast_argument *options;
+ struct sieve_ast_argument *message;
+};
+
+/*
+ * Tag validation
+ */
+
+static bool
+cmd_notify_validate_string_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+ struct cmd_notify_context_data *ctx_data =
+ (struct cmd_notify_context_data *)cmd->data;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg, 1);
+
+ /* Check syntax:
+ * :id <string>
+ * :method <string>
+ * :message <string>
+ */
+ if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0,
+ SAAT_STRING, FALSE))
+ return FALSE;
+
+ if (sieve_argument_is(tag, notify_method_tag)) {
+ ctx_data->method = *arg;
+
+ /* Removed */
+ *arg = sieve_ast_arguments_detach(*arg, 1);
+ } else if (sieve_argument_is(tag, notify_id_tag)) {
+ ctx_data->id = *arg;
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+ } else if (sieve_argument_is(tag, notify_message_tag)) {
+ ctx_data->message = *arg;
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+ }
+ return TRUE;
+}
+
+static bool
+cmd_notify_validate_stringlist_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+ struct cmd_notify_context_data *ctx_data =
+ (struct cmd_notify_context_data *)cmd->data;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ /* Check syntax:
+ * :options string-list
+ */
+ if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0,
+ SAAT_STRING_LIST, FALSE))
+ return FALSE;
+
+ /* Assign context */
+ ctx_data->options = *arg;
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+/*
+ * Command registration
+ */
+
+static bool
+cmd_notify_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &notify_method_tag, 0);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &notify_id_tag, OPT_ID);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &notify_message_tag, OPT_MESSAGE);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &notify_options_tag, OPT_OPTIONS);
+
+ ext_notify_register_importance_tags(valdtr, cmd_reg, ext,
+ OPT_IMPORTANCE);
+
+ return TRUE;
+}
+
+/*
+ * Command validation
+ */
+
+static bool
+cmd_notify_pre_validate(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_command *cmd)
+{
+ struct cmd_notify_context_data *ctx_data;
+
+ /* Create context */
+ ctx_data = p_new(sieve_command_pool(cmd),
+ struct cmd_notify_context_data, 1);
+ cmd->data = ctx_data;
+
+ return TRUE;
+}
+
+static int
+cmd_notify_address_validate(void *context, struct sieve_ast_argument *arg)
+{
+ struct sieve_validator *valdtr = (struct sieve_validator *)context;
+
+ if (sieve_argument_is_string_literal(arg)) {
+ string_t *address = sieve_ast_argument_str(arg);
+ const char *error;
+ int result;
+
+ T_BEGIN {
+ result = (sieve_address_validate_str(address, &error) ?
+ 1 : -1);
+
+ if (result <= 0) {
+ sieve_argument_validate_error(
+ valdtr, arg,
+ "specified :options address '%s' is invalid for "
+ "the mailto notify method: %s",
+ str_sanitize(str_c(address), 128),
+ error);
+ }
+ } T_END;
+
+ return result;
+ }
+
+ return 1;
+}
+
+static bool
+cmd_notify_validate(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ struct cmd_notify_context_data *ctx_data =
+ (struct cmd_notify_context_data *)cmd->data;
+
+ /* Check :method argument */
+ if (ctx_data->method != NULL) {
+ const char *method = sieve_ast_argument_strc(ctx_data->method);
+
+ if (strcasecmp(method, "mailto") != 0) {
+ sieve_command_validate_error(
+ valdtr, cmd,
+ "the notify command of the deprecated notify extension "
+ "only supports the 'mailto' notification method");
+ return FALSE;
+ }
+ }
+
+ /* Check :options argument */
+ if (ctx_data->options != NULL) {
+ struct sieve_ast_argument *option = ctx_data->options;
+
+ /* Parse and check options */
+ if (sieve_ast_stringlist_map(
+ &option, (void *)valdtr,
+ cmd_notify_address_validate) <= 0) {
+ return FALSE;
+ }
+ } else {
+ sieve_command_validate_warning(
+ valdtr, cmd,
+ "no :options (and hence recipients) specified for the notify command");
+ }
+
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+cmd_notify_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &notify_old_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, cmd, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+cmd_notify_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "NOTIFY");
+ sieve_code_descend(denv);
+
+ /* Dump optional operands */
+ for (;;) {
+ int opt;
+ bool opok = TRUE;
+
+ if ((opt = sieve_opr_optional_dump(denv, address,
+ &opt_code)) < 0)
+ return FALSE;
+
+ if (opt == 0)
+ break;
+
+ switch (opt_code) {
+ case OPT_IMPORTANCE:
+ opok = sieve_opr_number_dump(denv, address,
+ "importance");
+ break;
+ case OPT_ID:
+ opok = sieve_opr_string_dump(denv, address,
+ "id");
+ break;
+ case OPT_OPTIONS:
+ opok = sieve_opr_stringlist_dump(denv, address,
+ "options");
+ break;
+ case OPT_MESSAGE:
+ opok = sieve_opr_string_dump(denv, address,
+ "message");
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (!opok)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Code execution
+ */
+
+
+static int
+cmd_notify_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ struct ext_notify_action *act;
+ pool_t pool;
+ int opt_code = 0;
+ sieve_number_t importance = 1;
+ struct sieve_stringlist *options = NULL;
+ string_t *message = NULL, *id = NULL;
+ int ret = 0;
+
+ /*
+ * Read operands
+ */
+
+ /* Optional operands */
+
+ for (;;) {
+ int opt;
+
+ if ((opt = sieve_opr_optional_read(renv, address,
+ &opt_code)) < 0)
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ if (opt == 0)
+ break;
+
+ switch (opt_code) {
+ case OPT_IMPORTANCE:
+ ret = sieve_opr_number_read(renv, address, "importance",
+ &importance);
+ break;
+ case OPT_ID:
+ ret = sieve_opr_string_read(renv, address, "id", &id);
+ break;
+ case OPT_MESSAGE:
+ ret = sieve_opr_string_read(renv, address, "from",
+ &message);
+ break;
+ case OPT_OPTIONS:
+ ret = sieve_opr_stringlist_read(renv, address,
+ "options", &options);
+ break;
+ default:
+ sieve_runtime_trace_error(
+ renv, "unknown optional operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if (ret <= 0) return ret;
+ }
+
+ /*
+ * Perform operation
+ */
+
+ /* Enforce 0 < importance < 4 (just to be sure) */
+
+ if (importance < 1)
+ importance = 1;
+ else if (importance > 3)
+ importance = 3;
+
+ /* Trace */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "notify action");
+
+ /* Compose action */
+ if (options != NULL) {
+ string_t *raw_address;
+ string_t *out_message;
+
+ pool = sieve_result_pool(renv->result);
+ act = p_new(pool, struct ext_notify_action, 1);
+ if (id != NULL)
+ act->id = p_strdup(pool, str_c(id));
+ act->importance = importance;
+
+ /* Process message */
+
+ out_message = t_str_new(1024);
+ if ((ret = ext_notify_construct_message(
+ renv, (message == NULL ? NULL : str_c(message)),
+ out_message)) <= 0)
+ return ret;
+ act->message = p_strdup(pool, str_c(out_message));
+
+ /* Normalize and verify all :options addresses */
+
+ sieve_stringlist_reset(options);
+
+ p_array_init(&act->recipients, pool, 4);
+
+ raw_address = NULL;
+ while ((ret = sieve_stringlist_next_item(
+ options, &raw_address)) > 0) {
+ const char *error = NULL;
+ const struct smtp_address *address;
+
+ /* Add if valid address */
+ address = sieve_address_parse_str(raw_address, &error);
+ if (address != NULL) {
+ const struct ext_notify_recipient *rcpts;
+ unsigned int rcpt_count, i;
+
+ /* Prevent duplicates */
+ rcpts = array_get(&act->recipients, &rcpt_count);
+
+ for (i = 0; i < rcpt_count; i++) {
+ if (smtp_address_equals(rcpts[i].address,
+ address))
+ break;
+ }
+
+ /* Add only if unique */
+ if (i != rcpt_count) {
+ sieve_runtime_warning(
+ renv, NULL,
+ "duplicate recipient '%s' specified in the :options argument of "
+ "the deprecated notify command",
+ str_sanitize(str_c(raw_address), 128));
+
+ } else if (array_count(&act->recipients) >=
+ EXT_NOTIFY_MAX_RECIPIENTS) {
+ sieve_runtime_warning(renv, NULL,
+ "more than the maximum %u recipients are specified "
+ "for the deprecated notify command; "
+ "the rest is discarded",
+ EXT_NOTIFY_MAX_RECIPIENTS);
+ break;
+
+ } else {
+ struct ext_notify_recipient recipient;
+
+ recipient.full =
+ p_strdup(pool, str_c(raw_address));
+ recipient.address =
+ smtp_address_clone(pool, address);
+
+ array_append(&act->recipients, &recipient, 1);
+ }
+ } else {
+ sieve_runtime_error(
+ renv, NULL,
+ "specified :options address '%s' is invalid for "
+ "the deprecated notify command: %s",
+ str_sanitize(str_c(raw_address), 128), error);
+ return SIEVE_EXEC_FAILURE;
+ }
+ }
+
+ if (ret < 0) {
+ sieve_runtime_trace_error(
+ renv, "invalid options stringlist");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if (sieve_result_add_action(renv, this_ext, "notify",
+ &act_notify_old, NULL, (void *)act,
+ 0, FALSE) < 0)
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Action
+ */
+
+/* Runtime verification */
+
+static int
+act_notify_check_duplicate(const struct sieve_runtime_env *renv ATTR_UNUSED,
+ const struct sieve_action *act ATTR_UNUSED,
+ const struct sieve_action *act_other ATTR_UNUSED)
+{
+ struct ext_notify_action *new_nact, *old_nact;
+ const struct ext_notify_recipient *new_rcpts;
+ const struct ext_notify_recipient *old_rcpts;
+ unsigned int new_count, old_count, i, j;
+ unsigned int del_start = 0, del_len = 0;
+
+ if (act->context == NULL || act_other->context == NULL)
+ return 0;
+
+ new_nact = (struct ext_notify_action *)act->context;
+ old_nact = (struct ext_notify_action *)act_other->context;
+
+ new_rcpts = array_get(&new_nact->recipients, &new_count);
+ old_rcpts = array_get(&old_nact->recipients, &old_count);
+
+ for (i = 0; i < new_count; i++) {
+ for (j = 0; j < old_count; j++) {
+ if (smtp_address_equals(new_rcpts[i].address,
+ old_rcpts[j].address))
+ break;
+ }
+
+ if (j == old_count) {
+ /* Not duplicate */
+ if (del_len > 0) {
+ /* Perform pending deletion */
+ array_delete(&new_nact->recipients,
+ del_start, del_len);
+
+ /* Make sure the loop integrity is maintained */
+ i -= del_len;
+ new_rcpts = array_get(&new_nact->recipients,
+ &new_count);
+ }
+
+ del_len = 0;
+ } else {
+ /* Mark deletion */
+ if (del_len == 0)
+ del_start = i;
+ del_len++;
+ }
+ }
+
+ /* Perform pending deletion */
+ if (del_len > 0)
+ array_delete(&new_nact->recipients, del_start, del_len);
+
+ return (array_count(&new_nact->recipients) > 0 ? 0 : 1);
+}
+
+/* Result printing */
+
+static void
+act_notify_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv,
+ bool *keep ATTR_UNUSED)
+{
+ const struct ext_notify_action *act =
+ (const struct ext_notify_action *)action->context;
+ const struct ext_notify_recipient *recipients;
+ unsigned int count, i;
+
+ sieve_result_action_printf(
+ rpenv, "send (deprecated) notification with method 'mailto':");
+
+ /* Print main method parameters */
+
+ sieve_result_printf(rpenv, " => importance : %llu\n",
+ (unsigned long long)act->importance);
+
+ if (act->message != NULL) {
+ sieve_result_printf(
+ rpenv, " => message : %s\n", act->message);
+ }
+ if (act->id != NULL) {
+ sieve_result_printf(
+ rpenv, " => id : %s \n", act->id);
+ }
+
+ /* Print mailto: recipients */
+
+ sieve_result_printf(rpenv, " => recipients :\n");
+
+ recipients = array_get(&act->recipients, &count);
+ if (count == 0) {
+ sieve_result_printf(
+ rpenv, " NONE, action has no effect\n");
+ } else {
+ for (i = 0; i < count; i++) {
+ sieve_result_printf(
+ rpenv, " + To: %s\n", recipients[i].full);
+ }
+ }
+
+ /* Finish output with an empty line */
+
+ sieve_result_printf(rpenv, "\n");
+}
+
+/* Result execution */
+
+static bool contains_8bit(const char *msg)
+{
+ const unsigned char *s = (const unsigned char *)msg;
+
+ for (; *s != '\0'; s++) {
+ if ((*s & 0x80) != 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static bool
+act_notify_send(const struct sieve_action_exec_env *aenv,
+ const struct ext_notify_action *act)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ const struct ext_notify_recipient *recipients;
+ struct sieve_smtp_context *sctx;
+ unsigned int count, i;
+ struct ostream *output;
+ string_t *msg, *to, *all;
+ const char *outmsgid, *error;
+ int ret;
+
+ /* Get recipients */
+ recipients = array_get(&act->recipients, &count);
+ if (count == 0) {
+ sieve_result_warning(
+ aenv, "notify action specifies no recipients; "
+ "action has no effect");
+ return TRUE;
+ }
+
+ /* Just to be sure */
+ if (!sieve_smtp_available(senv)) {
+ sieve_result_global_warning(
+ aenv, "notify action has no means to send mail");
+ return TRUE;
+ }
+
+ /* Compose common headers */
+ msg = t_str_new(512);
+ rfc2822_header_write(msg, "X-Sieve", SIEVE_IMPLEMENTATION);
+ rfc2822_header_write(msg, "Date", message_date_create(ioloop_time));
+
+ /* Set importance */
+ switch (act->importance) {
+ case 1:
+ rfc2822_header_write(msg, "X-Priority", "1 (Highest)");
+ rfc2822_header_write(msg, "Importance", "High");
+ break;
+ case 3:
+ rfc2822_header_write(msg, "X-Priority", "5 (Lowest)");
+ rfc2822_header_write(msg, "Importance", "Low");
+ break;
+ case 2:
+ default:
+ rfc2822_header_write(msg, "X-Priority", "3 (Normal)");
+ rfc2822_header_write(msg, "Importance", "Normal");
+ break;
+ }
+
+ rfc2822_header_write(msg, "From", sieve_get_postmaster_address(senv));
+
+ rfc2822_header_write(msg, "Subject", "[SIEVE] New mail notification");
+
+ rfc2822_header_write(msg, "Auto-Submitted", "auto-generated (notify)");
+ rfc2822_header_write(msg, "Precedence", "bulk");
+
+ rfc2822_header_write(msg, "MIME-Version", "1.0");
+ if (contains_8bit(act->message)) {
+ rfc2822_header_write(msg, "Content-Type",
+ "text/plain; charset=utf-8");
+ rfc2822_header_write(msg, "Content-Transfer-Encoding", "8bit");
+ } else {
+ rfc2822_header_write(msg, "Content-Type",
+ "text/plain; charset=us-ascii");
+ rfc2822_header_write(msg, "Content-Transfer-Encoding", "7bit");
+ }
+
+ outmsgid = sieve_message_get_new_id(eenv->svinst);
+ rfc2822_header_write(msg, "Message-ID", outmsgid);
+
+ if ((eenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0 &&
+ sieve_message_get_sender(aenv->msgctx) != NULL) {
+ sctx = sieve_smtp_start(senv, sieve_get_postmaster_smtp(senv));
+ } else {
+ sctx = sieve_smtp_start(senv, NULL);
+ }
+
+ /* Add all recipients (and compose To header field) */
+ to = t_str_new(128);
+ all = t_str_new(256);
+ for (i = 0; i < count; i++) {
+ sieve_smtp_add_rcpt(sctx, recipients[i].address);
+ if (i > 0)
+ str_append(to, ", ");
+ str_append(to, recipients[i].full);
+ if (i < 3) {
+ if (i > 0)
+ str_append(all, ", ");
+ str_append(all, smtp_address_encode_path(
+ recipients[i].address));
+ } else if (i == 3) {
+ str_printfa(all, ", ... (%u total)", count);
+ }
+ }
+
+ rfc2822_header_write_address(msg, "To", str_c(to));
+
+ /* Generate message body */
+ str_printfa(msg, "\r\n%s\r\n", act->message);
+
+ output = sieve_smtp_send(sctx);
+ o_stream_nsend(output, str_data(msg), str_len(msg));
+
+ if ((ret = sieve_smtp_finish(sctx, &error)) <= 0) {
+ if (ret < 0) {
+ sieve_result_global_error(
+ aenv, "failed to send mail notification to %s: "
+ "%s (temporary failure)", str_c(all),
+ str_sanitize(error, 512));
+ } else {
+ sieve_result_global_log_error(
+ aenv, "failed to send mail notification to %s: "
+ "%s (permanent failure)", str_c(all),
+ str_sanitize(error, 512));
+ }
+ } else {
+ struct event_passthrough *e =
+ sieve_action_create_finish_event(aenv)->
+ add_str("notify_target", str_c(all));
+
+ sieve_result_event_log(aenv, e->event(),
+ "sent mail notification to %s",
+ str_c(all));
+ }
+
+ return TRUE;
+}
+
+static int
+act_notify_commit(const struct sieve_action_exec_env *aenv,
+ void *tr_context ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct mail *mail = eenv->msgdata->mail;
+ const struct ext_notify_action *act =
+ (const struct ext_notify_action *)aenv->action->context;
+ const char *const *hdsp;
+ bool result;
+ int ret;
+
+ /* Is the message an automatic reply ? */
+ if ((ret = mail_get_headers(mail, "auto-submitted", &hdsp)) < 0) {
+ return sieve_result_mail_error(
+ aenv, mail,
+ "failed to read `auto-submitted' header field");
+ }
+
+ /* Theoretically multiple headers could exist, so lets make sure */
+ if (ret > 0) {
+ while (*hdsp != NULL) {
+ if (strcasecmp(*hdsp, "no") != 0) {
+ const struct smtp_address *sender = NULL;
+ const char *from;
+
+ if ((eenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0)
+ sender = sieve_message_get_sender(aenv->msgctx);
+ from = (sender == NULL ? "" :
+ t_strdup_printf(" from <%s>",
+ smtp_address_encode(sender)));
+
+ sieve_result_global_log(
+ aenv,
+ "not sending notification for auto-submitted message%s",
+ from);
+ return SIEVE_EXEC_OK;
+ }
+ hdsp++;
+ }
+ }
+
+ T_BEGIN {
+ result = act_notify_send(aenv, act);
+ } T_END;
+
+ if (!result)
+ return SIEVE_EXEC_FAILURE;
+ eenv->exec_status->significant_action_executed = TRUE;
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/notify/ext-notify-common.c b/pigeonhole/src/lib-sieve/plugins/notify/ext-notify-common.c
new file mode 100644
index 0000000..589b21b
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/notify/ext-notify-common.c
@@ -0,0 +1,361 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "istream.h"
+#include "rfc822-parser.h"
+#include "message-parser.h"
+#include "message-decoder.h"
+#include "mail-storage.h"
+
+#include "sieve-common.h"
+#include "sieve-code.h"
+#include "sieve-message.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-result.h"
+
+#include "ext-notify-common.h"
+
+#include <ctype.h>
+
+/*
+ * Importance argument
+ */
+
+static bool
+tag_importance_validate(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+static const struct sieve_argument_def importance_low_tag = {
+ .identifier = "low",
+ .validate = tag_importance_validate,
+};
+
+static const struct sieve_argument_def importance_normal_tag = {
+ .identifier = "normal",
+ .validate = tag_importance_validate,
+};
+
+static const struct sieve_argument_def importance_high_tag = {
+ .identifier = "high",
+ .validate = tag_importance_validate,
+};
+
+static bool
+tag_importance_validate(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ struct sieve_ast_argument *tag = *arg;
+
+ if (sieve_argument_is(tag, importance_low_tag))
+ sieve_ast_argument_number_substitute(tag, 3);
+ else if (sieve_argument_is(tag, importance_normal_tag))
+ sieve_ast_argument_number_substitute(tag, 2);
+ else
+ sieve_ast_argument_number_substitute(tag, 1);
+
+ tag->argument = sieve_argument_create(tag->ast, &number_argument,
+ tag->argument->ext,
+ tag->argument->id_code);
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+void ext_notify_register_importance_tags(
+ struct sieve_validator *valdtr,
+ struct sieve_command_registration *cmd_reg,
+ const struct sieve_extension *ext, unsigned int id_code)
+{
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &importance_low_tag, id_code);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &importance_normal_tag, id_code);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &importance_high_tag, id_code);
+}
+
+/*
+ * Body extraction
+ */
+
+/* FIXME: overlaps somewhat with body extension */
+
+struct ext_notify_message_context {
+ pool_t pool;
+ buffer_t *body_text;
+};
+
+static struct ext_notify_message_context *
+ext_notify_get_message_context(const struct sieve_extension *this_ext,
+ struct sieve_message_context *msgctx)
+{
+ struct ext_notify_message_context *ctx;
+
+ /* Get message context (contains cached message body information) */
+ ctx = (struct ext_notify_message_context *)
+ sieve_message_context_extension_get(msgctx, this_ext);
+
+ /* Create it if it does not exist already */
+ if (ctx == NULL) {
+ pool_t pool = sieve_message_context_pool(msgctx);
+ ctx = p_new(pool, struct ext_notify_message_context, 1);
+ ctx->pool = pool;
+ ctx->body_text = NULL;
+
+ /* Register context */
+ sieve_message_context_extension_set(msgctx, this_ext,
+ (void *)ctx);
+ }
+
+ return ctx;
+}
+
+static bool _is_text_content(const struct message_header_line *hdr)
+{
+ struct rfc822_parser_context parser;
+ string_t *content_type;
+ const char *data;
+
+ /* Initialize parsing */
+ rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
+ (void)rfc822_skip_lwsp(&parser);
+
+ /* Parse content type */
+ content_type = t_str_new(64);
+ if (rfc822_parse_content_type(&parser, content_type) < 0)
+ return FALSE;
+
+ /* Content-type value must end here, otherwise it is invalid after all
+ */
+ (void)rfc822_skip_lwsp(&parser);
+ if (parser.data != parser.end && *parser.data != ';')
+ return FALSE;
+
+ /* Success */
+ data = str_c(content_type);
+ if (str_begins(data, "text/"))
+ return TRUE;
+ return FALSE;
+}
+
+static int
+cmd_notify_extract_body_text(const struct sieve_runtime_env *renv,
+ const char **body_text_r, size_t *body_size_r)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ struct ext_notify_message_context *mctx;
+ struct mail *mail = eenv->msgdata->mail;
+ struct message_parser_ctx *parser;
+ struct message_decoder_context *decoder;
+ struct message_part *parts;
+ struct message_block block, decoded;
+ struct istream *input;
+ bool is_text, save_body;
+ int ret = 1;
+
+ *body_text_r = NULL;
+ *body_size_r = 0;
+
+ /* Return cached result if available */
+ mctx = ext_notify_get_message_context(this_ext, renv->msgctx);
+ if (mctx->body_text != NULL) {
+ *body_text_r = (const char *)
+ buffer_get_data(mctx->body_text, body_size_r);
+ return SIEVE_EXEC_OK;
+ }
+
+ /* Create buffer */
+ mctx->body_text = buffer_create_dynamic(mctx->pool, 1024*64);
+
+ /* Get the message stream */
+ if (mail_get_stream(mail, NULL, NULL, &input) < 0) {
+ return sieve_runtime_mail_error(renv, mail, "notify action: "
+ "failed to read input message");
+ }
+
+ /* Initialize body decoder */
+ decoder = message_decoder_init(NULL, 0);
+
+ struct message_parser_settings mparser_set = {
+ .hdr_flags = 0,
+ .flags = 0,
+ };
+ parser = message_parser_init(mctx->pool, input, &mparser_set);
+ is_text = TRUE;
+ save_body = FALSE;
+ while ((ret = message_parser_parse_next_block(parser, &block)) > 0) {
+ if (block.hdr != NULL || block.size == 0) {
+ /* Decode block */
+ (void)message_decoder_decode_next_block(decoder, &block,
+ &decoded);
+
+ /* Check for end of headers */
+ if (block.hdr == NULL) {
+ save_body = is_text;
+ continue;
+ }
+
+ /* We're interested of only Content-Type: header */
+ if (strcasecmp(block.hdr->name, "Content-Type") != 0)
+ continue;
+
+ /* Header can have folding whitespace. Acquire the full
+ value before continuing */
+ if (block.hdr->continues) {
+ block.hdr->use_full_value = TRUE;
+ continue;
+ }
+
+ /* Is it a text part? */
+ T_BEGIN {
+ is_text = _is_text_content(block.hdr);
+ } T_END;
+
+ continue;
+ }
+
+ /* Read text body */
+ if (save_body) {
+ (void)message_decoder_decode_next_block(decoder, &block,
+ &decoded);
+ buffer_append(mctx->body_text, decoded.data,
+ decoded.size);
+ is_text = TRUE;
+ }
+ }
+
+ /* Cleanup */
+ (void)message_parser_deinit(&parser, &parts);
+ message_decoder_deinit(&decoder);
+
+ if (ret < 0 && input->stream_errno != 0) {
+ sieve_runtime_critical(renv, NULL, "notify action: "
+ "failed to read input message",
+ "notify action: read(%s) failed: %s",
+ i_stream_get_name(input),
+ i_stream_get_error(input));
+ return SIEVE_EXEC_TEMP_FAILURE;
+ }
+
+ /* Return status */
+ *body_text_r = (const char *)buffer_get_data(mctx->body_text,
+ body_size_r);
+ return SIEVE_EXEC_OK;
+}
+
+int ext_notify_construct_message(const struct sieve_runtime_env *renv,
+ const char *msg_format,
+ string_t *out_msg)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_message_data *msgdata = eenv->msgdata;
+ struct sieve_message_context *msgctx = renv->msgctx;
+ const struct smtp_address *return_path =
+ sieve_message_get_sender(msgctx);
+ const char *p;
+ int ret;
+
+ if (msg_format == NULL)
+ msg_format = "$from$: $subject$";
+
+ /* Scan message for substitutions */
+ p = msg_format;
+ while (*p != '\0') {
+ const char *header;
+
+ if (strncasecmp(p, "$from$", 6) == 0) {
+ p += 6;
+
+ /* Fetch sender from original message */
+ if ((ret = mail_get_first_header_utf8(
+ msgdata->mail, "from", &header)) < 0) {
+ return sieve_runtime_mail_error(
+ renv, msgdata->mail,
+ "failed to read header field `from'");
+ }
+ if (ret > 0)
+ str_append(out_msg, header);
+ } else if (strncasecmp(p, "$env-from$", 10) == 0) {
+ p += 10;
+
+ if (return_path != NULL)
+ smtp_address_write(out_msg, return_path);
+ } else if (strncasecmp(p, "$subject$", 9) == 0) {
+ p += 9;
+
+ /* Fetch sender from oriinal message */
+ if ((ret = mail_get_first_header_utf8(
+ msgdata->mail, "subject", &header)) < 0) {
+ return sieve_runtime_mail_error(
+ renv, msgdata->mail,
+ "failed to read header field `subject'");
+ }
+ if (ret > 0)
+ str_append(out_msg, header);
+ } else if (strncasecmp(p, "$text", 5) == 0 &&
+ (p[5] == '[' || p[5] == '$')) {
+ size_t num = 0;
+ const char *begin = p;
+ bool valid = TRUE;
+
+ p += 5;
+ if (*p == '[') {
+ p += 1;
+
+ while (i_isdigit(*p)) {
+ num = num * 10 + (*p - '0');
+ p++;
+ }
+
+ if (*p++ != ']' || *p++ != '$') {
+ str_append_data(out_msg, begin,
+ p-begin);
+ valid = FALSE;
+ }
+ } else {
+ p += 1;
+ }
+
+ if (valid) {
+ size_t body_size;
+ const char *body_text;
+
+ if ((ret = cmd_notify_extract_body_text(
+ renv, &body_text, &body_size)) <= 0)
+ return ret;
+
+ if (num > 0 && num < body_size) {
+ str_append_data(out_msg, body_text,
+ num);
+ } else {
+ str_append_data(out_msg, body_text,
+ body_size);
+ }
+ }
+ } else {
+ size_t len;
+
+ /* Find next substitution */
+ len = strcspn(p + 1, "$") + 1;
+
+ /* Copy normal text */
+ str_append_data(out_msg, p, len);
+ p += len;
+ }
+ }
+
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/notify/ext-notify-common.h b/pigeonhole/src/lib-sieve/plugins/notify/ext-notify-common.h
new file mode 100644
index 0000000..09db2cb
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/notify/ext-notify-common.h
@@ -0,0 +1,66 @@
+#ifndef EXT_NOTIFY_COMMON_H
+#define EXT_NOTIFY_COMMON_H
+
+/*
+ * Extension
+ */
+
+extern const struct sieve_extension_def notify_extension;
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def cmd_notify_old;
+extern const struct sieve_command_def cmd_denotify;
+
+/*
+ * Arguments
+ */
+
+void ext_notify_register_importance_tags(
+ struct sieve_validator *valdtr,
+ struct sieve_command_registration *cmd_reg,
+ const struct sieve_extension *this_ext, unsigned int id_code);
+
+/*
+ * Operations
+ */
+
+extern const struct sieve_operation_def notify_old_operation;
+extern const struct sieve_operation_def denotify_operation;
+
+enum ext_notify_opcode {
+ EXT_NOTIFY_OPERATION_NOTIFY,
+ EXT_NOTIFY_OPERATION_DENOTIFY,
+};
+
+/*
+ * Actions
+ */
+
+extern const struct sieve_action_def act_notify_old;
+
+struct ext_notify_recipient {
+ const char *full;
+ const struct smtp_address *address;
+};
+
+ARRAY_DEFINE_TYPE(recipients, struct ext_notify_recipient);
+
+struct ext_notify_action {
+ const char *id;
+ const char *message;
+ sieve_number_t importance;
+
+ ARRAY_TYPE(recipients) recipients;
+};
+
+/*
+ * Message construct
+ */
+
+int ext_notify_construct_message(const struct sieve_runtime_env *renv,
+ const char *msg_format, string_t *out_msg);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/notify/ext-notify-limits.h b/pigeonhole/src/lib-sieve/plugins/notify/ext-notify-limits.h
new file mode 100644
index 0000000..5fab7cb
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/notify/ext-notify-limits.h
@@ -0,0 +1,7 @@
+#ifndef EXT_NOTIFY_LIMITS_H
+#define EXT_NOTIFY_LIMITS_H
+
+#define EXT_NOTIFY_MAX_RECIPIENTS 8
+#define EXT_NOTIFY_MAX_MESSAGE 256
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/notify/ext-notify.c b/pigeonhole/src/lib-sieve/plugins/notify/ext-notify.c
new file mode 100644
index 0000000..e79e049
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/notify/ext-notify.c
@@ -0,0 +1,108 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension notify
+ * ----------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: draft-ietf-sieve-notify-00.txt
+ * Implementation: full, but deprecated; provided for backwards compatibility
+ * Status: testing
+ *
+ */
+
+#include "sieve-common.h"
+
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-actions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-result.h"
+
+#include "ext-notify-common.h"
+
+/*
+ * Operations
+ */
+
+const struct sieve_operation_def *ext_notify_operations[] = {
+ &notify_old_operation,
+ &denotify_operation
+};
+
+/*
+ * Extension
+ */
+
+static bool ext_notify_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def notify_extension = {
+ .name = "notify",
+ .validator_load = ext_notify_validator_load,
+ SIEVE_EXT_DEFINE_OPERATIONS(ext_notify_operations)
+};
+
+/*
+ * Extension validation
+ */
+
+static bool ext_notify_validator_check_conflict
+ (const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context,
+ struct sieve_ast_argument *require_arg,
+ const struct sieve_extension *ext_other,
+ bool required);
+static bool ext_notify_validator_validate
+ (const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context,
+ struct sieve_ast_argument *require_arg,
+ bool required);
+
+const struct sieve_validator_extension notify_validator_extension = {
+ .ext = &notify_extension,
+ .check_conflict = ext_notify_validator_check_conflict,
+ .validate = ext_notify_validator_validate
+};
+
+static bool ext_notify_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Register validator extension to check for conflict with enotify */
+ sieve_validator_extension_register
+ (valdtr, ext, &notify_validator_extension, NULL);
+ return TRUE;
+}
+
+static bool ext_notify_validator_check_conflict
+(const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_validator *valdtr, void *context ATTR_UNUSED,
+ struct sieve_ast_argument *require_arg,
+ const struct sieve_extension *ext_other,
+ bool required ATTR_UNUSED)
+{
+ /* Check for conflict with enotify */
+ if ( sieve_extension_name_is(ext_other, "enotify") ) {
+ sieve_argument_validate_error(valdtr, require_arg,
+ "the (deprecated) notify extension cannot be used "
+ "together with the enotify extension");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool ext_notify_validator_validate
+(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context ATTR_UNUSED,
+ struct sieve_ast_argument *require_arg ATTR_UNUSED,
+ bool required ATTR_UNUSED)
+{
+ /* No conflicts: register new commands */
+ sieve_validator_register_command(valdtr, ext, &cmd_notify_old);
+ sieve_validator_register_command(valdtr, ext, &cmd_denotify);
+ return TRUE;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/regex/Makefile.am b/pigeonhole/src/lib-sieve/plugins/regex/Makefile.am
new file mode 100644
index 0000000..eeb735e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/regex/Makefile.am
@@ -0,0 +1,13 @@
+noinst_LTLIBRARIES = libsieve_ext_regex.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+libsieve_ext_regex_la_SOURCES = \
+ mcht-regex.c \
+ ext-regex-common.c \
+ ext-regex.c
+
+noinst_HEADERS = \
+ ext-regex-common.h
diff --git a/pigeonhole/src/lib-sieve/plugins/regex/Makefile.in b/pigeonhole/src/lib-sieve/plugins/regex/Makefile.in
new file mode 100644
index 0000000..379d384
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/regex/Makefile.in
@@ -0,0 +1,688 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/regex
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_regex_la_LIBADD =
+am_libsieve_ext_regex_la_OBJECTS = mcht-regex.lo ext-regex-common.lo \
+ ext-regex.lo
+libsieve_ext_regex_la_OBJECTS = $(am_libsieve_ext_regex_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ext-regex-common.Plo \
+ ./$(DEPDIR)/ext-regex.Plo ./$(DEPDIR)/mcht-regex.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_regex_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_regex_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_regex.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+libsieve_ext_regex_la_SOURCES = \
+ mcht-regex.c \
+ ext-regex-common.c \
+ ext-regex.c
+
+noinst_HEADERS = \
+ ext-regex-common.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/regex/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/regex/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_regex.la: $(libsieve_ext_regex_la_OBJECTS) $(libsieve_ext_regex_la_DEPENDENCIES) $(EXTRA_libsieve_ext_regex_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_regex_la_OBJECTS) $(libsieve_ext_regex_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-regex-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-regex.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcht-regex.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ext-regex-common.Plo
+ -rm -f ./$(DEPDIR)/ext-regex.Plo
+ -rm -f ./$(DEPDIR)/mcht-regex.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ext-regex-common.Plo
+ -rm -f ./$(DEPDIR)/ext-regex.Plo
+ -rm -f ./$(DEPDIR)/mcht-regex.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/regex/ext-regex-common.c b/pigeonhole/src/lib-sieve/plugins/regex/ext-regex-common.c
new file mode 100644
index 0000000..975f4fb
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/regex/ext-regex-common.c
@@ -0,0 +1,22 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-match-types.h"
+
+#include "ext-regex-common.h"
+
+/*
+ * Regex match type operand
+ */
+
+static const struct sieve_extension_objects ext_match_types =
+ SIEVE_EXT_DEFINE_MATCH_TYPE(regex_match_type);
+
+const struct sieve_operand_def regex_match_type_operand = {
+ .name = "regex match",
+ .ext_def = &regex_extension,
+ .class = &sieve_match_type_operand_class,
+ .interface = &ext_match_types
+};
+
diff --git a/pigeonhole/src/lib-sieve/plugins/regex/ext-regex-common.h b/pigeonhole/src/lib-sieve/plugins/regex/ext-regex-common.h
new file mode 100644
index 0000000..e9d809f
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/regex/ext-regex-common.h
@@ -0,0 +1,24 @@
+#ifndef EXT_REGEX_COMMON_H
+#define EXT_REGEX_COMMON_H
+
+/*
+ * Extension
+ */
+
+extern const struct sieve_extension_def regex_extension;
+
+/*
+ * Operand
+ */
+
+extern const struct sieve_operand_def regex_match_type_operand;
+
+/*
+ * Match type
+ */
+
+extern const struct sieve_match_type_def regex_match_type;
+
+#endif
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/regex/ext-regex.c b/pigeonhole/src/lib-sieve/plugins/regex/ext-regex.c
new file mode 100644
index 0000000..0440b30
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/regex/ext-regex.c
@@ -0,0 +1,65 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension regex
+ * ---------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: draft-murchison-sieve-regex-08 (not latest)
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+/* FIXME: Regular expressions are compiled during compilation and
+ * again during interpretation. This is suboptimal and should be
+ * changed. This requires dumping the compiled regex to the binary.
+ * Most likely, this will only be possible when we implement regular
+ * expressions ourselves.
+ *
+ */
+
+#include "lib.h"
+#include "mempool.h"
+#include "buffer.h"
+
+#include "sieve-common.h"
+
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+#include "ext-regex-common.h"
+
+#include <sys/types.h>
+#include <regex.h>
+
+/*
+ * Extension
+ */
+
+static bool ext_regex_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *validator);
+
+const struct sieve_extension_def regex_extension = {
+ .name = "regex",
+ .validator_load = ext_regex_validator_load,
+ SIEVE_EXT_DEFINE_OPERAND(regex_match_type_operand)
+};
+
+static bool ext_regex_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ sieve_match_type_register(valdtr, ext, &regex_match_type);
+
+ return TRUE;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/regex/mcht-regex.c b/pigeonhole/src/lib-sieve/plugins/regex/mcht-regex.c
new file mode 100644
index 0000000..f0c630e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/regex/mcht-regex.c
@@ -0,0 +1,385 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Match-type ':regex'
+ */
+
+#include "lib.h"
+#include "mempool.h"
+#include "buffer.h"
+#include "array.h"
+#include "str.h"
+#include "str-sanitize.h"
+
+#include "sieve-common.h"
+#include "sieve-limits.h"
+#include "sieve-ast.h"
+#include "sieve-stringlist.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-interpreter.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-match.h"
+
+#include "ext-regex-common.h"
+
+#include <sys/types.h>
+#include <regex.h>
+#include <ctype.h>
+
+/*
+ * Configuration
+ */
+
+#define MCHT_REGEX_MAX_SUBSTITUTIONS SIEVE_MAX_MATCH_VALUES
+
+/*
+ * Match type
+ */
+
+static bool mcht_regex_validate_context
+(struct sieve_validator *valdtr, struct sieve_ast_argument *arg,
+ struct sieve_match_type_context *ctx, struct sieve_ast_argument *key_arg);
+
+static void mcht_regex_match_init(struct sieve_match_context *mctx);
+static int mcht_regex_match_keys
+ (struct sieve_match_context *mctx, const char *val, size_t val_size,
+ struct sieve_stringlist *key_list);
+static void mcht_regex_match_deinit(struct sieve_match_context *mctx);
+
+const struct sieve_match_type_def regex_match_type = {
+ SIEVE_OBJECT("regex", &regex_match_type_operand, 0),
+ .validate_context = mcht_regex_validate_context,
+ .match_init = mcht_regex_match_init,
+ .match_keys = mcht_regex_match_keys,
+ .match_deinit = mcht_regex_match_deinit
+};
+
+/*
+ * Match type validation
+ */
+
+/* Wrapper around the regerror function for easy access */
+static const char *_regexp_error(regex_t *regexp, int errorcode)
+{
+ size_t errsize = regerror(errorcode, regexp, NULL, 0);
+
+ if ( errsize > 0 ) {
+ char *errbuf;
+
+ buffer_t *error_buf =
+ buffer_create_dynamic(pool_datastack_create(), errsize);
+ errbuf = buffer_get_space_unsafe(error_buf, 0, errsize);
+
+ errsize = regerror(errorcode, regexp, errbuf, errsize);
+
+ /* We don't want the error to start with a capital letter */
+ errbuf[0] = i_tolower(errbuf[0]);
+
+ buffer_append_space_unsafe(error_buf, errsize);
+
+ return str_c(error_buf);
+ }
+
+ return "";
+}
+
+static int mcht_regex_validate_regexp
+(struct sieve_validator *valdtr,
+ struct sieve_match_type_context *mtctx ATTR_UNUSED,
+ struct sieve_ast_argument *key, int cflags)
+{
+ int ret;
+ regex_t regexp;
+ const char *regex_str = sieve_ast_argument_strc(key);
+
+ if ( (ret=regcomp(&regexp, regex_str, cflags)) != 0 ) {
+ sieve_argument_validate_error(valdtr, key,
+ "invalid regular expression '%s' for regex match: %s",
+ str_sanitize(regex_str, 128), _regexp_error(&regexp, ret));
+
+ regfree(&regexp);
+ return -1;
+ }
+
+ regfree(&regexp);
+ return 1;
+}
+
+struct _regex_key_context {
+ struct sieve_validator *valdtr;
+ struct sieve_match_type_context *mtctx;
+ int cflags;
+};
+
+static int mcht_regex_validate_key_argument
+(void *context, struct sieve_ast_argument *key)
+{
+ struct _regex_key_context *keyctx = (struct _regex_key_context *) context;
+
+ /* FIXME: We can currently only handle string literal argument, so
+ * variables are not allowed.
+ */
+ if ( sieve_argument_is_string_literal(key) ) {
+ return mcht_regex_validate_regexp
+ (keyctx->valdtr, keyctx->mtctx, key, keyctx->cflags);
+ }
+
+ return 1;
+}
+
+static bool mcht_regex_validate_context
+(struct sieve_validator *valdtr, struct sieve_ast_argument *arg ATTR_UNUSED,
+ struct sieve_match_type_context *mtctx, struct sieve_ast_argument *key_arg)
+{
+ const struct sieve_comparator *cmp = mtctx->comparator;
+ int cflags = REG_EXTENDED | REG_NOSUB;
+ struct _regex_key_context keyctx;
+ struct sieve_ast_argument *kitem;
+
+ if ( cmp != NULL ) {
+ if ( sieve_comparator_is(cmp, i_ascii_casemap_comparator) )
+ cflags = REG_EXTENDED | REG_NOSUB | REG_ICASE;
+ else if ( sieve_comparator_is(cmp, i_octet_comparator) )
+ cflags = REG_EXTENDED | REG_NOSUB;
+ else {
+ sieve_argument_validate_error(valdtr, mtctx->argument,
+ "regex match type only supports "
+ "i;octet and i;ascii-casemap comparators" );
+ return FALSE;
+ }
+ }
+
+ /* Validate regular expression keys */
+
+ keyctx.valdtr = valdtr;
+ keyctx.mtctx = mtctx;
+ keyctx.cflags = cflags;
+
+ kitem = key_arg;
+ if ( sieve_ast_stringlist_map(&kitem, (void *) &keyctx,
+ mcht_regex_validate_key_argument) <= 0 )
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Match type implementation
+ */
+
+struct mcht_regex_key {
+ regex_t regexp;
+ int status;
+};
+
+struct mcht_regex_context {
+ ARRAY(struct mcht_regex_key) reg_expressions;
+ regmatch_t *pmatch;
+ size_t nmatch;
+ bool all_compiled:1;
+};
+
+static void mcht_regex_match_init
+(struct sieve_match_context *mctx)
+{
+ pool_t pool = mctx->pool;
+ struct mcht_regex_context *ctx;
+
+ /* Create context */
+ ctx = p_new(pool, struct mcht_regex_context, 1);
+
+ /* Create storage for match values if match values are requested */
+ if ( sieve_match_values_are_enabled(mctx->runenv) ) {
+ ctx->pmatch = p_new(pool, regmatch_t, MCHT_REGEX_MAX_SUBSTITUTIONS);
+ ctx->nmatch = MCHT_REGEX_MAX_SUBSTITUTIONS;
+ } else {
+ ctx->pmatch = NULL;
+ ctx->nmatch = 0;
+ }
+
+ /* Assign context */
+ mctx->data = (void *) ctx;
+}
+
+static int mcht_regex_match_key
+(struct sieve_match_context *mctx, const char *val,
+ const regex_t *regexp)
+{
+ struct mcht_regex_context *ctx = (struct mcht_regex_context *) mctx->data;
+ int ret;
+
+ /* Execute regex */
+
+ ret = regexec(regexp, val, ctx->nmatch, ctx->pmatch, 0);
+
+ /* Handle match values if necessary */
+
+ if ( ret == 0 ) {
+ if ( ctx->nmatch > 0 ) {
+ struct sieve_match_values *mvalues;
+ size_t i;
+ int skipped = 0;
+ string_t *subst = t_str_new(32);
+
+ /* Start new list of match values */
+ mvalues = sieve_match_values_start(mctx->runenv);
+
+ i_assert( mvalues != NULL );
+
+ /* Add match values from regular expression */
+ for ( i = 0; i < ctx->nmatch; i++ ) {
+ str_truncate(subst, 0);
+
+ if ( ctx->pmatch[i].rm_so != -1 ) {
+ if ( skipped > 0 ) {
+ sieve_match_values_skip(mvalues, skipped);
+ skipped = 0;
+ }
+
+ str_append_data(subst, val + ctx->pmatch[i].rm_so,
+ ctx->pmatch[i].rm_eo - ctx->pmatch[i].rm_so);
+ sieve_match_values_add(mvalues, subst);
+ } else
+ skipped++;
+ }
+
+ /* Substitute the new match values */
+ sieve_match_values_commit(mctx->runenv, &mvalues);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int mcht_regex_match_keys
+(struct sieve_match_context *mctx, const char *val, size_t val_size ATTR_UNUSED,
+ struct sieve_stringlist *key_list)
+{
+ const struct sieve_runtime_env *renv = mctx->runenv;
+ bool trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING);
+ struct mcht_regex_context *ctx = (struct mcht_regex_context *) mctx->data;
+ const struct sieve_comparator *cmp = mctx->comparator;
+ int match;
+
+ if ( !ctx->all_compiled ) {
+ string_t *key_item = NULL;
+ unsigned int i;
+ int ret;
+
+ /* Regular expressions still need to be compiled */
+
+ if ( !array_is_created(&ctx->reg_expressions) )
+ p_array_init(&ctx->reg_expressions, mctx->pool, 16);
+
+ i = 0;
+ match = 0;
+ while ( match == 0 &&
+ (ret=sieve_stringlist_next_item(key_list, &key_item)) > 0 ) {
+
+ T_BEGIN {
+ struct mcht_regex_key *rkey;
+
+ if ( i >= array_count(&ctx->reg_expressions) ) {
+ int cflags;
+
+ rkey = array_append_space(&ctx->reg_expressions);
+
+ /* Configure case-sensitivity according to comparator */
+ if ( sieve_comparator_is(cmp, i_octet_comparator) )
+ cflags = REG_EXTENDED;
+ else if ( sieve_comparator_is(cmp, i_ascii_casemap_comparator) )
+ cflags = REG_EXTENDED | REG_ICASE;
+ else
+ rkey->status = -1; /* Not supported */
+
+ if ( rkey->status >= 0 ) {
+ const char *regex_str = str_c(key_item);
+ int rxret;
+
+ /* Indicate whether match values need to be produced */
+ if ( ctx->nmatch == 0 ) cflags |= REG_NOSUB;
+
+ /* Compile regular expression */
+ if ( (rxret=regcomp(&rkey->regexp, regex_str, cflags)) != 0 ) {
+ sieve_runtime_error(renv, NULL,
+ "invalid regular expression '%s' for regex match: %s",
+ str_sanitize(regex_str, 128),
+ _regexp_error(&rkey->regexp, rxret));
+ rkey->status = -1;
+ } else {
+ rkey->status = 1;
+ }
+ }
+ } else {
+ rkey = array_idx_modifiable(&ctx->reg_expressions, 1);
+ }
+
+ if ( rkey->status > 0 ) {
+ match = mcht_regex_match_key(mctx, val, &rkey->regexp);
+
+ if ( trace ) {
+ sieve_runtime_trace(renv, 0,
+ "with regex `%s' [id=%d] => %d",
+ str_sanitize(str_c(key_item), 80),
+ array_count(&ctx->reg_expressions)-1, match);
+ }
+ }
+ } T_END;
+
+ i++;
+ }
+
+ if ( ret == 0 ) {
+ ctx->all_compiled = TRUE;
+ } else if ( ret < 0 ) {
+ mctx->exec_status = key_list->exec_status;
+ match = -1;
+ }
+
+ } else {
+ const struct mcht_regex_key *rkeys;
+ unsigned int i, count;
+
+ /* Regular expressions are compiled */
+
+ rkeys = array_get(&ctx->reg_expressions, &count);
+
+ i = 0;
+ match = 0;
+ while ( match == 0 && i < count ) {
+ if ( rkeys[i].status > 0 ) {
+ match = mcht_regex_match_key(mctx, val, &rkeys[i].regexp);
+
+ if ( trace ) {
+ sieve_runtime_trace(renv, 0,
+ "with compiled regex [id=%d] => %d", i, match);
+ }
+ }
+
+ i++;
+ }
+ }
+
+ return match;
+}
+
+void mcht_regex_match_deinit
+(struct sieve_match_context *mctx)
+{
+ struct mcht_regex_context *ctx = (struct mcht_regex_context *) mctx->data;
+ struct mcht_regex_key *rkeys;
+ unsigned int count, i;
+
+ /* Clean up compiled regular expressions */
+ if ( array_is_created(&ctx->reg_expressions) ) {
+ rkeys = array_get_modifiable(&ctx->reg_expressions, &count);
+ for ( i = 0; i < count; i++ ) {
+ regfree(&rkeys[i].regexp);
+ }
+ }
+}
+
diff --git a/pigeonhole/src/lib-sieve/plugins/relational/Makefile.am b/pigeonhole/src/lib-sieve/plugins/relational/Makefile.am
new file mode 100644
index 0000000..dd28cc5
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/relational/Makefile.am
@@ -0,0 +1,14 @@
+noinst_LTLIBRARIES = libsieve_ext_relational.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+libsieve_ext_relational_la_SOURCES = \
+ ext-relational-common.c \
+ mcht-value.c \
+ mcht-count.c \
+ ext-relational.c
+
+noinst_HEADERS = \
+ ext-relational-common.h
diff --git a/pigeonhole/src/lib-sieve/plugins/relational/Makefile.in b/pigeonhole/src/lib-sieve/plugins/relational/Makefile.in
new file mode 100644
index 0000000..4977808
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/relational/Makefile.in
@@ -0,0 +1,694 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/relational
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_relational_la_LIBADD =
+am_libsieve_ext_relational_la_OBJECTS = ext-relational-common.lo \
+ mcht-value.lo mcht-count.lo ext-relational.lo
+libsieve_ext_relational_la_OBJECTS = \
+ $(am_libsieve_ext_relational_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ext-relational-common.Plo \
+ ./$(DEPDIR)/ext-relational.Plo ./$(DEPDIR)/mcht-count.Plo \
+ ./$(DEPDIR)/mcht-value.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_relational_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_relational_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_relational.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+libsieve_ext_relational_la_SOURCES = \
+ ext-relational-common.c \
+ mcht-value.c \
+ mcht-count.c \
+ ext-relational.c
+
+noinst_HEADERS = \
+ ext-relational-common.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/relational/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/relational/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_relational.la: $(libsieve_ext_relational_la_OBJECTS) $(libsieve_ext_relational_la_DEPENDENCIES) $(EXTRA_libsieve_ext_relational_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_relational_la_OBJECTS) $(libsieve_ext_relational_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-relational-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-relational.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcht-count.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcht-value.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ext-relational-common.Plo
+ -rm -f ./$(DEPDIR)/ext-relational.Plo
+ -rm -f ./$(DEPDIR)/mcht-count.Plo
+ -rm -f ./$(DEPDIR)/mcht-value.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ext-relational-common.Plo
+ -rm -f ./$(DEPDIR)/ext-relational.Plo
+ -rm -f ./$(DEPDIR)/mcht-count.Plo
+ -rm -f ./$(DEPDIR)/mcht-value.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/relational/ext-relational-common.c b/pigeonhole/src/lib-sieve/plugins/relational/ext-relational-common.c
new file mode 100644
index 0000000..a6dd1ed
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/relational/ext-relational-common.c
@@ -0,0 +1,171 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Syntax:
+
+ MATCH-TYPE =/ COUNT / VALUE
+ COUNT = ":count" relational-match
+ VALUE = ":value" relational-match
+ relational-match = DQUOTE ( "gt" / "ge" / "lt"
+ / "le" / "eq" / "ne" ) DQUOTE
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "str-sanitize.h"
+
+#include "sieve-common.h"
+#include "sieve-ast.h"
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+#include "ext-relational-common.h"
+
+/*
+ * Forward declarations
+ */
+
+const struct sieve_match_type_def *rel_match_types[];
+
+/*
+ * Validation
+ */
+
+bool mcht_relational_validate(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_match_type_context *ctx)
+{
+ struct sieve_match_type *mcht;
+ enum relational_match rel_match = REL_MATCH_INVALID;
+ pool_t pool = sieve_ast_argument_pool(ctx->argument);
+ string_t *rel_match_ident;
+
+ /* Check syntax:
+ relational-match = DQUOTE ( "gt" / "ge" / "lt"
+ / "le" / "eq" / "ne" ) DQUOTE
+
+ So, actually this must be a constant string and it is implemented as
+ such.
+ */
+
+ /* Did we get a string in the first place? */
+ if (*arg == NULL || (*arg)->type != SAAT_STRING) {
+ sieve_argument_validate_error(
+ valdtr, (*arg == NULL ? ctx->argument : *arg),
+ "the :%s match-type requires a constant string argument being "
+ "one of \"gt\", \"ge\", \"lt\", \"le\", \"eq\" or \"ne\", "
+ "but %s was found",
+ sieve_match_type_name(ctx->match_type),
+ (*arg == NULL ?
+ "none" : sieve_ast_argument_name(*arg)));
+ return FALSE;
+ }
+
+ /* Check the relational match id */
+
+ rel_match_ident = sieve_ast_argument_str(*arg);
+ if (str_len(rel_match_ident) == 2) {
+ const char *rel_match_id = str_c(rel_match_ident);
+
+ switch (rel_match_id[0]) {
+ /* "gt" or "ge" */
+ case 'g':
+ switch (rel_match_id[1]) {
+ case 't':
+ rel_match = REL_MATCH_GREATER;
+ break;
+ case 'e':
+ rel_match = REL_MATCH_GREATER_EQUAL;
+ break;
+ default:
+ rel_match = REL_MATCH_INVALID;
+ }
+ break;
+ /* "lt" or "le" */
+ case 'l':
+ switch (rel_match_id[1]) {
+ case 't':
+ rel_match = REL_MATCH_LESS;
+ break;
+ case 'e':
+ rel_match = REL_MATCH_LESS_EQUAL;
+ break;
+ default:
+ rel_match = REL_MATCH_INVALID;
+ }
+ break;
+ /* "eq" */
+ case 'e':
+ if (rel_match_id[1] == 'q')
+ rel_match = REL_MATCH_EQUAL;
+ else
+ rel_match = REL_MATCH_INVALID;
+ break;
+ /* "ne" */
+ case 'n':
+ if (rel_match_id[1] == 'e')
+ rel_match = REL_MATCH_NOT_EQUAL;
+ else
+ rel_match = REL_MATCH_INVALID;
+ break;
+ /* invalid */
+ default:
+ rel_match = REL_MATCH_INVALID;
+ }
+ }
+
+ if (rel_match >= REL_MATCH_INVALID) {
+ sieve_argument_validate_error(
+ valdtr, *arg,
+ "the :%s match-type requires a constant string argument being "
+ "one of \"gt\", \"ge\", \"lt\", \"le\", \"eq\" or \"ne\", "
+ "but \"%s\" was found",
+ sieve_match_type_name(ctx->match_type),
+ str_sanitize(str_c(rel_match_ident), 32));
+ return FALSE;
+ }
+
+ /* Delete argument */
+ *arg = sieve_ast_arguments_detach(*arg, 1);
+
+ /* Not used just yet */
+ ctx->ctx_data = (void *) rel_match;
+
+ /* Override the actual match type with a parameter-specific one
+ * FIXME: ugly!
+ */
+ mcht = p_new(pool, struct sieve_match_type, 1);
+ mcht->object.ext = ctx->match_type->object.ext;
+ SIEVE_OBJECT_SET_DEF(mcht, rel_match_types[
+ REL_MATCH_INDEX(ctx->match_type->object.def->code, rel_match)]);
+ ctx->match_type = mcht;
+
+ return TRUE;
+}
+
+/*
+ * Relational match-type operand
+ */
+
+const struct sieve_match_type_def *rel_match_types[] = {
+ &rel_match_value_gt, &rel_match_value_ge, &rel_match_value_lt,
+ &rel_match_value_le, &rel_match_value_eq, &rel_match_value_ne,
+ &rel_match_count_gt, &rel_match_count_ge, &rel_match_count_lt,
+ &rel_match_count_le, &rel_match_count_eq, &rel_match_count_ne,
+};
+
+static const struct sieve_extension_objects ext_match_types =
+ SIEVE_EXT_DEFINE_MATCH_TYPES(rel_match_types);
+
+const struct sieve_operand_def rel_match_type_operand = {
+ .name = "relational match",
+ .ext_def = &relational_extension,
+ .class = &sieve_match_type_operand_class,
+ .interface = &ext_match_types,
+};
diff --git a/pigeonhole/src/lib-sieve/plugins/relational/ext-relational-common.h b/pigeonhole/src/lib-sieve/plugins/relational/ext-relational-common.h
new file mode 100644
index 0000000..c0f7d3b
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/relational/ext-relational-common.h
@@ -0,0 +1,86 @@
+#ifndef EXT_RELATIONAL_COMMON_H
+#define EXT_RELATIONAL_COMMON_H
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve-common.h"
+
+/*
+ * Types
+ */
+
+enum ext_relational_match_type {
+ RELATIONAL_VALUE,
+ RELATIONAL_COUNT
+};
+
+enum relational_match {
+ REL_MATCH_GREATER,
+ REL_MATCH_GREATER_EQUAL,
+ REL_MATCH_LESS,
+ REL_MATCH_LESS_EQUAL,
+ REL_MATCH_EQUAL,
+ REL_MATCH_NOT_EQUAL,
+ REL_MATCH_INVALID
+};
+
+#define REL_MATCH_INDEX(type, match) (type * REL_MATCH_INVALID + match)
+#define REL_MATCH_TYPE(index) (index / REL_MATCH_INVALID)
+#define REL_MATCH(index) (index % REL_MATCH_INVALID)
+
+/*
+ * Extension definitions
+ */
+
+extern const struct sieve_extension_def relational_extension;
+
+/*
+ * Match types
+ */
+
+/* Registered for validation */
+
+extern const struct sieve_match_type_def value_match_type;
+extern const struct sieve_match_type_def count_match_type;
+
+/* Used in byte code */
+
+extern const struct sieve_match_type_def rel_match_count_gt;
+extern const struct sieve_match_type_def rel_match_count_ge;
+extern const struct sieve_match_type_def rel_match_count_lt;
+extern const struct sieve_match_type_def rel_match_count_le;
+extern const struct sieve_match_type_def rel_match_count_eq;
+extern const struct sieve_match_type_def rel_match_count_ne;
+
+extern const struct sieve_match_type_def rel_match_value_gt;
+extern const struct sieve_match_type_def rel_match_value_ge;
+extern const struct sieve_match_type_def rel_match_value_lt;
+extern const struct sieve_match_type_def rel_match_value_le;
+extern const struct sieve_match_type_def rel_match_value_eq;
+extern const struct sieve_match_type_def rel_match_value_ne;
+
+/*
+ * Operand
+ */
+
+extern const struct sieve_operand_def rel_match_type_operand;
+
+
+/*
+ * Match type validation
+ */
+
+bool mcht_relational_validate(struct sieve_validator *validator,
+ struct sieve_ast_argument **arg,
+ struct sieve_match_type_context *ctx);
+
+/*
+ * Value match function (also used by :count)
+ */
+
+int mcht_value_match_key(struct sieve_match_context *mctx,
+ const char *val, size_t val_size,
+ const char *key, size_t key_size);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/relational/ext-relational.c b/pigeonhole/src/lib-sieve/plugins/relational/ext-relational.c
new file mode 100644
index 0000000..28c278f
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/relational/ext-relational.c
@@ -0,0 +1,53 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension relational
+ * --------------------
+ *
+ * Author: Stephan Bosch
+ * Specification: RFC 3431
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve-common.h"
+
+#include "sieve-ast.h"
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+#include "ext-relational-common.h"
+
+/*
+ * Extension
+ */
+
+static bool ext_relational_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def relational_extension = {
+ .name = "relational",
+ .validator_load = ext_relational_validator_load,
+ SIEVE_EXT_DEFINE_OPERAND(rel_match_type_operand)
+};
+
+static bool ext_relational_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ sieve_match_type_register(valdtr, ext, &value_match_type);
+ sieve_match_type_register(valdtr, ext, &count_match_type);
+
+ return TRUE;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/relational/mcht-count.c b/pigeonhole/src/lib-sieve/plugins/relational/mcht-count.c
new file mode 100644
index 0000000..e31a63a
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/relational/mcht-count.c
@@ -0,0 +1,119 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Match-type ':count'
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "str-sanitize.h"
+
+#include "sieve-common.h"
+#include "sieve-ast.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-runtime-trace.h"
+#include "sieve-match.h"
+
+#include "ext-relational-common.h"
+
+/*
+ * Forward declarations
+ */
+
+static int mcht_count_match
+ (struct sieve_match_context *mctx, struct sieve_stringlist *value_list,
+ struct sieve_stringlist *key_list);
+
+/*
+ * Match-type objects
+ */
+
+const struct sieve_match_type_def count_match_type = {
+ SIEVE_OBJECT("count",
+ &rel_match_type_operand, RELATIONAL_COUNT),
+ .validate = mcht_relational_validate
+};
+
+#define COUNT_MATCH_TYPE(name, rel_match) \
+const struct sieve_match_type_def rel_match_count_ ## name = { \
+ SIEVE_OBJECT("count-" #name, \
+ &rel_match_type_operand, \
+ REL_MATCH_INDEX(RELATIONAL_COUNT, rel_match)), \
+ .match = mcht_count_match, \
+}
+
+COUNT_MATCH_TYPE(gt, REL_MATCH_GREATER);
+COUNT_MATCH_TYPE(ge, REL_MATCH_GREATER_EQUAL);
+COUNT_MATCH_TYPE(lt, REL_MATCH_LESS);
+COUNT_MATCH_TYPE(le, REL_MATCH_LESS_EQUAL);
+COUNT_MATCH_TYPE(eq, REL_MATCH_EQUAL);
+COUNT_MATCH_TYPE(ne, REL_MATCH_NOT_EQUAL);
+
+/*
+ * Match-type implementation
+ */
+
+static int mcht_count_match
+(struct sieve_match_context *mctx, struct sieve_stringlist *value_list,
+ struct sieve_stringlist *key_list)
+{
+ const struct sieve_runtime_env *renv = mctx->runenv;
+ bool trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING);
+ int count;
+ string_t *key_item;
+ int match, ret;
+
+ if ( (count=sieve_stringlist_get_length(value_list)) < 0 ) {
+ mctx->exec_status = value_list->exec_status;
+ return -1;
+ }
+
+ sieve_stringlist_reset(key_list);
+
+ string_t *value = t_str_new(20);
+ str_printfa(value, "%d", count);
+
+ if ( trace ) {
+ sieve_runtime_trace(renv, 0,
+ "matching count value `%s'", str_sanitize(str_c(value), 80));
+ }
+
+ sieve_runtime_trace_descend(renv);
+
+ /* Match to all key values */
+ key_item = NULL;
+ match = 0;
+ while ( match == 0 &&
+ (ret=sieve_stringlist_next_item(key_list, &key_item)) > 0 )
+ {
+ match = mcht_value_match_key
+ (mctx, str_c(value), str_len(value), str_c(key_item), str_len(key_item));
+
+ if ( trace ) {
+ sieve_runtime_trace(renv, 0,
+ "with key `%s' => %d", str_sanitize(str_c(key_item), 80), ret);
+ }
+ }
+
+ sieve_runtime_trace_ascend(renv);
+
+ if ( ret < 0 ) {
+ mctx->exec_status = key_list->exec_status;
+ match = -1;
+ }
+
+ return match;
+}
+
+
+
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/relational/mcht-value.c b/pigeonhole/src/lib-sieve/plugins/relational/mcht-value.c
new file mode 100644
index 0000000..dd55590
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/relational/mcht-value.c
@@ -0,0 +1,80 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve-common.h"
+
+#include "sieve-ast.h"
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-match.h"
+
+#include "ext-relational-common.h"
+
+/*
+ * Match-type objects
+ */
+
+const struct sieve_match_type_def value_match_type = {
+ SIEVE_OBJECT("value",
+ &rel_match_type_operand, RELATIONAL_VALUE),
+ .validate = mcht_relational_validate
+};
+
+#define VALUE_MATCH_TYPE(name, rel_match) \
+const struct sieve_match_type_def rel_match_value_ ## name = { \
+ SIEVE_OBJECT("value-" #name, \
+ &rel_match_type_operand, \
+ REL_MATCH_INDEX(RELATIONAL_VALUE, rel_match)), \
+ .match_key = mcht_value_match_key, \
+}
+
+VALUE_MATCH_TYPE(gt, REL_MATCH_GREATER);
+VALUE_MATCH_TYPE(ge, REL_MATCH_GREATER_EQUAL);
+VALUE_MATCH_TYPE(lt, REL_MATCH_LESS);
+VALUE_MATCH_TYPE(le, REL_MATCH_LESS_EQUAL);
+VALUE_MATCH_TYPE(eq, REL_MATCH_EQUAL);
+VALUE_MATCH_TYPE(ne, REL_MATCH_NOT_EQUAL);
+
+/*
+ * Match-type implementation
+ */
+
+int mcht_value_match_key
+(struct sieve_match_context *mctx, const char *val, size_t val_size,
+ const char *key, size_t key_size)
+{
+ const struct sieve_match_type *mtch = mctx->match_type;
+ unsigned int rel_match = REL_MATCH(mtch->object.def->code);
+ int cmp_result;
+
+ cmp_result = mctx->comparator->def->
+ compare(mctx->comparator, val, val_size, key, key_size);
+
+ switch ( rel_match ) {
+ case REL_MATCH_GREATER:
+ return ( cmp_result > 0 ? 1 : 0 );
+ case REL_MATCH_GREATER_EQUAL:
+ return ( cmp_result >= 0 ? 1 : 0 );
+ case REL_MATCH_LESS:
+ return ( cmp_result < 0 ? 1 : 0 );
+ case REL_MATCH_LESS_EQUAL:
+ return ( cmp_result <= 0 ? 1 : 0 );
+ case REL_MATCH_EQUAL:
+ return ( cmp_result == 0 ? 1 : 0);
+ case REL_MATCH_NOT_EQUAL:
+ return ( cmp_result != 0 ? 1 : 0);
+ }
+
+ i_unreached();
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/spamvirustest/Makefile.am b/pigeonhole/src/lib-sieve/plugins/spamvirustest/Makefile.am
new file mode 100644
index 0000000..6a15bdd
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/spamvirustest/Makefile.am
@@ -0,0 +1,16 @@
+noinst_LTLIBRARIES = libsieve_ext_spamvirustest.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+tests = \
+ tst-spamvirustest.c
+
+libsieve_ext_spamvirustest_la_SOURCES = \
+ $(tests) \
+ ext-spamvirustest-common.c \
+ ext-spamvirustest.c
+
+noinst_HEADERS = \
+ ext-spamvirustest-common.h
diff --git a/pigeonhole/src/lib-sieve/plugins/spamvirustest/Makefile.in b/pigeonhole/src/lib-sieve/plugins/spamvirustest/Makefile.in
new file mode 100644
index 0000000..dca31e3
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/spamvirustest/Makefile.in
@@ -0,0 +1,694 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/spamvirustest
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_spamvirustest_la_LIBADD =
+am__objects_1 = tst-spamvirustest.lo
+am_libsieve_ext_spamvirustest_la_OBJECTS = $(am__objects_1) \
+ ext-spamvirustest-common.lo ext-spamvirustest.lo
+libsieve_ext_spamvirustest_la_OBJECTS = \
+ $(am_libsieve_ext_spamvirustest_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ext-spamvirustest-common.Plo \
+ ./$(DEPDIR)/ext-spamvirustest.Plo \
+ ./$(DEPDIR)/tst-spamvirustest.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_spamvirustest_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_spamvirustest_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_spamvirustest.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+tests = \
+ tst-spamvirustest.c
+
+libsieve_ext_spamvirustest_la_SOURCES = \
+ $(tests) \
+ ext-spamvirustest-common.c \
+ ext-spamvirustest.c
+
+noinst_HEADERS = \
+ ext-spamvirustest-common.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/spamvirustest/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/spamvirustest/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_spamvirustest.la: $(libsieve_ext_spamvirustest_la_OBJECTS) $(libsieve_ext_spamvirustest_la_DEPENDENCIES) $(EXTRA_libsieve_ext_spamvirustest_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_spamvirustest_la_OBJECTS) $(libsieve_ext_spamvirustest_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-spamvirustest-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-spamvirustest.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-spamvirustest.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ext-spamvirustest-common.Plo
+ -rm -f ./$(DEPDIR)/ext-spamvirustest.Plo
+ -rm -f ./$(DEPDIR)/tst-spamvirustest.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ext-spamvirustest-common.Plo
+ -rm -f ./$(DEPDIR)/ext-spamvirustest.Plo
+ -rm -f ./$(DEPDIR)/tst-spamvirustest.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c b/pigeonhole/src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
new file mode 100644
index 0000000..38cb5d8
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c
@@ -0,0 +1,674 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "strfuncs.h"
+#include "mail-storage.h"
+
+#include "sieve-common.h"
+#include "sieve-settings.h"
+#include "sieve-error.h"
+#include "sieve-extensions.h"
+#include "sieve-message.h"
+#include "sieve-interpreter.h"
+#include "sieve-runtime-trace.h"
+
+#include "ext-spamvirustest-common.h"
+
+#include <sys/types.h>
+#include <regex.h>
+#include <ctype.h>
+
+/*
+ * Extension data
+ */
+
+enum ext_spamvirustest_status_type {
+ EXT_SPAMVIRUSTEST_STATUS_TYPE_SCORE,
+ EXT_SPAMVIRUSTEST_STATUS_TYPE_STRLEN,
+ EXT_SPAMVIRUSTEST_STATUS_TYPE_TEXT,
+};
+
+struct ext_spamvirustest_header_spec {
+ const char *header_name;
+ regex_t regexp;
+ bool regexp_match;
+};
+
+struct ext_spamvirustest_data {
+ pool_t pool;
+
+ int reload;
+
+ struct ext_spamvirustest_header_spec status_header;
+ struct ext_spamvirustest_header_spec max_header;
+
+ enum ext_spamvirustest_status_type status_type;
+
+ float max_value;
+
+ const char *text_values[11];
+};
+
+/*
+ * Regexp utility
+ */
+
+static bool _regexp_compile
+(regex_t *regexp, const char *data, const char **error_r)
+{
+ size_t errsize;
+ int ret;
+
+ *error_r = "";
+
+ if ( (ret=regcomp(regexp, data, REG_EXTENDED)) == 0 ) {
+ return TRUE;
+ }
+
+ errsize = regerror(ret, regexp, NULL, 0);
+
+ if ( errsize > 0 ) {
+ char *errbuf = t_malloc0(errsize);
+
+ (void)regerror(ret, regexp, errbuf, errsize);
+
+ /* We don't want the error to start with a capital letter */
+ errbuf[0] = i_tolower(errbuf[0]);
+
+ *error_r = errbuf;
+ }
+
+ return FALSE;
+}
+
+static const char *_regexp_match_get_value
+(const char *string, int index, regmatch_t pmatch[], int nmatch)
+{
+ if ( index > -1 && index < nmatch && pmatch[index].rm_so != -1 ) {
+ return t_strndup(string + pmatch[index].rm_so,
+ pmatch[index].rm_eo - pmatch[index].rm_so);
+ }
+ return NULL;
+}
+
+/*
+ * Configuration parser
+ */
+
+static bool ext_spamvirustest_header_spec_parse
+(struct ext_spamvirustest_header_spec *spec, pool_t pool, const char *data,
+ const char **error_r)
+{
+ const char *p;
+ const char *regexp_error;
+
+ if ( *data == '\0' ) {
+ *error_r = "empty header specification";
+ return FALSE;
+ }
+
+ /* Parse header name */
+
+ p = data;
+
+ while ( *p == ' ' || *p == '\t' ) p++;
+ while ( *p != ':' && *p != '\0' && *p != ' ' && *p != '\t' ) p++;
+
+ if ( *p == '\0' ) {
+ spec->header_name = p_strdup(pool, data);
+ return TRUE;
+ }
+
+ spec->header_name = p_strdup_until(pool, data, p);
+ while ( *p == ' ' || *p == '\t' ) p++;
+
+ if ( *p == '\0' ) {
+ spec->regexp_match = FALSE;
+ return TRUE;
+ }
+
+ /* Parse and compile regular expression */
+
+ if ( *p != ':' ) {
+ *error_r = t_strdup_printf("expecting ':', but found '%c'", *p);
+ return FALSE;
+ }
+ p++;
+ while ( *p == ' ' || *p == '\t' ) p++;
+
+ spec->regexp_match = TRUE;
+ if ( !_regexp_compile(&spec->regexp, p, &regexp_error) ) {
+ *error_r = t_strdup_printf("failed to compile regular expression '%s': "
+ "%s", p, regexp_error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void ext_spamvirustest_header_spec_free
+(struct ext_spamvirustest_header_spec *spec)
+{
+ regfree(&spec->regexp);
+}
+
+static bool ext_spamvirustest_parse_strlen_value
+(const char *str_value, float *value_r, const char **error_r)
+{
+ const char *p = str_value;
+ char ch = *p;
+
+ if ( *str_value == '\0' ) {
+ *value_r = 0;
+ return TRUE;
+ }
+
+ while ( *p == ch ) p++;
+
+ if ( *p != '\0' ) {
+ *error_r = t_strdup_printf(
+ "different character '%c' encountered in strlen value",
+ *p);
+ return FALSE;
+ }
+
+ *value_r = ( p - str_value );
+
+ return TRUE;
+}
+
+static bool ext_spamvirustest_parse_decimal_value
+(const char *str_value, float *value_r, const char **error_r)
+{
+ const char *p = str_value;
+ float value;
+ float sign = 1;
+ int digits;
+
+ if ( *p == '\0' ) {
+ *error_r = "empty value";
+ return FALSE;
+ }
+
+ if ( *p == '+' || *p == '-' ) {
+ if ( *p == '-' )
+ sign = -1;
+
+ p++;
+ }
+
+ value = 0;
+ digits = 0;
+ while ( i_isdigit(*p) ) {
+ value = value*10 + (*p-'0');
+ if ( digits++ > 4 ) {
+ *error_r = t_strdup_printf
+ ("decimal value has too many digits before radix point: %s",
+ str_value);
+ return FALSE;
+ }
+ p++;
+ }
+
+ if ( *p == '.' || *p == ',' ) {
+ float radix = .1;
+ p++;
+
+ digits = 0;
+ while ( i_isdigit(*p) ) {
+ value = value + (*p-'0')*radix;
+
+ if ( digits++ > 4 ) {
+ *error_r = t_strdup_printf
+ ("decimal value has too many digits after radix point: %s",
+ str_value);
+ return FALSE;
+ }
+ radix /= 10;
+ p++;
+ }
+ }
+
+ if ( *p != '\0' ) {
+ *error_r = t_strdup_printf
+ ("invalid decimal point value: %s", str_value);
+ return FALSE;
+ }
+
+ *value_r = value * sign;
+
+ return TRUE;
+}
+
+/*
+ * Extension initialization
+ */
+
+bool ext_spamvirustest_load
+(const struct sieve_extension *ext, void **context)
+{
+ struct ext_spamvirustest_data *ext_data =
+ (struct ext_spamvirustest_data *) *context;
+ struct sieve_instance *svinst = ext->svinst;
+ const char *ext_name, *status_header, *max_header, *status_type,
+ *max_value;
+ enum ext_spamvirustest_status_type type;
+ const char *error;
+ pool_t pool;
+ bool result = TRUE;
+ int reload = 0;
+
+ if ( *context != NULL ) {
+ reload = ext_data->reload + 1;
+ ext_spamvirustest_unload(ext);
+ *context = NULL;
+ }
+
+ /* FIXME:
+ * Prevent loading of both spamtest and spamtestplus: let these share
+ * contexts.
+ */
+
+ if ( sieve_extension_is(ext, spamtest_extension) ||
+ sieve_extension_is(ext, spamtestplus_extension) ) {
+ ext_name = spamtest_extension.name;
+ } else {
+ ext_name = sieve_extension_name(ext);
+ }
+
+ /* Get settings */
+
+ status_header = sieve_setting_get
+ (svinst, t_strconcat("sieve_", ext_name, "_status_header", NULL));
+ status_type = sieve_setting_get
+ (svinst, t_strconcat("sieve_", ext_name, "_status_type", NULL));
+ max_header = sieve_setting_get
+ (svinst, t_strconcat("sieve_", ext_name, "_max_header", NULL));
+ max_value = sieve_setting_get
+ (svinst, t_strconcat("sieve_", ext_name, "_max_value", NULL));
+
+ /* Base configuration */
+
+ if ( status_header == NULL ) {
+ return TRUE;
+ }
+
+ if ( status_type == NULL || strcmp(status_type, "score") == 0 ) {
+ type = EXT_SPAMVIRUSTEST_STATUS_TYPE_SCORE;
+ } else if ( strcmp(status_type, "strlen") == 0 ) {
+ type = EXT_SPAMVIRUSTEST_STATUS_TYPE_STRLEN;
+ } else if ( strcmp(status_type, "text") == 0 ) {
+ type = EXT_SPAMVIRUSTEST_STATUS_TYPE_TEXT;
+ } else {
+ e_error(svinst->event, "%s: "
+ "invalid status type '%s'", ext_name, status_type);
+ return FALSE;
+ }
+
+ /* Verify settings */
+
+ if ( type != EXT_SPAMVIRUSTEST_STATUS_TYPE_TEXT ) {
+
+ if ( max_header != NULL && max_value != NULL ) {
+ e_error(svinst->event, "%s: "
+ "sieve_%s_max_header and sieve_%s_max_value "
+ "cannot both be configured",
+ ext_name, ext_name, ext_name);
+ return TRUE;
+ }
+
+ if ( max_header == NULL && max_value == NULL ) {
+ e_error(svinst->event, "%s: "
+ "none of sieve_%s_max_header or sieve_%s_max_value "
+ "is configured", ext_name, ext_name, ext_name);
+ return TRUE;
+ }
+ } else {
+ if ( max_header != NULL ) {
+ e_warning(svinst->event, "%s: "
+ "setting sieve_%s_max_header has no meaning "
+ "for sieve_%s_status_type=text",
+ ext_name, ext_name, ext_name);
+ }
+
+ if ( max_value != NULL ) {
+ e_warning(svinst->event, "%s: "
+ "setting sieve_%s_max_value has no meaning "
+ "for sieve_%s_status_type=text",
+ ext_name, ext_name, ext_name);
+ }
+ }
+
+ pool = pool_alloconly_create("spamvirustest_data", 512);
+ ext_data = p_new(pool, struct ext_spamvirustest_data, 1);
+ ext_data->pool = pool;
+ ext_data->reload = reload;
+ ext_data->status_type = type;
+
+ if ( !ext_spamvirustest_header_spec_parse
+ (&ext_data->status_header, ext_data->pool, status_header, &error) ) {
+ e_error(svinst->event, "%s: "
+ "invalid status header specification '%s': %s",
+ ext_name, status_header, error);
+ result = FALSE;
+ }
+
+ if ( result ) {
+ if ( type != EXT_SPAMVIRUSTEST_STATUS_TYPE_TEXT ) {
+ /* Parse max header */
+
+ if ( max_header != NULL && !ext_spamvirustest_header_spec_parse
+ (&ext_data->max_header, ext_data->pool, max_header, &error) ) {
+ e_error(svinst->event, "%s: "
+ "invalid max header specification "
+ "'%s': %s", ext_name, max_header,
+ error);
+ result = FALSE;
+ }
+
+ /* Parse max value */
+
+ if ( result && max_value != NULL ) {
+ if ( !ext_spamvirustest_parse_decimal_value
+ (max_value, &ext_data->max_value, &error) ) {
+ e_error(svinst->event, "%s: "
+ "invalid max value specification "
+ "'%s': %s", ext_name, max_value,
+ error);
+ result = FALSE;
+ }
+ }
+
+ } else {
+ unsigned int i, max_text;
+
+ max_text = ( sieve_extension_is(ext, virustest_extension) ? 5 : 10 );
+
+ /* Get text values */
+ for ( i = 0; i <= max_text; i++ ) {
+ const char *value = sieve_setting_get
+ (svinst, t_strdup_printf("sieve_%s_text_value%d", ext_name, i));
+
+ if ( value != NULL && *value != '\0' )
+ ext_data->text_values[i] = p_strdup(ext_data->pool, value);
+ }
+
+ ext_data->max_value = 1;
+ }
+ }
+
+ if ( result ) {
+ *context = (void *) ext_data;
+ } else {
+ e_warning(svinst->event, "%s: "
+ "extension not configured, "
+ "tests will always match against \"0\"",
+ ext_name);
+ ext_spamvirustest_unload(ext);
+ *context = NULL;
+ }
+
+ return result;
+}
+
+void ext_spamvirustest_unload(const struct sieve_extension *ext)
+{
+ struct ext_spamvirustest_data *ext_data =
+ (struct ext_spamvirustest_data *) ext->context;
+
+ if ( ext_data != NULL ) {
+ ext_spamvirustest_header_spec_free(&ext_data->status_header);
+ ext_spamvirustest_header_spec_free(&ext_data->max_header);
+ pool_unref(&ext_data->pool);
+ }
+}
+
+/*
+ * Runtime
+ */
+
+struct ext_spamvirustest_message_context {
+ int reload;
+ float score_ratio;
+};
+
+static const char *ext_spamvirustest_get_score
+(const struct sieve_extension *ext, float score_ratio, bool percent)
+{
+ int score;
+
+ if ( score_ratio < 0 )
+ return "0";
+
+ if ( score_ratio > 1 )
+ score_ratio = 1;
+
+ if ( percent )
+ score = score_ratio * 100 + 0.001;
+ else if ( sieve_extension_is(ext, virustest_extension) )
+ score = score_ratio * 4 + 1.001;
+ else
+ score = score_ratio * 9 + 1.001;
+
+ return t_strdup_printf("%d", score);
+}
+
+int ext_spamvirustest_get_value
+(const struct sieve_runtime_env *renv, const struct sieve_extension *ext,
+ bool percent, const char **value_r)
+{
+ struct ext_spamvirustest_data *ext_data =
+ (struct ext_spamvirustest_data *) ext->context;
+ struct ext_spamvirustest_header_spec *status_header, *max_header;
+ struct sieve_message_context *msgctx = renv->msgctx;
+ struct ext_spamvirustest_message_context *mctx;
+ struct mail *mail;
+ regmatch_t match_values[2];
+ const char *header_value, *error;
+ const char *status = NULL, *max = NULL;
+ float status_value, max_value;
+ unsigned int i, max_text;
+ pool_t pool = sieve_interpreter_pool(renv->interp);
+
+ *value_r = "0";
+
+ /*
+ * Check whether extension is properly configured
+ */
+ if ( ext_data == NULL ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "error: extension not configured");
+ return SIEVE_EXEC_OK;
+ }
+
+ /*
+ * Check wether a cached result is available
+ */
+
+ mctx = (struct ext_spamvirustest_message_context *)
+ sieve_message_context_extension_get(msgctx, ext);
+
+ if ( mctx == NULL ) {
+ /* Create new context */
+ mctx = p_new(pool, struct ext_spamvirustest_message_context, 1);
+ sieve_message_context_extension_set(msgctx, ext, (void *)mctx);
+ } else if ( mctx->reload == ext_data->reload ) {
+ /* Use cached result */
+ *value_r = ext_spamvirustest_get_score(ext, mctx->score_ratio, percent);
+ return SIEVE_EXEC_OK;
+ } else {
+ /* Extension was reloaded (probably in testsuite) */
+ }
+
+ mctx->reload = ext_data->reload;
+
+ /*
+ * Get max status value
+ */
+
+ mail = sieve_message_get_mail(renv->msgctx);
+ status_header = &ext_data->status_header;
+ max_header = &ext_data->max_header;
+
+ if ( ext_data->status_type != EXT_SPAMVIRUSTEST_STATUS_TYPE_TEXT ) {
+ if ( max_header->header_name != NULL ) {
+ /* Get header from message */
+ if ( mail_get_first_header_utf8
+ (mail, max_header->header_name, &header_value) < 0 ) {
+ return sieve_runtime_mail_error (renv, mail,
+ "%s test: failed to read header field `%s'",
+ sieve_extension_name(ext), max_header->header_name);
+ }
+ if ( header_value == NULL ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "header '%s' not found in message",
+ max_header->header_name);
+ goto failed;
+ }
+
+ if ( max_header->regexp_match ) {
+ /* Execute regex */
+ if ( regexec(&max_header->regexp, header_value, 2, match_values, 0)
+ != 0 ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "regexp for header '%s' did not match "
+ "on value '%s'", max_header->header_name, header_value);
+ goto failed;
+ }
+
+ max = _regexp_match_get_value(header_value, 1, match_values, 2);
+ if ( max == NULL ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "regexp did not return match value "
+ "for string '%s'", header_value);
+ goto failed;
+ }
+ } else {
+ max = header_value;
+ }
+
+ if ( !ext_spamvirustest_parse_decimal_value(max, &max_value, &error) ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "failed to parse maximum value: %s", error);
+ goto failed;
+ }
+ } else {
+ max_value = ext_data->max_value;
+ }
+
+ if ( max_value == 0 ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "error: max value is 0");
+ goto failed;
+ }
+ } else {
+ max_value = ( sieve_extension_is(ext, virustest_extension) ? 5 : 10 );
+ }
+
+ /*
+ * Get status value
+ */
+
+ /* Get header from message */
+ if ( mail_get_first_header_utf8
+ (mail, status_header->header_name, &header_value) < 0 ) {
+ return sieve_runtime_mail_error (renv, mail,
+ "%s test: failed to read header field `%s'",
+ sieve_extension_name(ext), status_header->header_name);
+ }
+ if ( header_value == NULL ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "header '%s' not found in message",
+ status_header->header_name);
+ goto failed;
+ }
+
+ /* Execute regex */
+ if ( status_header->regexp_match ) {
+ if ( regexec(&status_header->regexp, header_value, 2, match_values, 0)
+ != 0 ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "regexp for header '%s' did not match on value '%s'",
+ status_header->header_name, header_value);
+ goto failed;
+ }
+
+ status = _regexp_match_get_value(header_value, 1, match_values, 2);
+ if ( status == NULL ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "regexp did not return match value for string '%s'",
+ header_value);
+ goto failed;
+ }
+ } else {
+ status = header_value;
+ }
+
+ switch ( ext_data->status_type ) {
+ case EXT_SPAMVIRUSTEST_STATUS_TYPE_SCORE:
+ if ( !ext_spamvirustest_parse_decimal_value
+ (status, &status_value, &error) ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "failed to parse status value '%s': %s",
+ status, error);
+ goto failed;
+ }
+ break;
+ case EXT_SPAMVIRUSTEST_STATUS_TYPE_STRLEN:
+ if ( !ext_spamvirustest_parse_strlen_value
+ (status, &status_value, &error) ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "failed to parse status value '%s': %s",
+ status, error);
+ goto failed;
+ }
+ break;
+ case EXT_SPAMVIRUSTEST_STATUS_TYPE_TEXT:
+ max_text = ( sieve_extension_is(ext, virustest_extension) ? 5 : 10 );
+ status_value = 0;
+
+ i = 0;
+ while ( i <= max_text ) {
+ if ( ext_data->text_values[i] != NULL &&
+ strcmp(status, ext_data->text_values[i]) == 0 ) {
+ status_value = (float) i;
+ break;
+ }
+ i++;
+ }
+
+ if ( i > max_text ) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "failed to match textstatus value '%s'",
+ status);
+ goto failed;
+ }
+ break;
+ default:
+ i_unreached();
+ break;
+ }
+
+ /* Calculate value */
+ if ( status_value < 0 )
+ mctx->score_ratio = 0;
+ else if ( status_value > max_value )
+ mctx->score_ratio = 1;
+ else
+ mctx->score_ratio = (status_value / max_value);
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "extracted score=%.3f, max=%.3f, ratio=%.0f %%",
+ status_value, max_value, mctx->score_ratio * 100);
+
+ *value_r = ext_spamvirustest_get_score(ext, mctx->score_ratio, percent);
+ return SIEVE_EXEC_OK;
+
+failed:
+ mctx->score_ratio = -1;
+ *value_r = "0";
+ return SIEVE_EXEC_OK;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h b/pigeonhole/src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
new file mode 100644
index 0000000..331a637
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.h
@@ -0,0 +1,35 @@
+#ifndef EXT_SPAMVIRUSTEST_COMMON_H
+#define EXT_SPAMVIRUSTEST_COMMON_H
+
+#include "sieve-common.h"
+
+/*
+ * Extensions
+ */
+
+extern const struct sieve_extension_def spamtest_extension;
+extern const struct sieve_extension_def spamtestplus_extension;
+extern const struct sieve_extension_def virustest_extension;
+
+bool ext_spamvirustest_load(const struct sieve_extension *ext, void **context);
+void ext_spamvirustest_unload(const struct sieve_extension *ext);
+
+/*
+ * Tests
+ */
+
+extern const struct sieve_command_def spamtest_test;
+extern const struct sieve_command_def virustest_test;
+
+int ext_spamvirustest_get_value
+(const struct sieve_runtime_env *renv, const struct sieve_extension *ext,
+ bool percent, const char **value_r);
+
+/*
+ * Operations
+ */
+
+extern const struct sieve_operation_def spamtest_operation;
+extern const struct sieve_operation_def virustest_operation;
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c b/pigeonhole/src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
new file mode 100644
index 0000000..e0c9b54
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/spamvirustest/ext-spamvirustest.c
@@ -0,0 +1,146 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extensions spamtest, spamtestplus and virustest
+ * -----------------------------------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5235
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+/* Configuration examples:
+ *
+ * # 1: X-Spam-Score: No, score=-3.2
+ *
+ * sieve_spamtest_status_header = \
+ * X-Spam-Score: [[:alnum:]]+, score=(-?[[:digit:]]+\.[[:digit:]])
+ * sieve_spamtest_max_value = 5.0
+ *
+ * # 2: X-Spam-Status: Yes
+ *
+ * sieve_spamtest_status_header = X-Spam-Status
+ * sieve_spamtest_status_type = yesno
+ * sieve_spamtest_max_value = Yes
+ *
+ * # 3: X-Spam-Score: sssssss
+ * sieve_spamtest_status_header = X-Spam-Score
+ * sieve_spamtest_status_type = strlen
+ * sieve_spamtest_max_value = 5
+ *
+ * # 4: X-Spam-Score: status=3.2 required=5.0
+ *
+ * sieve_spamtest_status_header = \
+ * X-Spam-Score: score=(-?[[:digit:]]+\.[[:digit:]]).*
+ * sieve_spamtest_max_header = \
+ * X-Spam-Score: score=-?[[:digit:]]+\.[[:digit:]] required=([[:digit:]]+\.[[:digit:]])
+ *
+ * # 5: X-Virus-Scan: Found to be clean.
+ *
+ * sieve_virustest_status_header = \
+ * X-Virus-Scan: Found to be (.+)\.
+ * sieve_virustest_status_type = text
+ * sieve_virustest_text_value1 = clean
+ * sieve_virustest_text_value5 = infected
+ */
+
+#include "lib.h"
+#include "array.h"
+
+#include "sieve-common.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+
+#include "sieve-validator.h"
+
+#include "ext-spamvirustest-common.h"
+
+/*
+ * Extensions
+ */
+
+/* Spamtest */
+
+static bool ext_spamvirustest_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *validator);
+
+const struct sieve_extension_def spamtest_extension = {
+ .name = "spamtest",
+ .load = ext_spamvirustest_load,
+ .unload = ext_spamvirustest_unload,
+ .validator_load = ext_spamvirustest_validator_load,
+ SIEVE_EXT_DEFINE_OPERATION(spamtest_operation)
+};
+
+const struct sieve_extension_def spamtestplus_extension = {
+ .name = "spamtestplus",
+ .load = ext_spamvirustest_load,
+ .unload = ext_spamvirustest_unload,
+ .validator_load = ext_spamvirustest_validator_load,
+ SIEVE_EXT_DEFINE_OPERATION(spamtest_operation)
+};
+
+const struct sieve_extension_def virustest_extension = {
+ .name = "virustest",
+ .load = ext_spamvirustest_load,
+ .unload = ext_spamvirustest_unload,
+ .validator_load = ext_spamvirustest_validator_load,
+ SIEVE_EXT_DEFINE_OPERATION(virustest_operation)
+};
+
+/*
+ * Implementation
+ */
+
+static bool ext_spamtest_validator_check_conflict
+ (const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context,
+ struct sieve_ast_argument *require_arg,
+ const struct sieve_extension *ext_other,
+ bool required);
+
+const struct sieve_validator_extension spamtest_validator_extension = {
+ .ext = &spamtest_extension,
+ .check_conflict = ext_spamtest_validator_check_conflict
+};
+
+static bool ext_spamvirustest_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Register new test */
+
+ if ( sieve_extension_is(ext, virustest_extension) ) {
+ sieve_validator_register_command(valdtr, ext, &virustest_test);
+ } else {
+ if ( sieve_extension_is(ext, spamtest_extension) ) {
+ /* Register validator extension to warn for duplicate */
+ sieve_validator_extension_register
+ (valdtr, ext, &spamtest_validator_extension, NULL);
+ }
+
+ sieve_validator_register_command(valdtr, ext, &spamtest_test);
+ }
+
+ return TRUE;
+}
+
+static bool ext_spamtest_validator_check_conflict
+(const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_validator *valdtr, void *context ATTR_UNUSED,
+ struct sieve_ast_argument *require_arg,
+ const struct sieve_extension *ext_other,
+ bool required ATTR_UNUSED)
+{
+ if ( sieve_extension_name_is(ext_other, "spamtestplus") ) {
+ sieve_argument_validate_warning(valdtr, require_arg,
+ "the spamtest and spamtestplus extensions should "
+ "not be specified at the same time");
+ }
+
+ return TRUE;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c b/pigeonhole/src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
new file mode 100644
index 0000000..26d051e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c
@@ -0,0 +1,304 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-address-parts.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-match.h"
+
+#include "ext-spamvirustest-common.h"
+
+/*
+ * Tests
+ */
+
+static bool tst_spamvirustest_validate
+ (struct sieve_validator *valdtr, struct sieve_command *tst);
+static bool tst_spamvirustest_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+static bool tst_spamvirustest_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+
+/* Spamtest test
+ *
+ * Syntax:
+ * spamtest [":percent"] [COMPARATOR] [MATCH-TYPE] <value: string>
+ */
+
+const struct sieve_command_def spamtest_test = {
+ .identifier = "spamtest",
+ .type = SCT_TEST,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_spamvirustest_registered,
+ .validate = tst_spamvirustest_validate,
+ .generate = tst_spamvirustest_generate
+};
+
+/* Virustest test
+ *
+ * Syntax:
+ * virustest [COMPARATOR] [MATCH-TYPE] <value: string>
+ */
+
+const struct sieve_command_def virustest_test = {
+ .identifier = "virustest",
+ .type = SCT_TEST,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_spamvirustest_registered,
+ .validate = tst_spamvirustest_validate,
+ .generate = tst_spamvirustest_generate
+};
+
+/*
+ * Tagged arguments
+ */
+
+static bool tst_spamtest_validate_percent_tag
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *tst);
+
+static const struct sieve_argument_def spamtest_percent_tag = {
+ .identifier = "percent",
+ .validate = tst_spamtest_validate_percent_tag
+};
+
+/*
+ * Spamtest and virustest operations
+ */
+
+static bool tst_spamvirustest_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int tst_spamvirustest_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def spamtest_operation = {
+ .mnemonic = "SPAMTEST",
+ .ext_def = &spamtest_extension,
+ .dump = tst_spamvirustest_operation_dump,
+ .execute = tst_spamvirustest_operation_execute
+};
+
+const struct sieve_operation_def virustest_operation = {
+ .mnemonic = "VIRUSTEST",
+ .ext_def = &virustest_extension,
+ .dump = tst_spamvirustest_operation_dump,
+ .execute = tst_spamvirustest_operation_execute
+};
+
+/*
+ * Optional operands
+ */
+
+enum tst_spamvirustest_optional {
+ OPT_SPAMTEST_PERCENT = SIEVE_MATCH_OPT_LAST,
+ OPT_SPAMTEST_LAST
+};
+
+/*
+ * Test registration
+ */
+
+static bool tst_spamvirustest_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_comparators_link_tag(valdtr, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
+ sieve_match_types_link_tags(valdtr, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
+
+ if ( sieve_extension_is(ext, spamtestplus_extension) ||
+ sieve_extension_is(ext, spamtest_extension) ) {
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, ext, &spamtest_percent_tag, OPT_SPAMTEST_PERCENT);
+ }
+
+ return TRUE;
+}
+
+/*
+ * Validation
+ */
+
+static bool tst_spamtest_validate_percent_tag
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *tst)
+{
+ if ( !sieve_extension_is(tst->ext, spamtestplus_extension) ) {
+ sieve_argument_validate_error(valdtr, *arg,
+ "the spamtest test only accepts the :percent argument when "
+ "the spamtestplus extension is active");
+ return FALSE;
+ }
+
+ /* Skip tag */
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+static bool tst_spamvirustest_validate
+(struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+ const struct sieve_match_type mcht_default =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ const struct sieve_comparator cmp_default =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+
+ /* Check value */
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "value", 1, SAAT_STRING) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ /* Validate the key argument to a specified match type */
+ return sieve_match_type_validate
+ (valdtr, tst, arg, &mcht_default, &cmp_default);
+}
+
+/*
+ * Code generation
+ */
+
+static bool tst_spamvirustest_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
+{
+ if ( sieve_command_is(tst, spamtest_test) )
+ sieve_operation_emit(cgenv->sblock, tst->ext, &spamtest_operation);
+ else if ( sieve_command_is(tst, virustest_test) )
+ sieve_operation_emit(cgenv->sblock, tst->ext, &virustest_operation);
+ else
+ i_unreached();
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, tst, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool tst_spamvirustest_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ int opt_code = 0;
+ const struct sieve_operation *op = denv->oprtn;
+
+ sieve_code_dumpf(denv, "%s", sieve_operation_mnemonic(op));
+ sieve_code_descend(denv);
+
+ /* Optional operands */
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_match_opr_optional_dump(denv, address, &opt_code)) < 0 )
+ return FALSE;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_SPAMTEST_PERCENT:
+ sieve_code_dumpf(denv, "percent");
+ break;
+ default:
+ return FALSE;
+ }
+ }
+
+ return
+ sieve_opr_string_dump(denv, address, "value");
+}
+
+/*
+ * Code execution
+ */
+
+static int tst_spamvirustest_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ const struct sieve_operation *op = renv->oprtn;
+ const struct sieve_extension *this_ext = op->ext;
+ int opt_code = 0;
+ struct sieve_match_type mcht =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ struct sieve_comparator cmp =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+ bool percent = FALSE;
+ struct sieve_stringlist *value_list, *key_list;
+ const char *score_value;
+ int match, ret;
+
+ /* Read optional operands */
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_match_opr_optional_read
+ (renv, address, &opt_code, &ret, &cmp, &mcht)) < 0 )
+ return ret;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_SPAMTEST_PERCENT:
+ percent = TRUE;
+ break;
+ default:
+ sieve_runtime_trace_error(renv, "unknown optional operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ }
+
+ /* Read value part */
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "value", &key_list)) <= 0 )
+ return ret;
+
+ /* Perform test */
+
+ if ( sieve_operation_is(op, spamtest_operation) ) {
+ sieve_runtime_trace
+ (renv, SIEVE_TRLVL_TESTS, "spamtest test [percent=%s]",
+ ( percent ? "true" : "false" ));
+ } else {
+ sieve_runtime_trace
+ (renv, SIEVE_TRLVL_TESTS, "virustest test");
+ }
+
+ /* Get score value */
+ sieve_runtime_trace_descend(renv);
+ if ( (ret=ext_spamvirustest_get_value
+ (renv, this_ext, percent, &score_value)) <= 0 )
+ return ret;
+ sieve_runtime_trace_ascend(renv);
+
+ /* Construct value list */
+ value_list = sieve_single_stringlist_create_cstr(renv, score_value, TRUE);
+
+ /* Perform match */
+ if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret)) < 0 )
+ return ret;
+
+ /* Set test result for subsequent conditional jump */
+ sieve_interpreter_set_test_result(renv->interp, match > 0);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/special-use/Makefile.am b/pigeonhole/src/lib-sieve/plugins/special-use/Makefile.am
new file mode 100644
index 0000000..0f31aee
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/special-use/Makefile.am
@@ -0,0 +1,22 @@
+noinst_LTLIBRARIES = libsieve_ext_special_use.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+tags = \
+ tag-specialuse.c
+
+tests = \
+ tst-specialuse-exists.c
+
+libsieve_ext_special_use_la_SOURCES = \
+ $(tags) \
+ $(tests) \
+ ext-special-use-common.c \
+ ext-special-use.c
+
+headers = \
+ ext-special-use-common.h
+
+noinst_HEADERS = $(headers)
diff --git a/pigeonhole/src/lib-sieve/plugins/special-use/Makefile.in b/pigeonhole/src/lib-sieve/plugins/special-use/Makefile.in
new file mode 100644
index 0000000..5032dae
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/special-use/Makefile.in
@@ -0,0 +1,703 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/special-use
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_special_use_la_LIBADD =
+am__objects_1 = tag-specialuse.lo
+am__objects_2 = tst-specialuse-exists.lo
+am_libsieve_ext_special_use_la_OBJECTS = $(am__objects_1) \
+ $(am__objects_2) ext-special-use-common.lo ext-special-use.lo
+libsieve_ext_special_use_la_OBJECTS = \
+ $(am_libsieve_ext_special_use_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ext-special-use-common.Plo \
+ ./$(DEPDIR)/ext-special-use.Plo ./$(DEPDIR)/tag-specialuse.Plo \
+ ./$(DEPDIR)/tst-specialuse-exists.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_special_use_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_special_use_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_special_use.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+tags = \
+ tag-specialuse.c
+
+tests = \
+ tst-specialuse-exists.c
+
+libsieve_ext_special_use_la_SOURCES = \
+ $(tags) \
+ $(tests) \
+ ext-special-use-common.c \
+ ext-special-use.c
+
+headers = \
+ ext-special-use-common.h
+
+noinst_HEADERS = $(headers)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/special-use/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/special-use/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_special_use.la: $(libsieve_ext_special_use_la_OBJECTS) $(libsieve_ext_special_use_la_DEPENDENCIES) $(EXTRA_libsieve_ext_special_use_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_special_use_la_OBJECTS) $(libsieve_ext_special_use_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-special-use-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-special-use.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tag-specialuse.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-specialuse-exists.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ext-special-use-common.Plo
+ -rm -f ./$(DEPDIR)/ext-special-use.Plo
+ -rm -f ./$(DEPDIR)/tag-specialuse.Plo
+ -rm -f ./$(DEPDIR)/tst-specialuse-exists.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ext-special-use-common.Plo
+ -rm -f ./$(DEPDIR)/ext-special-use.Plo
+ -rm -f ./$(DEPDIR)/tag-specialuse.Plo
+ -rm -f ./$(DEPDIR)/tst-specialuse-exists.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/special-use/ext-special-use-common.c b/pigeonhole/src/lib-sieve/plugins/special-use/ext-special-use-common.c
new file mode 100644
index 0000000..fcaf1b5
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/special-use/ext-special-use-common.c
@@ -0,0 +1,31 @@
+/* Copyright (c) 2019 Pigeonhole authors, see the included COPYING file */
+
+#include "lib.h"
+#include "imap-arg.h"
+
+#include "ext-special-use-common.h"
+
+bool ext_special_use_flag_valid(const char *flag)
+{
+ const char *p = flag;
+
+ /* RFC 6154, Section 6:
+
+ use-attr = "\All" / "\Archive" / "\Drafts" / "\Flagged" /
+ "\Junk" / "\Sent" / "\Trash" / use-attr-ext
+ use-attr-ext = "\" atom
+ */
+
+ /* "\" */
+ if (*p != '\\')
+ return FALSE;
+ p++;
+
+ /* atom */
+ for (; *p != '\0'; p++) {
+ if (!IS_ATOM_CHAR(*p))
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/special-use/ext-special-use-common.h b/pigeonhole/src/lib-sieve/plugins/special-use/ext-special-use-common.h
new file mode 100644
index 0000000..61f23d0
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/special-use/ext-special-use-common.h
@@ -0,0 +1,43 @@
+#ifndef EXT_SPECIAL_USE_COMMON_H
+#define EXT_SPECIAL_USE_COMMON_H
+
+#include "sieve-common.h"
+
+/*
+ * Tagged arguments
+ */
+
+extern const struct sieve_argument_def specialuse_tag;
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def specialuse_exists_test;
+
+/*
+ * Operands
+ */
+
+extern const struct sieve_operand_def specialuse_operand;
+
+/*
+ * Operations
+ */
+
+extern const struct sieve_operation_def specialuse_exists_operation;
+
+/*
+ * Extension
+ */
+
+extern const struct sieve_extension_def special_use_extension;
+
+/*
+ * Flag checking
+ */
+
+bool ext_special_use_flag_valid(const char *flag);
+
+#endif /* EXT_SPECIAL_USE_COMMON_H */
+
diff --git a/pigeonhole/src/lib-sieve/plugins/special-use/ext-special-use.c b/pigeonhole/src/lib-sieve/plugins/special-use/ext-special-use.c
new file mode 100644
index 0000000..acbb13e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/special-use/ext-special-use.c
@@ -0,0 +1,57 @@
+/* Copyright (c) 2019 Pigeonhole authors, see the included COPYING file */
+
+/* Extension special-use
+ * ---------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 8579
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "sieve-common.h"
+
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-actions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-result.h"
+
+#include "ext-special-use-common.h"
+
+/*
+ * Extension
+ */
+
+static bool
+ext_special_use_validator_load(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr);
+
+const struct sieve_extension_def special_use_extension = {
+ .name = "special-use",
+ .validator_load = ext_special_use_validator_load,
+ SIEVE_EXT_DEFINE_OPERATION(specialuse_exists_operation),
+ SIEVE_EXT_DEFINE_OPERAND(specialuse_operand)
+};
+
+static bool
+ext_special_use_validator_load(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr)
+{
+ /* Register :specialuse tag with fileinto command and we don't care
+ whether this command is registered or even whether it will be
+ registered at all. The validator handles either situation gracefully.
+ */
+ sieve_validator_register_external_tag(
+ valdtr, "fileinto", ext, &specialuse_tag,
+ SIEVE_OPT_SIDE_EFFECT);
+
+ /* Register new test */
+ sieve_validator_register_command(valdtr, ext, &specialuse_exists_test);
+
+ return TRUE;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/special-use/tag-specialuse.c b/pigeonhole/src/lib-sieve/plugins/special-use/tag-specialuse.c
new file mode 100644
index 0000000..0f6d32a
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/special-use/tag-specialuse.c
@@ -0,0 +1,316 @@
+/* Copyright (c) 2019 Pigeonhole authors, see the included COPYING file */
+
+#include "lib.h"
+#include "str-sanitize.h"
+#include "mail-storage.h"
+#include "mail-namespace.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-actions.h"
+#include "sieve-code.h"
+#include "sieve-actions.h"
+#include "sieve-result.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+#include "ext-special-use-common.h"
+
+/*
+ * Flags tagged argument
+ */
+
+static bool
+tag_specialuse_validate(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool
+tag_specialuse_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_argument *arg,
+ struct sieve_command *cmd);
+
+const struct sieve_argument_def specialuse_tag = {
+ .identifier = "specialuse",
+ .validate = tag_specialuse_validate,
+ .generate = tag_specialuse_generate
+};
+
+/*
+ * Side effect
+ */
+
+static bool
+seff_specialuse_dump_context(const struct sieve_side_effect *seffect,
+ const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+seff_specialuse_read_context(const struct sieve_side_effect *seffect,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address, void **context);
+
+static int
+seff_specialuse_merge(const struct sieve_runtime_env *renv,
+ const struct sieve_action *action,
+ const struct sieve_side_effect *old_seffect,
+ const struct sieve_side_effect *new_seffect,
+ void **old_context);
+
+static void
+seff_specialuse_print(const struct sieve_side_effect *seffect,
+ const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv, bool *keep);
+
+static int
+seff_specialuse_pre_execute(const struct sieve_side_effect *seffect,
+ const struct sieve_action_exec_env *aenv,
+ void *tr_context, void **se_tr_context ATTR_UNUSED);
+
+const struct sieve_side_effect_def specialuse_side_effect = {
+ SIEVE_OBJECT("specialuse", &specialuse_operand, 0),
+ .precedence = 200,
+ .to_action = &act_store,
+ .dump_context = seff_specialuse_dump_context,
+ .read_context = seff_specialuse_read_context,
+ .merge = seff_specialuse_merge,
+ .print = seff_specialuse_print,
+ .pre_execute = seff_specialuse_pre_execute
+};
+
+/*
+ * Operand
+ */
+
+static const struct sieve_extension_objects ext_side_effects =
+ SIEVE_EXT_DEFINE_SIDE_EFFECT(specialuse_side_effect);
+
+const struct sieve_operand_def specialuse_operand = {
+ .name = "specialuse operand",
+ .ext_def = &special_use_extension,
+ .class = &sieve_side_effect_operand_class,
+ .interface = &ext_side_effects
+};
+
+/*
+ * Tag validation
+ */
+
+static bool
+tag_specialuse_validate(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_argument_next(*arg);
+
+ /* Check syntax:
+ * :specialuse <special-use-flag: string>
+ */
+ if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0,
+ SAAT_STRING, FALSE))
+ return FALSE;
+ if (sieve_argument_is_string_literal(*arg)) {
+ const char *use_flag = sieve_ast_argument_strc(*arg);
+
+ if (!ext_special_use_flag_valid(use_flag)) {
+ sieve_argument_validate_error(
+ valdtr, *arg, "specialuse tag: "
+ "invalid special-use flag `%s' specified",
+ str_sanitize(use_flag, 64));
+ return FALSE;
+ }
+ }
+
+ tag->parameters = *arg;
+
+ /* Detach parameter */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+tag_specialuse_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_argument *arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *param;
+
+ if (sieve_ast_argument_type(arg) != SAAT_TAG)
+ return FALSE;
+
+ sieve_opr_side_effect_emit(cgenv->sblock, arg->argument->ext,
+ &specialuse_side_effect);
+
+ /* Explicit :specialuse tag */
+ param = arg->parameters;
+
+ /* Call the generation function for the argument */
+ if (param->argument != NULL && param->argument->def != NULL &&
+ param->argument->def->generate != NULL &&
+ !param->argument->def->generate(cgenv, param, cmd))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Side effect implementation
+ */
+
+/* Context data */
+
+struct seff_specialuse_context {
+ const char *special_use_flag;
+};
+
+/* Context coding */
+
+static bool
+seff_specialuse_dump_context(
+ const struct sieve_side_effect *seffect ATTR_UNUSED,
+ const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ return sieve_opr_stringlist_dump(denv, address, "specialuse");
+}
+
+static int
+seff_specialuse_read_context(
+ const struct sieve_side_effect *seffect ATTR_UNUSED,
+ const struct sieve_runtime_env *renv, sieve_size_t *address,
+ void **se_context)
+{
+ pool_t pool = sieve_result_pool(renv->result);
+ struct seff_specialuse_context *ctx;
+ string_t *special_use_flag;
+ const char *use_flag;
+ int ret;
+
+ if ((ret = sieve_opr_string_read(renv, address, "specialuse",
+ &special_use_flag)) <= 0)
+ return ret;
+
+ use_flag = str_c(special_use_flag);
+ if (!ext_special_use_flag_valid(use_flag)) {
+ sieve_runtime_error(
+ renv, NULL, "specialuse tag: "
+ "invalid special-use flag `%s' specified",
+ str_sanitize(use_flag, 64));
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ ctx = p_new(pool, struct seff_specialuse_context, 1);
+ ctx->special_use_flag = p_strdup(pool, use_flag);
+
+ *se_context = (void *) ctx;
+
+ return SIEVE_EXEC_OK;
+}
+
+/* Result verification */
+
+static int
+seff_specialuse_merge(const struct sieve_runtime_env *renv ATTR_UNUSED,
+ const struct sieve_action *action ATTR_UNUSED,
+ const struct sieve_side_effect *old_seffect ATTR_UNUSED,
+ const struct sieve_side_effect *new_seffect,
+ void **old_context)
+{
+ if (new_seffect != NULL)
+ *old_context = new_seffect->context;
+
+ return 1;
+}
+
+/* Result printing */
+
+static void
+seff_specialuse_print(const struct sieve_side_effect *seffect,
+ const struct sieve_action *action ATTR_UNUSED,
+ const struct sieve_result_print_env *rpenv,
+ bool *keep ATTR_UNUSED)
+{
+ struct seff_specialuse_context *ctx =
+ (struct seff_specialuse_context *)seffect->context;
+
+ sieve_result_seffect_printf(
+ rpenv,
+ "use mailbox with special-use flag `%s' instead if accessible",
+ ctx->special_use_flag);
+}
+
+/* Result execution */
+
+static int
+seff_specialuse_pre_execute(const struct sieve_side_effect *seffect,
+ const struct sieve_action_exec_env *aenv,
+ void *tr_context, void **se_tr_context ATTR_UNUSED)
+{
+ struct seff_specialuse_context *ctx =
+ (struct seff_specialuse_context *)seffect->context;
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct act_store_transaction *trans =
+ (struct act_store_transaction *)tr_context;
+ struct mailbox *box;
+
+ if (trans->box == NULL || trans->disabled)
+ return SIEVE_EXEC_OK;
+
+ /* Check whether something already failed */
+ switch (trans->error_code) {
+ case MAIL_ERROR_NONE:
+ break;
+ case MAIL_ERROR_TEMP:
+ return SIEVE_EXEC_TEMP_FAILURE;
+ default:
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ trans->error = NULL;
+ trans->error_code = MAIL_ERROR_NONE;
+
+ box = mailbox_alloc_for_user(eenv->scriptenv->user,
+ ctx->special_use_flag,
+ (MAILBOX_FLAG_POST_SESSION |
+ MAILBOX_FLAG_SPECIAL_USE));
+
+ /* We still override the allocate default mailbox with ours below even
+ when the default and special-use mailbox are identical. Choosing
+ either one is (currently) equal and setting trans->mailbox_identifier
+ for SPECIAL-USE needs to be done either way, so we use the same code
+ path. */
+
+ /* Try to open the mailbox */
+ eenv->exec_status->last_storage = mailbox_get_storage(box);
+ if (mailbox_open(box) == 0) {
+ pool_t pool = sieve_result_pool(aenv->result);
+
+ /* Success */
+ mailbox_free(&trans->box);
+ trans->box = box;
+ trans->mailbox_identifier = p_strdup_printf(pool,
+ "[SPECIAL-USE %s]", ctx->special_use_flag);
+
+ } else {
+ /* Failure */
+ if (mailbox_get_last_mail_error(box) == MAIL_ERROR_NOTFOUND) {
+ /* Not found; revert to default */
+ mailbox_free(&box);
+ } else {
+ /* Total failure */
+ mailbox_free(&trans->box);
+ trans->box = box;
+ sieve_act_store_get_storage_error(aenv, trans);
+ return (trans->error_code == MAIL_ERROR_TEMP ?
+ SIEVE_EXEC_TEMP_FAILURE : SIEVE_EXEC_FAILURE);
+ }
+ }
+
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/special-use/tst-specialuse-exists.c b/pigeonhole/src/lib-sieve/plugins/special-use/tst-specialuse-exists.c
new file mode 100644
index 0000000..a1aa878
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/special-use/tst-specialuse-exists.c
@@ -0,0 +1,525 @@
+/* Copyright (c) 2019 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+#include "mail-storage.h"
+#include "mail-namespace.h"
+
+#include "sieve-common.h"
+#include "sieve-actions.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-special-use-common.h"
+
+/*
+ * specialuse_exists command
+ *
+ * Syntax:
+ * specialuse_exists [<mailbox: string>]
+ * <special-use-flags: string-list>
+ */
+
+static bool
+tst_specialuse_exists_validate(struct sieve_validator *valdtr,
+ struct sieve_command *tst);
+static bool
+tst_specialuse_exists_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+const struct sieve_command_def specialuse_exists_test = {
+ .identifier = "specialuse_exists",
+ .type = SCT_TEST,
+ .positional_args = -1, /* We check positional arguments ourselves */
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = tst_specialuse_exists_validate,
+ .generate = tst_specialuse_exists_generate,
+};
+
+/*
+ * Mailboxexists operation
+ */
+
+static bool
+tst_specialuse_exists_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+tst_specialuse_exists_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def specialuse_exists_operation = {
+ .mnemonic = "SPECIALUSE_EXISTS",
+ .ext_def = &special_use_extension,
+ .dump = tst_specialuse_exists_operation_dump,
+ .execute = tst_specialuse_exists_operation_execute,
+};
+
+/*
+ * Test validation
+ */
+
+struct _validate_context {
+ struct sieve_validator *valdtr;
+ struct sieve_command *tst;
+};
+
+static int
+tst_specialuse_exists_flag_validate(void *context,
+ struct sieve_ast_argument *arg)
+{
+ struct _validate_context *valctx = (struct _validate_context *)context;
+
+ if (sieve_argument_is_string_literal(arg)) {
+ const char *flag = sieve_ast_argument_strc(arg);
+
+ if (!ext_special_use_flag_valid(flag)) {
+ sieve_argument_validate_error(
+ valctx->valdtr, arg, "%s test: "
+ "invalid special-use flag `%s' specified",
+ sieve_command_identifier(valctx->tst),
+ str_sanitize(flag, 64));
+ }
+ }
+
+ return 1;
+}
+
+static bool
+tst_specialuse_exists_validate(struct sieve_validator *valdtr,
+ struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+ struct sieve_ast_argument *arg2;
+ struct sieve_ast_argument *aarg;
+ struct _validate_context valctx;
+
+ if (arg == NULL) {
+ sieve_command_validate_error(
+ valdtr, tst, "the %s %s expects at least one argument, "
+ "but none was found",
+ sieve_command_identifier(tst),
+ sieve_command_type_name(tst));
+ return FALSE;
+ }
+
+ if (sieve_ast_argument_type(arg) != SAAT_STRING &&
+ sieve_ast_argument_type(arg) != SAAT_STRING_LIST) {
+ sieve_argument_validate_error(
+ valdtr, arg,
+ "the %s %s expects either a string (mailbox) or "
+ "a string-list (special-use flags) as first argument, "
+ "but %s was found",
+ sieve_command_identifier(tst),
+ sieve_command_type_name(tst),
+ sieve_ast_argument_name(arg));
+ return FALSE;
+ }
+
+ arg2 = sieve_ast_argument_next(arg);
+ if (arg2 != NULL) {
+ /* First, check syntax sanity */
+ if (sieve_ast_argument_type(arg) != SAAT_STRING) {
+ sieve_argument_validate_error(
+ valdtr, arg,
+ "if a second argument is specified for the %s %s, "
+ "the first must be a string (mailbox), "
+ "but %s was found",
+ sieve_command_identifier(tst),
+ sieve_command_type_name(tst),
+ sieve_ast_argument_name(arg));
+ return FALSE;
+ }
+ if (!sieve_validator_argument_activate(valdtr, tst, arg, FALSE))
+ return FALSE;
+
+ /* Check name validity when mailbox argument is not a variable */
+ if (sieve_argument_is_string_literal(arg)) {
+ const char *mailbox = sieve_ast_argument_strc(arg);
+ const char *error;
+
+ if (!sieve_mailbox_check_name(mailbox, &error)) {
+ sieve_argument_validate_warning(
+ valdtr, arg, "%s test: "
+ "invalid mailbox name `%s' specified: %s",
+ sieve_command_identifier(tst),
+ str_sanitize(mailbox, 256), error);
+ }
+ }
+
+ if (sieve_ast_argument_type(arg2) != SAAT_STRING &&
+ sieve_ast_argument_type(arg2) != SAAT_STRING_LIST) {
+ sieve_argument_validate_error(
+ valdtr, arg2,
+ "the %s %s expects a string list (special-use flags) as "
+ "second argument when two arguments are specified, "
+ "but %s was found",
+ sieve_command_identifier(tst),
+ sieve_command_type_name(tst),
+ sieve_ast_argument_name(arg2));
+ return FALSE;
+ }
+ } else
+ arg2 = arg;
+
+ if (!sieve_validator_argument_activate(valdtr, tst, arg2, FALSE))
+ return FALSE;
+
+ aarg = arg2;
+ memset(&valctx, 0, sizeof(valctx));
+ valctx.valdtr = valdtr;
+ valctx.tst = tst;
+
+ return (sieve_ast_stringlist_map(
+ &aarg, (void*)&valctx,
+ tst_specialuse_exists_flag_validate) >= 0);
+}
+
+/*
+ * Test generation
+ */
+
+static bool
+tst_specialuse_exists_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+ struct sieve_ast_argument *arg2;
+
+ sieve_operation_emit(cgenv->sblock,
+ tst->ext, &specialuse_exists_operation);
+
+ /* Generate arguments */
+ arg2 = sieve_ast_argument_next(arg);
+ if (arg2 != NULL) {
+ if (!sieve_generate_argument(cgenv, arg, tst))
+ return FALSE;
+ } else {
+ sieve_opr_omitted_emit(cgenv->sblock);
+ arg2 = arg;
+ }
+ return sieve_generate_argument(cgenv, arg2, tst);
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+tst_specialuse_exists_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ struct sieve_operand oprnd;
+
+ sieve_code_dumpf(denv, "SPECIALUSE_EXISTS");
+ sieve_code_descend(denv);
+
+ sieve_code_mark(denv);
+ if (!sieve_operand_read(denv->sblock, address, NULL, &oprnd)) {
+ sieve_code_dumpf(denv, "ERROR: INVALID OPERAND");
+ return FALSE;
+ }
+
+ if (!sieve_operand_is_omitted(&oprnd)) {
+ return (sieve_opr_string_dump_data(denv, &oprnd,
+ address, "mailbox") &&
+ sieve_opr_stringlist_dump(denv, address,
+ "special-use-flags"));
+ }
+
+ return sieve_opr_stringlist_dump(denv, address, "special-use-flags");
+}
+
+/*
+ * Code execution
+ */
+
+static int
+tst_specialuse_find_mailbox(const struct sieve_runtime_env *renv,
+ const char *mailbox, struct mailbox **box_r)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ struct mail_user *user = eenv->scriptenv->user;
+ struct mailbox *box;
+ bool trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING);
+ enum mail_error error_code;
+ const char *error;
+
+ *box_r = NULL;
+
+ if (user == NULL)
+ return 0;
+
+ /* Open the box */
+ box = mailbox_alloc_for_user(user, mailbox, MAILBOX_FLAG_POST_SESSION);
+ if (mailbox_open(box) < 0) {
+ error = mailbox_get_last_internal_error(box, &error_code);
+
+ if (trace) {
+ sieve_runtime_trace(
+ renv, 0, "mailbox `%s' cannot be opened: %s",
+ str_sanitize(mailbox, 256), error);
+ }
+
+ mailbox_free(&box);
+
+ if (error_code == MAIL_ERROR_TEMP) {
+ sieve_runtime_error(
+ renv, NULL, "specialuse_exists test: "
+ "failed to open mailbox `%s': %s",
+ str_sanitize(mailbox, 256), error);
+ return -1;
+ }
+ return 0;
+ }
+
+ /* Also fail when it is readonly */
+ if (mailbox_is_readonly(box)) {
+ if (trace) {
+ sieve_runtime_trace(
+ renv, 0, "mailbox `%s' is read-only",
+ str_sanitize(mailbox, 256));
+ }
+
+ mailbox_free(&box);
+ return 0;
+ }
+
+ *box_r = box;
+ return 1;
+}
+
+static int
+tst_specialuse_find_specialuse(const struct sieve_runtime_env *renv,
+ const char *special_use)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ struct mail_user *user = eenv->scriptenv->user;
+ struct mailbox *box;
+ bool trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING);
+ enum mail_error error_code;
+ const char *error;
+
+ if (user == NULL)
+ return 0;
+
+ /* Open the box */
+ box = mailbox_alloc_for_user(user, special_use,
+ (MAILBOX_FLAG_POST_SESSION |
+ MAILBOX_FLAG_SPECIAL_USE));
+ if (mailbox_open(box) < 0) {
+ error = mailbox_get_last_internal_error(box, &error_code);
+
+ if (trace) {
+ sieve_runtime_trace(
+ renv, 0, "mailbox with special-use flag `%s' "
+ "cannot be opened: %s",
+ str_sanitize(special_use, 64), error);
+ }
+
+ mailbox_free(&box);
+
+ if (error_code == MAIL_ERROR_TEMP) {
+ sieve_runtime_error(
+ renv, NULL, "specialuse_exists test: "
+ "failed to open mailbox with special-use flag`%s': %s",
+ str_sanitize(special_use, 64), error);
+ return -1;
+ }
+ return 0;
+ }
+
+ /* Also fail when it is readonly */
+ if (mailbox_is_readonly(box)) {
+ if (trace) {
+ sieve_runtime_trace(
+ renv, 0,
+ "mailbox with special-use flag `%s' is read-only",
+ str_sanitize(special_use, 64));
+ }
+
+ mailbox_free(&box);
+ return 0;
+ }
+
+ mailbox_free(&box);
+ return 1;
+}
+
+static int
+tst_specialuse_exists_check_flag(const struct sieve_runtime_env *renv,
+ struct mailbox *box, const char *use_flag,
+ bool trace, bool *all_exist_r)
+{
+ int ret;
+
+ if (!ext_special_use_flag_valid(use_flag)) {
+ sieve_runtime_error(
+ renv, NULL, "specialuse_exists test: "
+ "invalid special-use flag `%s' specified",
+ str_sanitize(use_flag, 64));
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ if (box != NULL) {
+ /* Mailbox has this SPECIAL-USE flag? */
+ if (!mailbox_has_special_use(box, use_flag)) {
+ *all_exist_r = FALSE;
+ return SIEVE_EXEC_OK;
+ }
+ } else {
+ /* Is there mailbox with this SPECIAL-USE flag? */
+ ret = tst_specialuse_find_specialuse(renv, use_flag);
+ if (ret < 0)
+ return SIEVE_EXEC_TEMP_FAILURE;
+ if (ret == 0) {
+ *all_exist_r = FALSE;
+ return SIEVE_EXEC_OK;
+ }
+ }
+
+ if (trace) {
+ sieve_runtime_trace(
+ renv, 0, "special-use flag `%s' exists",
+ str_sanitize(use_flag, 80));
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+static int
+tst_specialuse_exists_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ struct sieve_operand oprnd;
+ struct sieve_stringlist *special_use_flags;
+ string_t *mailbox, *special_use_flag;
+ struct mailbox *box = NULL;
+ const char *error;
+ bool trace = FALSE, all_exist = TRUE;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Read bare operand (two types possible) */
+ ret = sieve_operand_runtime_read(renv, address, NULL, &oprnd);
+ if (ret <= 0)
+ return ret;
+
+ /* Mailbox operand (optional) */
+ mailbox = NULL;
+ if (!sieve_operand_is_omitted(&oprnd)) {
+ /* Read the mailbox operand */
+ ret = sieve_opr_string_read_data(renv, &oprnd, address,
+ "mailbox", &mailbox);
+ if (ret <= 0)
+ return ret;
+
+ /* Read flag list */
+ ret = sieve_opr_stringlist_read(renv, address,
+ "special-use-flags",
+ &special_use_flags);
+ if (ret <= 0)
+ return ret;
+
+ /* Flag-list operand */
+ } else {
+ /* Read flag list */
+ ret = sieve_opr_stringlist_read(renv, address,
+ "special-use-flags",
+ &special_use_flags);
+ if (ret <= 0)
+ return ret;
+ }
+
+ /*
+ * Perform operation
+ */
+
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_TESTS)) {
+ sieve_runtime_trace(renv, 0, "specialuse_exists test");
+ sieve_runtime_trace_descend(renv);
+
+ trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING);
+ }
+
+ if (mailbox != NULL) {
+ if (!sieve_mailbox_check_name(str_c(mailbox), &error)) {
+ sieve_runtime_warning(
+ renv, NULL, "specialuse_exists test: "
+ "invalid mailbox name `%s' specified: %s",
+ str_sanitize(str_c(mailbox), 256), error);
+ sieve_interpreter_set_test_result(renv->interp, FALSE);
+ return SIEVE_EXEC_OK;
+ }
+
+ if (tst_specialuse_find_mailbox(renv, str_c(mailbox), &box) < 0)
+ return SIEVE_EXEC_TEMP_FAILURE;
+ }
+
+ if (box == NULL && mailbox != NULL) {
+ sieve_runtime_trace(
+ renv, 0, "mailbox `%s' is not accessible",
+ str_sanitize(str_c(mailbox), 80));
+ sieve_interpreter_set_test_result(renv->interp, FALSE);
+ return SIEVE_EXEC_OK;
+ }
+
+ if (mailbox != NULL) {
+ sieve_runtime_trace(
+ renv, 0, "mailbox `%s' is accessible",
+ str_sanitize(str_c(mailbox), 80));
+ }
+
+ ret = 0;
+ special_use_flag = NULL;
+ while (all_exist &&
+ (ret = sieve_stringlist_next_item(
+ special_use_flags, &special_use_flag)) > 0) {
+ const char *use_flag = str_c(special_use_flag);
+
+ ret = tst_specialuse_exists_check_flag(
+ renv, box, use_flag, trace, &all_exist);
+ if (ret <= 0) {
+ if (box != NULL) {
+ /* Close mailbox */
+ mailbox_free(&box);
+ }
+ return ret;
+ }
+ }
+
+ if (box != NULL) {
+ /* Close mailbox */
+ mailbox_free(&box);
+ }
+
+ if (ret < 0) {
+ sieve_runtime_trace_error(
+ renv, "invalid special-use flag item");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if (trace) {
+ if (all_exist) {
+ sieve_runtime_trace(
+ renv, 0, "all special-use flags are set");
+ } else {
+ sieve_runtime_trace(
+ renv, 0, "some special-use are not set");
+ }
+ }
+
+ sieve_interpreter_set_test_result(renv->interp, all_exist);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/subaddress/Makefile.am b/pigeonhole/src/lib-sieve/plugins/subaddress/Makefile.am
new file mode 100644
index 0000000..2bab53f
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/subaddress/Makefile.am
@@ -0,0 +1,8 @@
+noinst_LTLIBRARIES = libsieve_ext_subaddress.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+libsieve_ext_subaddress_la_SOURCES = \
+ ext-subaddress.c
diff --git a/pigeonhole/src/lib-sieve/plugins/subaddress/Makefile.in b/pigeonhole/src/lib-sieve/plugins/subaddress/Makefile.in
new file mode 100644
index 0000000..c5b6b7c
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/subaddress/Makefile.in
@@ -0,0 +1,673 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/subaddress
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_subaddress_la_LIBADD =
+am_libsieve_ext_subaddress_la_OBJECTS = ext-subaddress.lo
+libsieve_ext_subaddress_la_OBJECTS = \
+ $(am_libsieve_ext_subaddress_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ext-subaddress.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_subaddress_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_subaddress_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_subaddress.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+libsieve_ext_subaddress_la_SOURCES = \
+ ext-subaddress.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/subaddress/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/subaddress/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_subaddress.la: $(libsieve_ext_subaddress_la_OBJECTS) $(libsieve_ext_subaddress_la_DEPENDENCIES) $(EXTRA_libsieve_ext_subaddress_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_subaddress_la_OBJECTS) $(libsieve_ext_subaddress_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-subaddress.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ext-subaddress.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ext-subaddress.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/subaddress/ext-subaddress.c b/pigeonhole/src/lib-sieve/plugins/subaddress/ext-subaddress.c
new file mode 100644
index 0000000..abaa7ae
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/subaddress/ext-subaddress.c
@@ -0,0 +1,191 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension subaddress
+ * --------------------
+ *
+ * Author: Stephan Bosch
+ * Specification: RFC 3598
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "sieve-common.h"
+
+#include "sieve-settings.h"
+#include "sieve-code.h"
+#include "sieve-address.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-address-parts.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+#include <string.h>
+
+/*
+ * Configuration
+ */
+
+#define SUBADDRESS_DEFAULT_DELIM "+"
+
+struct ext_subaddress_config {
+ char *delimiter;
+};
+
+/*
+ * Forward declarations
+ */
+
+const struct sieve_address_part_def user_address_part;
+const struct sieve_address_part_def detail_address_part;
+
+static struct sieve_operand_def subaddress_operand;
+
+/*
+ * Extension
+ */
+
+static bool ext_subaddress_load
+ (const struct sieve_extension *ext, void **context);
+static void ext_subaddress_unload
+ (const struct sieve_extension *ext);
+static bool ext_subaddress_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *validator);
+
+const struct sieve_extension_def subaddress_extension = {
+ .name = "subaddress",
+ .load = ext_subaddress_load,
+ .unload = ext_subaddress_unload,
+ .validator_load = ext_subaddress_validator_load,
+ SIEVE_EXT_DEFINE_OPERAND(subaddress_operand)
+};
+
+static bool ext_subaddress_load
+(const struct sieve_extension *ext, void **context)
+{
+ struct ext_subaddress_config *config;
+ const char *delim;
+
+ if ( *context != NULL ) {
+ ext_subaddress_unload(ext);
+ }
+
+ delim = sieve_setting_get(ext->svinst, "recipient_delimiter");
+
+ if ( delim == NULL )
+ delim = SUBADDRESS_DEFAULT_DELIM;
+
+ config = i_new(struct ext_subaddress_config, 1);
+ config->delimiter = i_strdup(delim);
+
+ *context = (void *) config;
+
+ return TRUE;
+}
+
+static void ext_subaddress_unload
+(const struct sieve_extension *ext)
+{
+ struct ext_subaddress_config *config =
+ (struct ext_subaddress_config *) ext->context;
+
+ i_free(config->delimiter);
+ i_free(config);
+}
+
+static bool ext_subaddress_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *validator)
+{
+ sieve_address_part_register(validator, ext, &user_address_part);
+ sieve_address_part_register(validator, ext, &detail_address_part);
+
+ return TRUE;
+}
+
+/*
+ * Address parts
+ */
+
+enum ext_subaddress_address_part {
+ SUBADDRESS_USER,
+ SUBADDRESS_DETAIL
+};
+
+/* Forward declarations */
+
+static const char *subaddress_user_extract_from
+ (const struct sieve_address_part *addrp, const struct smtp_address *address);
+static const char *subaddress_detail_extract_from
+ (const struct sieve_address_part *addrp, const struct smtp_address *address);
+
+/* Address part objects */
+
+const struct sieve_address_part_def user_address_part = {
+ SIEVE_OBJECT("user",
+ &subaddress_operand, SUBADDRESS_USER),
+ subaddress_user_extract_from
+};
+
+const struct sieve_address_part_def detail_address_part = {
+ SIEVE_OBJECT("detail",
+ &subaddress_operand, SUBADDRESS_DETAIL),
+ .extract_from = subaddress_detail_extract_from
+};
+
+/* Address part implementation */
+
+static const char *subaddress_user_extract_from
+(const struct sieve_address_part *addrp, const struct smtp_address *address)
+{
+ struct ext_subaddress_config *config =
+ (struct ext_subaddress_config *) addrp->object.ext->context;
+ const char *delim;
+ size_t idx;
+
+ idx = strcspn(address->localpart, config->delimiter);
+ delim = address->localpart[idx] != '\0' ? address->localpart + idx : NULL;
+
+ if ( delim == NULL ) return address->localpart;
+
+ return t_strdup_until(address->localpart, delim);
+}
+
+static const char *subaddress_detail_extract_from
+(const struct sieve_address_part *addrp, const struct smtp_address *address)
+{
+ struct ext_subaddress_config *config =
+ (struct ext_subaddress_config *) addrp->object.ext->context;
+ const char *delim;
+ size_t idx;
+
+ idx = strcspn(address->localpart, config->delimiter);
+ delim = address->localpart[idx] != '\0' ? address->localpart + idx + 1: NULL;
+
+ /* Just to be sure */
+ if ( delim == NULL ||
+ delim > (address->localpart + strlen(address->localpart)) )
+ return NULL;
+ return delim;
+}
+
+/*
+ * Operand
+ */
+
+const struct sieve_address_part_def *ext_subaddress_parts[] = {
+ &user_address_part, &detail_address_part
+};
+
+static const struct sieve_extension_objects ext_address_parts =
+ SIEVE_EXT_DEFINE_ADDRESS_PARTS(ext_subaddress_parts);
+
+static struct sieve_operand_def subaddress_operand = {
+ .name = "address-part",
+ .ext_def = &subaddress_extension,
+ .class = &sieve_address_part_operand_class,
+ .interface = &ext_address_parts
+};
+
diff --git a/pigeonhole/src/lib-sieve/plugins/vacation/Makefile.am b/pigeonhole/src/lib-sieve/plugins/vacation/Makefile.am
new file mode 100644
index 0000000..09df27b
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vacation/Makefile.am
@@ -0,0 +1,19 @@
+noinst_LTLIBRARIES = libsieve_ext_vacation.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../../util \
+ $(LIBDOVECOT_INCLUDE)
+
+cmds = \
+ cmd-vacation.c
+
+libsieve_ext_vacation_la_SOURCES = \
+ $(cmds) \
+ ext-vacation-common.c \
+ ext-vacation.c \
+ ext-vacation-seconds.c
+
+noinst_HEADERS = \
+ ext-vacation-common.h
+
diff --git a/pigeonhole/src/lib-sieve/plugins/vacation/Makefile.in b/pigeonhole/src/lib-sieve/plugins/vacation/Makefile.in
new file mode 100644
index 0000000..f18806a
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vacation/Makefile.in
@@ -0,0 +1,700 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/vacation
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_vacation_la_LIBADD =
+am__objects_1 = cmd-vacation.lo
+am_libsieve_ext_vacation_la_OBJECTS = $(am__objects_1) \
+ ext-vacation-common.lo ext-vacation.lo ext-vacation-seconds.lo
+libsieve_ext_vacation_la_OBJECTS = \
+ $(am_libsieve_ext_vacation_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cmd-vacation.Plo \
+ ./$(DEPDIR)/ext-vacation-common.Plo \
+ ./$(DEPDIR)/ext-vacation-seconds.Plo \
+ ./$(DEPDIR)/ext-vacation.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_vacation_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_vacation_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_vacation.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../../util \
+ $(LIBDOVECOT_INCLUDE)
+
+cmds = \
+ cmd-vacation.c
+
+libsieve_ext_vacation_la_SOURCES = \
+ $(cmds) \
+ ext-vacation-common.c \
+ ext-vacation.c \
+ ext-vacation-seconds.c
+
+noinst_HEADERS = \
+ ext-vacation-common.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/vacation/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/vacation/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_vacation.la: $(libsieve_ext_vacation_la_OBJECTS) $(libsieve_ext_vacation_la_DEPENDENCIES) $(EXTRA_libsieve_ext_vacation_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_vacation_la_OBJECTS) $(libsieve_ext_vacation_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-vacation.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-vacation-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-vacation-seconds.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-vacation.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/cmd-vacation.Plo
+ -rm -f ./$(DEPDIR)/ext-vacation-common.Plo
+ -rm -f ./$(DEPDIR)/ext-vacation-seconds.Plo
+ -rm -f ./$(DEPDIR)/ext-vacation.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/cmd-vacation.Plo
+ -rm -f ./$(DEPDIR)/ext-vacation-common.Plo
+ -rm -f ./$(DEPDIR)/ext-vacation-seconds.Plo
+ -rm -f ./$(DEPDIR)/ext-vacation.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/vacation/cmd-vacation.c b/pigeonhole/src/lib-sieve/plugins/vacation/cmd-vacation.c
new file mode 100644
index 0000000..ddc14be
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vacation/cmd-vacation.c
@@ -0,0 +1,1578 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "strfuncs.h"
+#include "md5.h"
+#include "hostpid.h"
+#include "str-sanitize.h"
+#include "ostream.h"
+#include "message-address.h"
+#include "message-date.h"
+#include "var-expand.h"
+#include "ioloop.h"
+#include "mail-storage.h"
+
+#include "rfc2822.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-address.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-result.h"
+#include "sieve-message.h"
+#include "sieve-smtp.h"
+
+#include "ext-vacation-common.h"
+
+#include <stdio.h>
+
+/*
+ * Forward declarations
+ */
+
+static const struct sieve_argument_def vacation_days_tag;
+static const struct sieve_argument_def vacation_subject_tag;
+static const struct sieve_argument_def vacation_from_tag;
+static const struct sieve_argument_def vacation_addresses_tag;
+static const struct sieve_argument_def vacation_mime_tag;
+static const struct sieve_argument_def vacation_handle_tag;
+
+/*
+ * Vacation command
+ *
+ * Syntax:
+ * vacation [":days" number] [":subject" string]
+ * [":from" string] [":addresses" string-list]
+ * [":mime"] [":handle" string] <reason: string>
+ */
+
+static bool
+cmd_vacation_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool
+cmd_vacation_pre_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd);
+static bool
+cmd_vacation_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd);
+static bool
+cmd_vacation_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd);
+
+const struct sieve_command_def vacation_command = {
+ .identifier = "vacation",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = cmd_vacation_registered,
+ .pre_validate = cmd_vacation_pre_validate,
+ .validate = cmd_vacation_validate,
+ .generate = cmd_vacation_generate,
+};
+
+/*
+ * Vacation command tags
+ */
+
+/* Forward declarations */
+
+static bool
+cmd_vacation_validate_number_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool
+cmd_vacation_validate_string_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool
+cmd_vacation_validate_stringlist_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool
+cmd_vacation_validate_mime_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+/* Argument objects */
+
+static const struct sieve_argument_def vacation_days_tag = {
+ .identifier = "days",
+ .validate = cmd_vacation_validate_number_tag
+};
+
+static const struct sieve_argument_def vacation_seconds_tag = {
+ .identifier = "seconds",
+ .validate = cmd_vacation_validate_number_tag
+};
+
+static const struct sieve_argument_def vacation_subject_tag = {
+ .identifier = "subject",
+ .validate = cmd_vacation_validate_string_tag
+};
+
+static const struct sieve_argument_def vacation_from_tag = {
+ .identifier = "from",
+ .validate = cmd_vacation_validate_string_tag
+};
+
+static const struct sieve_argument_def vacation_addresses_tag = {
+ .identifier = "addresses",
+ .validate = cmd_vacation_validate_stringlist_tag
+};
+
+static const struct sieve_argument_def vacation_mime_tag = {
+ .identifier = "mime",
+ .validate = cmd_vacation_validate_mime_tag
+};
+
+static const struct sieve_argument_def vacation_handle_tag = {
+ .identifier = "handle",
+ .validate = cmd_vacation_validate_string_tag
+};
+
+/* Codes for optional arguments */
+
+enum cmd_vacation_optional {
+ OPT_END,
+ OPT_SECONDS,
+ OPT_SUBJECT,
+ OPT_FROM,
+ OPT_ADDRESSES,
+ OPT_MIME
+};
+
+/*
+ * Vacation operation
+ */
+
+static bool
+ext_vacation_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+ext_vacation_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def vacation_operation = {
+ .mnemonic = "VACATION",
+ .ext_def = &vacation_extension,
+ .dump = ext_vacation_operation_dump,
+ .execute = ext_vacation_operation_execute
+};
+
+/*
+ * Vacation action
+ */
+
+/* Forward declarations */
+
+static int
+act_vacation_check_duplicate(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other);
+int act_vacation_check_conflict(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other);
+static void
+act_vacation_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv, bool *keep);
+static int
+act_vacation_commit(const struct sieve_action_exec_env *aenv, void *tr_context);
+
+/* Action object */
+
+const struct sieve_action_def act_vacation = {
+ .name = "vacation",
+ .flags = SIEVE_ACTFLAG_SENDS_RESPONSE,
+ .check_duplicate = act_vacation_check_duplicate,
+ .check_conflict = act_vacation_check_conflict,
+ .print = act_vacation_print,
+ .commit = act_vacation_commit
+};
+
+/* Action context information */
+
+struct act_vacation_context {
+ const char *reason;
+
+ sieve_number_t seconds;
+ const char *subject;
+ const char *handle;
+ bool mime;
+ const char *from;
+ const struct smtp_address *from_address;
+ const struct smtp_address *const *addresses;
+};
+
+/*
+ * Command validation context
+ */
+
+struct cmd_vacation_context_data {
+ string_t *from;
+ string_t *subject;
+
+ bool mime;
+
+ struct sieve_ast_argument *handle_arg;
+};
+
+/*
+ * Tag validation
+ */
+
+static bool
+cmd_vacation_validate_number_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ const struct sieve_extension *ext = sieve_argument_ext(*arg);
+ const struct ext_vacation_config *config =
+ (const struct ext_vacation_config *)ext->context;
+ struct sieve_ast_argument *tag = *arg;
+ sieve_number_t period, seconds;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ /* Check syntax:
+ * :days number
+ */
+ if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0,
+ SAAT_NUMBER, FALSE))
+ return FALSE;
+
+ period = sieve_ast_argument_number(*arg);
+ if (sieve_argument_is(tag, vacation_days_tag))
+ seconds = period * (24*60*60);
+ else if (sieve_argument_is(tag, vacation_seconds_tag))
+ seconds = period;
+ else
+ i_unreached();
+
+ /* Enforce :seconds >= min_period */
+ if (seconds < config->min_period) {
+ seconds = config->min_period;
+
+ sieve_argument_validate_warning(
+ valdtr, *arg,
+ "specified :%s value '%llu' is under the minimum",
+ sieve_argument_identifier(tag),
+ (unsigned long long)period);
+ /* Enforce :days <= max_period */
+ } else if (config->max_period > 0 && seconds > config->max_period) {
+ seconds = config->max_period;
+
+ sieve_argument_validate_warning(
+ valdtr, *arg,
+ "specified :%s value '%llu' is over the maximum",
+ sieve_argument_identifier(tag),
+ (unsigned long long)period);
+ }
+
+ sieve_ast_argument_number_set(*arg, seconds);
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+static bool
+cmd_vacation_validate_string_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+ struct cmd_vacation_context_data *ctx_data =
+ (struct cmd_vacation_context_data *)cmd->data;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ /* Check syntax:
+ * :subject string
+ * :from string
+ * :handle string
+ */
+ if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0,
+ SAAT_STRING, FALSE))
+ return FALSE;
+
+ if (sieve_argument_is(tag, vacation_from_tag)) {
+ if (sieve_argument_is_string_literal(*arg)) {
+ string_t *address = sieve_ast_argument_str(*arg);
+ const char *error;
+ bool result;
+
+ T_BEGIN {
+ result = sieve_address_validate_str(address,
+ &error);
+
+ if (!result) {
+ sieve_argument_validate_error(
+ valdtr, *arg,
+ "specified :from address '%s' is invalid for vacation action: %s",
+ str_sanitize(str_c(address), 128),
+ error);
+ }
+ } T_END;
+
+ if (!result)
+ return FALSE;
+ }
+
+ ctx_data->from = sieve_ast_argument_str(*arg);
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+ } else if (sieve_argument_is(tag, vacation_subject_tag)) {
+ ctx_data->subject = sieve_ast_argument_str(*arg);
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+ } else if (sieve_argument_is(tag, vacation_handle_tag)) {
+ ctx_data->handle_arg = *arg;
+
+ /* Detach optional argument (emitted as mandatory) */
+ *arg = sieve_ast_arguments_detach(*arg, 1);
+ }
+ return TRUE;
+}
+
+static bool
+cmd_vacation_validate_stringlist_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ /* Check syntax:
+ * :addresses string-list
+ */
+ if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0,
+ SAAT_STRING_LIST, FALSE))
+ return FALSE;
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+static bool
+cmd_vacation_validate_mime_tag(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct cmd_vacation_context_data *ctx_data =
+ (struct cmd_vacation_context_data *)cmd->data;
+
+ ctx_data->mime = TRUE;
+
+ /* Skip tag */
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+/*
+ * Command registration
+ */
+
+static bool
+cmd_vacation_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &vacation_days_tag, OPT_SECONDS);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &vacation_subject_tag, OPT_SUBJECT);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &vacation_from_tag, OPT_FROM);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &vacation_addresses_tag, OPT_ADDRESSES);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &vacation_mime_tag, OPT_MIME);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &vacation_handle_tag, 0);
+ return TRUE;
+}
+
+bool ext_vacation_register_seconds_tag(
+ struct sieve_validator *valdtr,
+ const struct sieve_extension *vacation_ext)
+{
+ sieve_validator_register_external_tag(
+ valdtr, vacation_command.identifier, vacation_ext,
+ &vacation_seconds_tag, OPT_SECONDS);
+
+ return TRUE;
+}
+
+/*
+ * Command validation
+ */
+
+static bool
+cmd_vacation_pre_validate(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_command *cmd)
+{
+ struct cmd_vacation_context_data *ctx_data;
+
+ /* Assign context */
+ ctx_data = p_new(sieve_command_pool(cmd),
+ struct cmd_vacation_context_data, 1);
+ cmd->data = ctx_data;
+
+ return TRUE;
+}
+
+static const char _handle_empty_subject[] = "<default-subject>";
+static const char _handle_empty_from[] = "<default-from>";
+static const char _handle_mime_enabled[] = "<MIME>";
+static const char _handle_mime_disabled[] = "<NO-MIME>";
+
+static bool
+cmd_vacation_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+ struct cmd_vacation_context_data *ctx_data =
+ (struct cmd_vacation_context_data *)cmd->data;
+
+ if (!sieve_validate_positional_argument(valdtr, cmd, arg, "reason", 1,
+ SAAT_STRING))
+ return FALSE;
+
+ if (!sieve_validator_argument_activate(valdtr, cmd, arg, FALSE))
+ return FALSE;
+
+ /* Construct handle if not set explicitly */
+ if (ctx_data->handle_arg == NULL) {
+ T_BEGIN {
+ string_t *handle;
+ string_t *reason = sieve_ast_argument_str(arg);
+ unsigned int size = str_len(reason);
+
+ /* Precalculate the size of it all */
+ size += (ctx_data->subject == NULL ?
+ sizeof(_handle_empty_subject) - 1 :
+ str_len(ctx_data->subject));
+ size += (ctx_data->from == NULL ?
+ sizeof(_handle_empty_from) - 1 :
+ str_len(ctx_data->from));
+ size += (ctx_data->mime ?
+ sizeof(_handle_mime_enabled) - 1 :
+ sizeof(_handle_mime_disabled) - 1);
+
+ /* Construct the string */
+ handle = t_str_new(size);
+ str_append_str(handle, reason);
+
+ if (ctx_data->subject != NULL)
+ str_append_str(handle, ctx_data->subject);
+ else
+ str_append(handle, _handle_empty_subject);
+
+ if (ctx_data->from != NULL)
+ str_append_str(handle, ctx_data->from);
+ else
+ str_append(handle, _handle_empty_from);
+
+ str_append(handle, (ctx_data->mime ?
+ _handle_mime_enabled :
+ _handle_mime_disabled));
+
+ /* Create positional handle argument */
+ ctx_data->handle_arg =
+ sieve_ast_argument_string_create(
+ cmd->ast_node, handle,
+ sieve_ast_node_line(cmd->ast_node));
+ } T_END;
+
+ if (!sieve_validator_argument_activate(
+ valdtr, cmd, ctx_data->handle_arg, TRUE))
+ return FALSE;
+ } else {
+ /* Attach explicit handle argument as positional */
+ (void)sieve_ast_argument_attach(cmd->ast_node,
+ ctx_data->handle_arg);
+ }
+
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+cmd_vacation_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &vacation_operation);
+
+ /* Generate arguments */
+ if (!sieve_generate_arguments(cgenv, cmd, NULL))
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+ext_vacation_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "VACATION");
+ sieve_code_descend(denv);
+
+ /* Dump optional operands */
+
+ for (;;) {
+ int opt;
+ bool opok = TRUE;
+
+ if ((opt = sieve_opr_optional_dump(denv, address,
+ &opt_code)) < 0)
+ return FALSE;
+
+ if (opt == 0)
+ break;
+
+ switch (opt_code) {
+ case OPT_SECONDS:
+ opok = sieve_opr_number_dump(denv, address, "seconds");
+ break;
+ case OPT_SUBJECT:
+ opok = sieve_opr_string_dump(denv, address, "subject");
+ break;
+ case OPT_FROM:
+ opok = sieve_opr_string_dump(denv, address, "from");
+ break;
+ case OPT_ADDRESSES:
+ opok = sieve_opr_stringlist_dump(denv, address,
+ "addresses");
+ break;
+ case OPT_MIME:
+ sieve_code_dumpf(denv, "mime");
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (!opok)
+ return FALSE;
+ }
+
+ /* Dump reason and handle operands */
+ return (sieve_opr_string_dump(denv, address, "reason") &&
+ sieve_opr_string_dump(denv, address, "handle"));
+}
+
+/*
+ * Code execution
+ */
+
+static int
+ext_vacation_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ const struct ext_vacation_config *config =
+ (const struct ext_vacation_config *)this_ext->context;
+ struct sieve_side_effects_list *slist = NULL;
+ struct act_vacation_context *act;
+ pool_t pool;
+ int opt_code = 0;
+ sieve_number_t seconds = config->default_period;
+ bool mime = FALSE;
+ struct sieve_stringlist *addresses = NULL;
+ string_t *reason, *subject = NULL, *from = NULL, *handle = NULL;
+ const struct smtp_address *from_address = NULL;
+ int ret;
+
+ /*
+ * Read code
+ */
+
+ /* Optional operands */
+
+ for (;;) {
+ int opt;
+
+ if ((opt = sieve_opr_optional_read(renv, address,
+ &opt_code)) < 0)
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ if (opt == 0)
+ break;
+
+ switch (opt_code) {
+ case OPT_SECONDS:
+ ret = sieve_opr_number_read(renv, address, "seconds",
+ &seconds);
+ break;
+ case OPT_SUBJECT:
+ ret = sieve_opr_string_read(renv, address, "subject",
+ &subject);
+ break;
+ case OPT_FROM:
+ ret = sieve_opr_string_read(renv, address, "from",
+ &from);
+ break;
+ case OPT_ADDRESSES:
+ ret = sieve_opr_stringlist_read(renv, address,
+ "addresses",
+ &addresses);
+ break;
+ case OPT_MIME:
+ mime = TRUE;
+ ret = SIEVE_EXEC_OK;
+ break;
+ default:
+ sieve_runtime_trace_error(
+ renv, "unknown optional operand");
+ ret = SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if (ret <= 0)
+ return ret;
+ }
+
+ /* Fixed operands */
+
+ if ((ret =sieve_opr_string_read(renv, address,
+ "reason", &reason)) <= 0 ||
+ (ret = sieve_opr_string_read(renv, address,
+ "handle", &handle)) <= 0)
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ /* Trace */
+
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_ACTIONS)) {
+ sieve_runtime_trace(renv, 0, "vacation action");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(renv, 0, "auto-reply with message `%s'",
+ str_sanitize(str_c(reason), 80));
+ }
+
+ /* Parse :from address */
+ if (from != NULL) {
+ const char *error;
+
+ from_address = sieve_address_parse_str(from, &error);
+ if (from_address == NULL) {
+ sieve_runtime_error(
+ renv, NULL,
+ "specified :from address '%s' is invalid for vacation action: %s",
+ str_sanitize(str_c(from), 128), error);
+ }
+ }
+
+ /* Add vacation action to the result */
+
+ pool = sieve_result_pool(renv->result);
+ act = p_new(pool, struct act_vacation_context, 1);
+ act->reason = p_strdup(pool, str_c(reason));
+ act->handle = p_strdup(pool, str_c(handle));
+ act->seconds = seconds;
+ act->mime = mime;
+ if (subject != NULL)
+ act->subject = p_strdup(pool, str_c(subject));
+ if (from != NULL) {
+ act->from = p_strdup(pool, str_c(from));
+ act->from_address = smtp_address_clone(pool, from_address);
+ }
+
+ /* Normalize all addresses */
+ if (addresses != NULL) {
+ ARRAY_TYPE(smtp_address_const) addrs;
+ string_t *raw_address;
+ int ret;
+
+ sieve_stringlist_reset(addresses);
+
+ p_array_init(&addrs, pool, 4);
+
+ raw_address = NULL;
+ while ((ret = sieve_stringlist_next_item(addresses,
+ &raw_address)) > 0) {
+ const struct smtp_address *addr;
+ const char *error;
+
+ addr = sieve_address_parse_str(raw_address, &error);
+ if (addr != NULL) {
+ addr = smtp_address_clone(pool, addr);
+ array_append(&addrs, &addr, 1);
+ } else {
+ sieve_runtime_error(
+ renv, NULL,
+ "specified :addresses item '%s' is invalid: "
+ "%s for vacation action (ignored)",
+ str_sanitize(str_c(raw_address),128),
+ error);
+ }
+ }
+
+ if (ret < 0) {
+ sieve_runtime_trace_error(
+ renv, "invalid addresses stringlist");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ (void)array_append_space(&addrs);
+ act->addresses = array_idx(&addrs, 0);
+ }
+
+ if (sieve_result_add_action(renv, this_ext, "vacation", &act_vacation,
+ slist, (void *)act, 0, FALSE) < 0)
+ return SIEVE_EXEC_FAILURE;
+
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Action
+ */
+
+/* Runtime verification */
+
+static int
+act_vacation_check_duplicate(const struct sieve_runtime_env *renv ATTR_UNUSED,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other)
+{
+ if (!sieve_action_is_executed(act_other, renv->result)) {
+ sieve_runtime_error(
+ renv, act->location,
+ "duplicate vacation action not allowed "
+ "(previously triggered one was here: %s)",
+ act_other->location);
+ return -1;
+ }
+
+ /* Not an error if executed in preceeding script */
+ return 1;
+}
+
+int act_vacation_check_conflict(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other)
+{
+ if ((act_other->def->flags & SIEVE_ACTFLAG_SENDS_RESPONSE) > 0) {
+ if (!sieve_action_is_executed(act_other, renv->result)) {
+ sieve_runtime_error(
+ renv, act->location,
+ "vacation action conflicts with other action: "
+ "the %s action (%s) also sends a response back to the sender",
+ act_other->def->name, act_other->location);
+ return -1;
+ } else {
+ /* Not an error if executed in preceeding script */
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Result printing */
+
+static void act_vacation_print(const struct sieve_action *action ATTR_UNUSED,
+ const struct sieve_result_print_env *rpenv,
+ bool *keep ATTR_UNUSED)
+{
+ struct act_vacation_context *ctx =
+ (struct act_vacation_context *)action->context;
+
+ sieve_result_action_printf(rpenv, "send vacation message:");
+ sieve_result_printf(rpenv, " => seconds : %llu\n",
+ (unsigned long long)ctx->seconds);
+ if (ctx->subject != NULL) {
+ sieve_result_printf(rpenv, " => subject : %s\n",
+ ctx->subject);
+ }
+ if (ctx->from != NULL) {
+ sieve_result_printf(rpenv, " => from : %s\n",
+ ctx->from);
+ }
+ if (ctx->handle != NULL) {
+ sieve_result_printf(rpenv, " => handle : %s\n",
+ ctx->handle);
+ }
+ sieve_result_printf(rpenv, "\nSTART MESSAGE\n%s\nEND MESSAGE\n",
+ ctx->reason);
+}
+
+/* Result execution */
+
+/* Headers known to be associated with mailing lists
+ */
+static const char * const _list_headers[] = {
+ "list-id",
+ "list-owner",
+ "list-subscribe",
+ "list-post",
+ "list-unsubscribe",
+ "list-help",
+ "list-archive",
+ NULL
+};
+
+/* Headers that should be searched for the user's own mail address(es)
+ */
+
+static const char * const _my_address_headers[] = {
+ "to",
+ "cc",
+ "bcc",
+ "resent-to",
+ "resent-cc",
+ "resent-bcc",
+ NULL
+};
+
+/* Headers that should be searched for the full sender address
+ */
+
+static const char * const _sender_headers[] = {
+ "sender",
+ "resent-from",
+ "from",
+ NULL
+};
+
+static inline bool _is_system_address(const struct smtp_address *address)
+{
+ if (strcasecmp(address->localpart, "MAILER-DAEMON") == 0)
+ return TRUE;
+ if (strcasecmp(address->localpart, "LISTSERV") == 0)
+ return TRUE;
+ if (strcasecmp(address->localpart, "majordomo") == 0)
+ return TRUE;
+ if (strstr(address->localpart, "-request") != NULL)
+ return TRUE;
+ if (str_begins(address->localpart, "owner-"))
+ return TRUE;
+ return FALSE;
+}
+
+static bool
+_msg_address_equals(const struct message_address *addr1,
+ const struct smtp_address *addr2)
+{
+ struct smtp_address saddr;
+
+ i_assert(addr1->mailbox != NULL);
+ return (smtp_address_init_from_msg(&saddr, addr1) >= 0 &&
+ smtp_address_equals_icase(addr2, &saddr));
+}
+
+static inline bool
+_header_contains_my_address(const char *header_val,
+ const struct smtp_address *my_address)
+{
+ const struct message_address *msg_addr;
+
+ msg_addr = message_address_parse(pool_datastack_create(),
+ (const unsigned char *)header_val,
+ strlen(header_val), 256, 0);
+ while (msg_addr != NULL) {
+ if (msg_addr->domain != NULL) {
+ if (_msg_address_equals(msg_addr, my_address))
+ return TRUE;
+ }
+
+ msg_addr = msg_addr->next;
+ }
+
+ return FALSE;
+}
+
+static inline bool
+_contains_my_address(const char * const *headers,
+ const struct smtp_address *my_address)
+{
+ const char *const *hdsp = headers;
+
+ while (*hdsp != NULL) {
+ bool result;
+
+ T_BEGIN {
+ result = _header_contains_my_address(*hdsp, my_address);
+ } T_END;
+
+ if (result)
+ return TRUE;
+
+ hdsp++;
+ }
+
+ return FALSE;
+}
+
+static bool _contains_8bit(const char *text)
+{
+ const unsigned char *p = (const unsigned char *)text;
+
+ for (; *p != '\0'; p++) {
+ if ((*p & 0x80) != 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static bool
+_header_get_full_reply_recipient(const struct ext_vacation_config *config,
+ const struct smtp_address *smtp_to,
+ const char *header,
+ struct message_address *reply_to_r)
+{
+ const struct message_address *addr;
+
+ addr = message_address_parse(
+ pool_datastack_create(),
+ (const unsigned char *)header,
+ strlen(header), 256, 0);
+
+ for (; addr != NULL; addr = addr->next) {
+ bool matched = config->to_header_ignore_envelope;
+
+ if (addr->domain == NULL || addr->invalid_syntax)
+ continue;
+
+ if (!matched)
+ matched = _msg_address_equals(addr, smtp_to);
+
+ if (matched) {
+ *reply_to_r = *addr;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static int
+_get_full_reply_recipient(const struct sieve_action_exec_env *aenv,
+ const struct ext_vacation_config *config,
+ const struct smtp_address *smtp_to,
+ struct message_address *reply_to_r)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ const struct sieve_message_data *msgdata = eenv->msgdata;
+ const char *const *hdsp;
+ int ret;
+
+ hdsp = _sender_headers;
+ for (; *hdsp != NULL; hdsp++) {
+ const char *header;
+
+ if ((ret = mail_get_first_header(msgdata->mail, *hdsp,
+ &header)) < 0) {
+ return sieve_result_mail_error(
+ aenv, msgdata->mail,
+ "failed to read header field `%s'", *hdsp);
+ }
+ if (ret == 0 || header == NULL)
+ continue;
+
+ if (_header_get_full_reply_recipient(config, smtp_to,
+ header, reply_to_r))
+ return SIEVE_EXEC_OK;
+ }
+
+ reply_to_r->mailbox = smtp_to->localpart;
+ reply_to_r->domain = smtp_to->domain;
+ return SIEVE_EXEC_OK;
+}
+
+static const struct var_expand_table *
+_get_var_expand_table(const struct sieve_action_exec_env *aenv ATTR_UNUSED,
+ const char *subject)
+{
+ const struct var_expand_table stack_tab[] = {
+ { '$', subject, "subject" },
+ { '\0', NULL, NULL }
+ };
+
+ return p_memdup(unsafe_data_stack_pool, stack_tab, sizeof(stack_tab));
+}
+
+static int
+act_vacation_get_default_subject(const struct sieve_action_exec_env *aenv,
+ const struct ext_vacation_config *config,
+ const char **subject_r)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ const struct sieve_message_data *msgdata = eenv->msgdata;
+ const char *header, *error;
+ string_t *str;
+ const struct var_expand_table *tab;
+ int ret;
+
+ *subject_r = (config->default_subject == NULL ?
+ "Automated reply" : config->default_subject);
+ if ((ret = mail_get_first_header_utf8(msgdata->mail, "subject",
+ &header)) < 0) {
+ return sieve_result_mail_error(
+ aenv, msgdata->mail,
+ "failed to read header field `subject'");
+ }
+ if (ret == 0)
+ return SIEVE_EXEC_OK;
+ if (config->default_subject_template == NULL) {
+ *subject_r = t_strconcat("Auto: ", header, NULL);
+ return SIEVE_EXEC_OK;
+ }
+
+ str = t_str_new(256);
+ tab = _get_var_expand_table(aenv, header);
+ if (var_expand(str, config->default_subject_template,
+ tab, &error) <= 0) {
+ i_error("Failed to expand deliver_log_format=%s: %s",
+ config->default_subject_template, error);
+ *subject_r = t_strconcat("Auto: ", header, NULL);
+ return SIEVE_EXEC_OK;
+ }
+
+ *subject_r = str_c(str);
+ return SIEVE_EXEC_OK;
+}
+
+static int
+act_vacation_send(const struct sieve_action_exec_env *aenv,
+ const struct ext_vacation_config *config,
+ struct act_vacation_context *ctx,
+ const struct smtp_address *smtp_to,
+ const struct smtp_address *smtp_from,
+ const struct message_address *reply_from)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ const struct sieve_message_data *msgdata = eenv->msgdata;
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ struct sieve_smtp_context *sctx;
+ struct ostream *output;
+ string_t *msg;
+ struct message_address reply_to;
+ const char *header, *outmsgid, *subject, *error;
+ int ret;
+
+ /* Check smpt functions just to be sure */
+
+ if (!sieve_smtp_available(senv)) {
+ sieve_result_global_warning(
+ aenv, "vacation action has no means to send mail");
+ return SIEVE_EXEC_OK;
+ }
+
+ /* Make sure we have a subject for our reply */
+
+ if (ctx->subject == NULL || *(ctx->subject) == '\0') {
+ if ((ret = act_vacation_get_default_subject(aenv, config,
+ &subject)) <= 0)
+ return ret;
+ } else {
+ subject = ctx->subject;
+ }
+
+ subject = str_sanitize_utf8(subject, config->max_subject_codepoints);
+
+ /* Obtain full To address for reply */
+
+ i_zero(&reply_to);
+ reply_to.mailbox = smtp_to->localpart;
+ reply_to.domain = smtp_to->domain;
+ if ((ret = _get_full_reply_recipient(aenv, config, smtp_to,
+ &reply_to)) <= 0)
+ return ret;
+
+ /* Open smtp session */
+
+ sctx = sieve_smtp_start_single(senv, smtp_to, smtp_from, &output);
+
+ outmsgid = sieve_message_get_new_id(eenv->svinst);
+
+ /* Produce a proper reply */
+
+ msg = t_str_new(512);
+ rfc2822_header_write(msg, "X-Sieve", SIEVE_IMPLEMENTATION);
+ rfc2822_header_write(msg, "Message-ID", outmsgid);
+ rfc2822_header_write(msg, "Date", message_date_create(ioloop_time));
+
+ if (ctx->from != NULL && *(ctx->from) != '\0') {
+ rfc2822_header_write_address(msg, "From", ctx->from);
+ } else {
+ if (reply_from == NULL || reply_from->mailbox == NULL ||
+ *reply_from->mailbox == '\0')
+ reply_from = sieve_get_postmaster(senv);
+ rfc2822_header_write(
+ msg, "From",
+ message_address_first_to_string(reply_from));
+ }
+
+ rfc2822_header_write(msg, "To",
+ message_address_first_to_string(&reply_to));
+
+ if (_contains_8bit(subject))
+ rfc2822_header_utf8_printf(msg, "Subject", "%s", subject);
+ else
+ rfc2822_header_printf(msg, "Subject", "%s", subject);
+
+ /* Compose proper in-reply-to and references headers */
+
+ if ((ret = mail_get_first_header(msgdata->mail, "references",
+ &header)) < 0) {
+ sieve_smtp_abort(sctx);
+ return sieve_result_mail_error(
+ aenv, msgdata->mail,
+ "failed to read header field `references'");
+ }
+
+ if (msgdata->id != NULL) {
+ rfc2822_header_write(msg, "In-Reply-To", msgdata->id);
+
+ if (ret > 0 && header != NULL) {
+ rfc2822_header_write(
+ msg, "References",
+ t_strconcat(header, " ", msgdata->id, NULL));
+ } else {
+ rfc2822_header_write(msg, "References", msgdata->id);
+ }
+ } else if (ret > 0 && header != NULL) {
+ rfc2822_header_write(msg, "References", header);
+ }
+
+ rfc2822_header_write(msg, "Auto-Submitted", "auto-replied (vacation)");
+ rfc2822_header_write(msg, "Precedence", "bulk");
+
+ /* Prevent older Microsoft products from replying to this message */
+ rfc2822_header_write(msg, "X-Auto-Response-Suppress", "All");
+
+ rfc2822_header_write(msg, "MIME-Version", "1.0");
+
+ if (!ctx->mime) {
+ rfc2822_header_write(msg, "Content-Type",
+ "text/plain; charset=utf-8");
+ rfc2822_header_write(msg, "Content-Transfer-Encoding", "8bit");
+ str_append(msg, "\r\n");
+ }
+
+ str_printfa(msg, "%s\r\n", ctx->reason);
+ o_stream_nsend(output, str_data(msg), str_len(msg));
+
+ /* Close smtp session */
+ if ((ret = sieve_smtp_finish(sctx, &error)) <= 0) {
+ if (ret < 0) {
+ sieve_result_global_error(
+ aenv, "failed to send vacation response to %s: "
+ "<%s> (temporary error)",
+ smtp_address_encode(smtp_to),
+ str_sanitize(error, 512));
+ } else {
+ sieve_result_global_log_error(
+ aenv, "failed to send vacation response to %s: "
+ "<%s> (permanent error)",
+ smtp_address_encode(smtp_to),
+ str_sanitize(error, 512));
+ }
+ /* This error will be ignored in the end */
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ eenv->exec_status->significant_action_executed = TRUE;
+ return SIEVE_EXEC_OK;
+}
+
+static void
+act_vacation_hash(struct act_vacation_context *vctx, const char *sender,
+ unsigned char hash_r[])
+{
+ const char *rpath = t_str_lcase(sender);
+ struct md5_context ctx;
+
+ md5_init(&ctx);
+ md5_update(&ctx, rpath, strlen(rpath));
+
+ md5_update(&ctx, vctx->handle, strlen(vctx->handle));
+
+ md5_final(&ctx, hash_r);
+}
+
+static int
+act_vacation_commit(const struct sieve_action_exec_env *aenv,
+ void *tr_context ATTR_UNUSED)
+{
+ const struct sieve_action *action = aenv->action;
+ const struct sieve_extension *ext = action->ext;
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_instance *svinst = eenv->svinst;
+ const struct ext_vacation_config *config =
+ (const struct ext_vacation_config *)ext->context;
+ struct act_vacation_context *ctx =
+ (struct act_vacation_context *)action->context;
+ unsigned char dupl_hash[MD5_RESULTLEN];
+ struct mail *mail = sieve_message_get_mail(aenv->msgctx);
+ const struct smtp_address *sender, *recipient;
+ const struct smtp_address *orig_recipient, *user_email;
+ const struct smtp_address *smtp_from;
+ struct message_address reply_from;
+ const char *const *hdsp, *const *headers;
+ int ret;
+
+ if ((eenv->flags & SIEVE_EXECUTE_FLAG_SKIP_RESPONSES) != 0) {
+ sieve_result_global_log(
+ aenv, "not sending vacation reply (skipped)");
+ return SIEVE_EXEC_OK;
+ }
+
+ sender = sieve_message_get_sender(aenv->msgctx);
+ recipient = sieve_message_get_final_recipient(aenv->msgctx);
+
+ i_zero(&reply_from);
+ smtp_from = orig_recipient = user_email = NULL;
+
+ /* Is the recipient unset?
+ */
+ if (smtp_address_isnull(recipient)) {
+ sieve_result_global_warning(
+ aenv, "vacation action aborted: "
+ "envelope recipient is <>");
+ return SIEVE_EXEC_OK;
+ }
+
+ /* Is the return path unset ?
+ */
+ if (smtp_address_isnull(sender)) {
+ sieve_result_global_log(aenv, "discarded vacation reply to <>");
+ return SIEVE_EXEC_OK;
+ }
+
+ /* Are we perhaps trying to respond to ourselves ?
+ */
+ if (smtp_address_equals_icase(sender, recipient)) {
+ sieve_result_global_log(
+ aenv, "discarded vacation reply to own address <%s>",
+ smtp_address_encode(sender));
+ return SIEVE_EXEC_OK;
+ }
+
+ /* Are we perhaps trying to respond to one of our alternative :addresses?
+ */
+ if (ctx->addresses != NULL) {
+ const struct smtp_address * const *alt_address;
+
+ alt_address = ctx->addresses;
+ while (*alt_address != NULL) {
+ if (smtp_address_equals_icase(sender, *alt_address)) {
+ sieve_result_global_log(
+ aenv,
+ "discarded vacation reply to own address <%s> "
+ "(as specified using :addresses argument)",
+ smtp_address_encode(sender));
+ return SIEVE_EXEC_OK;
+ }
+ alt_address++;
+ }
+ }
+
+ /* Did whe respond to this user before? */
+ if (sieve_action_duplicate_check_available(aenv)) {
+ bool duplicate;
+
+ act_vacation_hash(ctx, smtp_address_encode(sender), dupl_hash);
+
+ ret = sieve_action_duplicate_check(aenv, dupl_hash,
+ sizeof(dupl_hash),
+ &duplicate);
+ if (ret < SIEVE_EXEC_OK) {
+ sieve_result_critical(
+ aenv, "failed to check for duplicate vacation response",
+ "failed to check for duplicate vacation response%s",
+ (ret == SIEVE_EXEC_TEMP_FAILURE ?
+ " (temporaty failure)" : ""));
+ return ret;
+ }
+ if (duplicate) {
+ sieve_result_global_log(
+ aenv,
+ "discarded duplicate vacation response to <%s>",
+ smtp_address_encode(sender));
+ return SIEVE_EXEC_OK;
+ }
+ }
+
+ /* Are we trying to respond to a mailing list ? */
+ hdsp = _list_headers;
+ while (*hdsp != NULL) {
+ if ((ret = mail_get_headers(mail, *hdsp, &headers)) < 0) {
+ return sieve_result_mail_error(
+ aenv, mail,
+ "failed to read header field `%s'", *hdsp);
+ }
+
+ if (ret > 0 && headers[0] != NULL) {
+ /* Yes, bail out */
+ sieve_result_global_log(
+ aenv, "discarding vacation response "
+ "to mailinglist recipient <%s>",
+ smtp_address_encode(sender));
+ return SIEVE_EXEC_OK;
+ }
+ hdsp++;
+ }
+
+ /* Is the message that we are replying to an automatic reply ? */
+ if ((ret = mail_get_headers(mail, "auto-submitted", &headers)) < 0) {
+ return sieve_result_mail_error(
+ aenv, mail,
+ "failed to read header field `auto-submitted'");
+ }
+ /* Theoretically multiple headers could exist, so lets make sure */
+ if (ret > 0) {
+ hdsp = headers;
+ while (*hdsp != NULL) {
+ if (strcasecmp(*hdsp, "no") != 0) {
+ sieve_result_global_log(
+ aenv, "discarding vacation response "
+ "to auto-submitted message from <%s>",
+ smtp_address_encode(sender));
+ return SIEVE_EXEC_OK;
+ }
+ hdsp++;
+ }
+ }
+
+ /* Check for the (non-standard) precedence header */
+ if ((ret = mail_get_headers(mail, "precedence", &headers)) < 0) {
+ return sieve_result_mail_error(
+ aenv, mail, "failed to read header field `precedence'");
+ }
+ /* Theoretically multiple headers could exist, so lets make sure */
+ if (ret > 0) {
+ hdsp = headers;
+ while (*hdsp != NULL) {
+ if (strcasecmp(*hdsp, "junk") == 0 ||
+ strcasecmp(*hdsp, "bulk") == 0 ||
+ strcasecmp(*hdsp, "list") == 0) {
+ sieve_result_global_log(
+ aenv, "discarding vacation response "
+ "to precedence=%s message from <%s>",
+ *hdsp, smtp_address_encode(sender));
+ return SIEVE_EXEC_OK;
+ }
+ hdsp++;
+ }
+ }
+
+ /* Check for the (non-standard) Microsoft X-Auto-Response-Suppress header */
+ if ((ret = mail_get_headers(mail, "x-auto-response-suppress",
+ &headers)) < 0) {
+ return sieve_result_mail_error(
+ aenv, mail,
+ "failed to read header field `x-auto-response-suppress'");
+ }
+ /* Theoretically multiple headers could exist, so lets make sure */
+ if (ret > 0) {
+ hdsp = headers;
+ while (*hdsp != NULL) {
+ const char *const *flags = t_strsplit(*hdsp, ",");
+
+ while (*flags != NULL) {
+ const char *flag = t_str_trim(*flags, " \t");
+
+ if (strcasecmp(flag, "All") == 0 ||
+ strcasecmp(flag, "OOF") == 0) {
+ sieve_result_global_log(
+ aenv, "discarding vacation response to message from <%s> "
+ "(`%s' flag found in x-auto-response-suppress header)",
+ smtp_address_encode(sender), flag);
+ return SIEVE_EXEC_OK;
+ }
+ flags++;
+ }
+ hdsp++;
+ }
+ }
+
+ /* Do not reply to system addresses */
+ if (_is_system_address(sender)) {
+ sieve_result_global_log(
+ aenv, "not sending vacation response to system address <%s>",
+ smtp_address_encode(sender));
+ return SIEVE_EXEC_OK;
+ }
+
+ /* Fetch original recipient if necessary */
+ if (config->use_original_recipient)
+ orig_recipient = sieve_message_get_orig_recipient(aenv->msgctx);
+ /* Fetch explicitly configured user email address */
+ if (svinst->user_email != NULL)
+ user_email = svinst->user_email;
+
+ /* Is the original message directly addressed to the user or the addresses
+ * specified using the :addresses tag?
+ */
+ hdsp = _my_address_headers;
+ while (*hdsp != NULL) {
+ if ((ret = mail_get_headers(mail, *hdsp, &headers)) < 0) {
+ return sieve_result_mail_error(
+ aenv, mail, "failed to read header field `%s'",
+ *hdsp);
+ }
+ if (ret > 0 && headers[0] != NULL) {
+ /* Final recipient directly listed in headers? */
+ if (_contains_my_address(headers, recipient)) {
+ smtp_from = recipient;
+ message_address_init_from_smtp(
+ &reply_from, NULL, recipient);
+ break;
+ }
+
+ /* Original recipient directly listed in headers? */
+ if (!smtp_address_isnull(orig_recipient) &&
+ _contains_my_address(headers, orig_recipient)) {
+ smtp_from = orig_recipient;
+ message_address_init_from_smtp(
+ &reply_from, NULL, orig_recipient);
+ break;
+ }
+
+ /* User-provided :addresses listed in headers? */
+ if (ctx->addresses != NULL) {
+ bool found = FALSE;
+ const struct smtp_address * const *my_address;
+
+ my_address = ctx->addresses;
+ while (!found && *my_address != NULL) {
+ if ((found = _contains_my_address(headers, *my_address))) {
+ /* Avoid letting user determine SMTP sender directly */
+ smtp_from = (orig_recipient == NULL ?
+ recipient : orig_recipient);
+ message_address_init_from_smtp(
+ &reply_from, NULL, *my_address);
+ }
+ my_address++;
+ }
+
+ if (found) break;
+ }
+
+ /* Explicitly-configured user email address directly listed in
+ headers? */
+ if (user_email != NULL &&
+ _contains_my_address(headers, user_email)) {
+ smtp_from = user_email;
+ message_address_init_from_smtp(
+ &reply_from, NULL, smtp_from);
+ break;
+ }
+ }
+ hdsp++;
+ }
+
+ /* My address not found in the headers; we got an implicit delivery */
+ if (*hdsp == NULL) {
+ if (config->dont_check_recipient) {
+ /* Send reply from envelope recipient address */
+ smtp_from = (orig_recipient == NULL ?
+ recipient : orig_recipient);
+ if (user_email == NULL)
+ user_email = sieve_get_user_email(svinst);
+ message_address_init_from_smtp(&reply_from,
+ NULL, user_email);
+ } else {
+ const char *orig_rcpt_str = "", *user_email_str = "";
+
+ /* Bail out */
+ if (config->use_original_recipient) {
+ orig_rcpt_str =
+ t_strdup_printf("original-recipient=<%s>, ",
+ (orig_recipient == NULL ? "UNAVAILABLE" :
+ smtp_address_encode(orig_recipient)));
+ }
+
+ if (user_email != NULL) {
+ user_email_str = t_strdup_printf(
+ "user-email=<%s>, ",
+ smtp_address_encode(user_email));
+ }
+
+ sieve_result_global_log(
+ aenv, "discarding vacation response for implicitly delivered message; "
+ "no known (envelope) recipient address found in message headers "
+ "(recipient=<%s>, %s%sand%s additional `:addresses' are specified)",
+ smtp_address_encode(recipient),
+ orig_rcpt_str, user_email_str,
+ (ctx->addresses == NULL || *ctx->addresses == NULL ?
+ " no" : ""));
+ return SIEVE_EXEC_OK;
+ }
+ }
+
+ /* Send the message */
+
+ T_BEGIN {
+ ret = act_vacation_send(
+ aenv, config, ctx, sender,
+ (config->send_from_recipient ? smtp_from : NULL),
+ &reply_from);
+ } T_END;
+
+ if (ret == SIEVE_EXEC_OK) {
+ sieve_number_t seconds;
+
+ eenv->exec_status->significant_action_executed = TRUE;
+
+ struct event_passthrough *e =
+ sieve_action_create_finish_event(aenv);
+
+ sieve_result_event_log(aenv, e->event(),
+ "sent vacation response to <%s>",
+ smtp_address_encode(sender));
+
+ /* Check period limits once more */
+ seconds = ctx->seconds;
+ if (seconds < config->min_period)
+ seconds = config->min_period;
+ else if (config->max_period > 0 && seconds > config->max_period)
+ seconds = config->max_period;
+
+ /* Mark as replied */
+ if (seconds > 0) {
+ sieve_action_duplicate_mark(aenv, dupl_hash,
+ sizeof(dupl_hash),
+ ioloop_time + seconds);
+ }
+ }
+
+ if (ret == SIEVE_EXEC_TEMP_FAILURE)
+ return SIEVE_EXEC_TEMP_FAILURE;
+
+ /* Ignore all other errors */
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/vacation/ext-vacation-common.c b/pigeonhole/src/lib-sieve/plugins/vacation/ext-vacation-common.c
new file mode 100644
index 0000000..97be3a5
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vacation/ext-vacation-common.c
@@ -0,0 +1,114 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-settings.h"
+#include "sieve-extensions.h"
+
+#include "ext-vacation-common.h"
+
+bool ext_vacation_load
+(const struct sieve_extension *ext, void **context)
+{
+ struct sieve_instance *svinst = ext->svinst;
+ struct ext_vacation_config *config;
+ sieve_number_t min_period, max_period, default_period;
+ bool use_original_recipient, dont_check_recipient, send_from_recipient,
+ to_header_ignore_envelope;
+ unsigned long long max_subject_codepoints;
+ const char *default_subject, *default_subject_template;
+
+ if ( *context != NULL ) {
+ ext_vacation_unload(ext);
+ }
+
+ if ( !sieve_setting_get_duration_value
+ (svinst, "sieve_vacation_min_period", &min_period) ) {
+ min_period = EXT_VACATION_DEFAULT_MIN_PERIOD;
+ }
+
+ if ( !sieve_setting_get_duration_value
+ (svinst, "sieve_vacation_max_period", &max_period) ) {
+ max_period = EXT_VACATION_DEFAULT_MAX_PERIOD;
+ }
+
+ if ( !sieve_setting_get_duration_value
+ (svinst, "sieve_vacation_default_period", &default_period) ) {
+ default_period = EXT_VACATION_DEFAULT_PERIOD;
+ }
+
+ if ( max_period > 0
+ && (min_period > max_period || default_period < min_period
+ || default_period > max_period) ) {
+ min_period = EXT_VACATION_DEFAULT_MIN_PERIOD;
+ max_period = EXT_VACATION_DEFAULT_MAX_PERIOD;
+ default_period = EXT_VACATION_DEFAULT_PERIOD;
+
+ e_warning(svinst->event, "vacation extension: "
+ "invalid settings: violated "
+ "sieve_vacation_min_period < "
+ "sieve_vacation_default_period < "
+ "sieve_vacation_max_period");
+ }
+
+ default_subject = sieve_setting_get(
+ svinst, "sieve_vacation_default_subject");
+ default_subject_template = sieve_setting_get(
+ svinst, "sieve_vacation_default_subject_template");
+
+ if ( !sieve_setting_get_uint_value
+ (svinst, "sieve_vacation_max_subject_codepoints", &max_subject_codepoints) ) {
+ max_subject_codepoints = EXT_VACATION_DEFAULT_MAX_SUBJECT_CODEPOINTS;
+ }
+
+ if ( !sieve_setting_get_bool_value
+ (svinst, "sieve_vacation_use_original_recipient", &use_original_recipient) ) {
+ use_original_recipient = FALSE;
+ }
+
+ if ( !sieve_setting_get_bool_value
+ (svinst, "sieve_vacation_dont_check_recipient", &dont_check_recipient) ) {
+ dont_check_recipient = FALSE;
+ }
+
+ if ( !sieve_setting_get_bool_value
+ (svinst, "sieve_vacation_send_from_recipient", &send_from_recipient) ) {
+ send_from_recipient = FALSE;
+ }
+
+ if ( !sieve_setting_get_bool_value(svinst,
+ "sieve_vacation_to_header_ignore_envelope",
+ &to_header_ignore_envelope) ) {
+ to_header_ignore_envelope = FALSE;
+ }
+
+ config = i_new(struct ext_vacation_config, 1);
+ config->min_period = min_period;
+ config->max_period = max_period;
+ config->default_period = default_period;
+ config->max_subject_codepoints = max_subject_codepoints;
+ config->default_subject = i_strdup_empty(default_subject);
+ config->default_subject_template = i_strdup_empty(default_subject_template);
+ config->use_original_recipient = use_original_recipient;
+ config->dont_check_recipient = dont_check_recipient;
+ config->send_from_recipient = send_from_recipient;
+ config->to_header_ignore_envelope = to_header_ignore_envelope;
+
+ *context = (void *) config;
+
+ return TRUE;
+}
+
+void ext_vacation_unload
+(const struct sieve_extension *ext)
+{
+ struct ext_vacation_config *config =
+ (struct ext_vacation_config *) ext->context;
+
+ i_free(config->default_subject);
+ i_free(config->default_subject_template);
+ i_free(config);
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/vacation/ext-vacation-common.h b/pigeonhole/src/lib-sieve/plugins/vacation/ext-vacation-common.h
new file mode 100644
index 0000000..3a38cf6
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vacation/ext-vacation-common.h
@@ -0,0 +1,60 @@
+#ifndef EXT_VACATION_COMMON_H
+#define EXT_VACATION_COMMON_H
+
+#include "sieve-common.h"
+
+/*
+ * Extension configuration
+ */
+
+#define EXT_VACATION_DEFAULT_PERIOD (7*24*60*60)
+#define EXT_VACATION_DEFAULT_MIN_PERIOD (24*60*60)
+#define EXT_VACATION_DEFAULT_MAX_PERIOD 0
+#define EXT_VACATION_DEFAULT_MAX_SUBJECT_CODEPOINTS 256
+
+struct ext_vacation_config {
+ unsigned int min_period;
+ unsigned int max_period;
+ unsigned int default_period;
+ unsigned long long max_subject_codepoints;
+ char *default_subject;
+ char *default_subject_template;
+ bool use_original_recipient;
+ bool dont_check_recipient;
+ bool send_from_recipient;
+ bool to_header_ignore_envelope;
+};
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def vacation_command;
+
+/*
+ * Operations
+ */
+
+extern const struct sieve_operation_def vacation_operation;
+
+/*
+ * Extensions
+ */
+
+/* Vacation */
+
+extern const struct sieve_extension_def vacation_extension;
+
+bool ext_vacation_load
+ (const struct sieve_extension *ext, void **context);
+void ext_vacation_unload
+ (const struct sieve_extension *ext);
+
+/* Vacation-seconds */
+
+extern const struct sieve_extension_def vacation_seconds_extension;
+
+bool ext_vacation_register_seconds_tag
+ (struct sieve_validator *valdtr, const struct sieve_extension *vacation_ext);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/vacation/ext-vacation-seconds.c b/pigeonhole/src/lib-sieve/plugins/vacation/ext-vacation-seconds.c
new file mode 100644
index 0000000..41c0f06
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vacation/ext-vacation-seconds.c
@@ -0,0 +1,66 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension vacation-seconds
+ * --------------------------
+ *
+ * Authors: Stephan Bosch <stephan@rename-it.nl>
+ * Specification: RFC 6131
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+
+#include "sieve-extensions.h"
+#include "sieve-validator.h"
+
+#include "ext-vacation-common.h"
+
+/*
+ * Extension
+ */
+
+bool ext_vacation_seconds_load
+ (const struct sieve_extension *ext, void **context);
+static bool ext_vacation_seconds_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def vacation_seconds_extension = {
+ .name = "vacation-seconds",
+ .load = ext_vacation_seconds_load,
+ .validator_load = ext_vacation_seconds_validator_load,
+};
+
+bool ext_vacation_seconds_load
+(const struct sieve_extension *ext, void **context)
+{
+ if ( *context == NULL ) {
+ /* Make sure vacation extension is registered */
+ *context = (void *)
+ sieve_extension_require(ext->svinst, &vacation_extension, TRUE);
+ }
+
+ return TRUE;
+}
+
+static bool ext_vacation_seconds_validator_load
+(const struct sieve_extension *ext ATTR_UNUSED, struct sieve_validator *valdtr)
+{
+ const struct sieve_extension *vacation_ext;
+
+ /* Load vacation extension implicitly */
+
+ vacation_ext = sieve_validator_extension_load_implicit
+ (valdtr, vacation_extension.name);
+
+ if ( vacation_ext == NULL )
+ return FALSE;
+
+ /* Add seconds tag to vacation command */
+
+ return ext_vacation_register_seconds_tag(valdtr, vacation_ext);
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/vacation/ext-vacation.c b/pigeonhole/src/lib-sieve/plugins/vacation/ext-vacation.c
new file mode 100644
index 0000000..8d3d9a7
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vacation/ext-vacation.c
@@ -0,0 +1,131 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension vacation
+ * ------------------
+ *
+ * Authors: Stephan Bosch <stephan@rename-it.nl>
+ * Specification: RFC 5230
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-vacation-common.h"
+
+/*
+ * Extension
+ */
+
+static bool
+ext_vacation_validator_load(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr);
+static bool
+ext_vacation_interpreter_load(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+static bool
+ext_vacation_validator_validate(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context,
+ struct sieve_ast_argument *require_arg,
+ bool required);
+static int
+ext_vacation_interpreter_run(const struct sieve_extension *this_ext,
+ const struct sieve_runtime_env *renv,
+ void *context, bool deferred);
+
+const struct sieve_extension_def vacation_extension = {
+ .name = "vacation",
+ .load = ext_vacation_load,
+ .unload = ext_vacation_unload,
+ .validator_load = ext_vacation_validator_load,
+ .interpreter_load = ext_vacation_interpreter_load,
+ SIEVE_EXT_DEFINE_OPERATION(vacation_operation)
+};
+const struct sieve_validator_extension
+vacation_validator_extension = {
+ .ext = &vacation_extension,
+ .validate = ext_vacation_validator_validate
+};
+const struct sieve_interpreter_extension
+vacation_interpreter_extension = {
+ .ext_def = &vacation_extension,
+ .run = ext_vacation_interpreter_run
+};
+
+static bool
+ext_vacation_validator_load(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr)
+{
+ /* Register new command */
+ sieve_validator_register_command(valdtr, ext, &vacation_command);
+
+ sieve_validator_extension_register(valdtr, ext,
+ &vacation_validator_extension, NULL);
+ return TRUE;
+}
+
+static bool
+ext_vacation_interpreter_load(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ sieve_interpreter_extension_register(
+ renv->interp, ext, &vacation_interpreter_extension, NULL);
+ return TRUE;
+}
+
+static bool
+ext_vacation_validator_validate(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr,
+ void *context ATTR_UNUSED,
+ struct sieve_ast_argument *require_arg,
+ bool required)
+{
+ if (required) {
+ enum sieve_compile_flags flags =
+ sieve_validator_compile_flags(valdtr);
+
+ if ((flags & SIEVE_COMPILE_FLAG_NO_ENVELOPE) != 0) {
+ sieve_argument_validate_error(
+ valdtr, require_arg,
+ "the %s extension cannot be used in this context "
+ "(needs access to message envelope)",
+ sieve_extension_name(ext));
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static int
+ext_vacation_interpreter_run(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ void *context ATTR_UNUSED, bool deferred)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+
+ if ((eenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) != 0) {
+ if (!deferred) {
+ sieve_runtime_error(
+ renv, NULL,
+ "the %s extension cannot be used in this context "
+ "(needs access to message envelope)",
+ sieve_extension_name(ext));
+ }
+ return SIEVE_EXEC_FAILURE;
+ }
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/Makefile.am b/pigeonhole/src/lib-sieve/plugins/variables/Makefile.am
new file mode 100644
index 0000000..354bad2
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/Makefile.am
@@ -0,0 +1,41 @@
+noinst_LTLIBRARIES = libsieve_ext_variables.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+cmds = \
+ cmd-set.c
+
+tsts = \
+ tst-string.c
+
+libsieve_ext_variables_la_SOURCES = \
+ ext-variables-common.c \
+ ext-variables-name.c \
+ ext-variables-namespaces.c \
+ ext-variables-arguments.c \
+ ext-variables-operands.c \
+ ext-variables-modifiers.c \
+ ext-variables-dump.c \
+ $(cmds) \
+ $(tsts) \
+ ext-variables.c
+
+public_headers = \
+ sieve-ext-variables.h
+
+headers = \
+ ext-variables-common.h \
+ ext-variables-limits.h \
+ ext-variables-name.h \
+ ext-variables-namespaces.h \
+ ext-variables-arguments.h \
+ ext-variables-operands.h \
+ ext-variables-modifiers.h \
+ ext-variables-dump.h
+
+pkginc_libdir=$(dovecot_pkgincludedir)/sieve
+pkginc_lib_HEADERS = $(public_headers)
+noinst_HEADERS = $(headers)
+
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/Makefile.in b/pigeonhole/src/lib-sieve/plugins/variables/Makefile.in
new file mode 100644
index 0000000..701d574
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/Makefile.in
@@ -0,0 +1,801 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/variables
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(pkginc_lib_HEADERS) $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_variables_la_LIBADD =
+am__objects_1 = cmd-set.lo
+am__objects_2 = tst-string.lo
+am_libsieve_ext_variables_la_OBJECTS = ext-variables-common.lo \
+ ext-variables-name.lo ext-variables-namespaces.lo \
+ ext-variables-arguments.lo ext-variables-operands.lo \
+ ext-variables-modifiers.lo ext-variables-dump.lo \
+ $(am__objects_1) $(am__objects_2) ext-variables.lo
+libsieve_ext_variables_la_OBJECTS = \
+ $(am_libsieve_ext_variables_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cmd-set.Plo \
+ ./$(DEPDIR)/ext-variables-arguments.Plo \
+ ./$(DEPDIR)/ext-variables-common.Plo \
+ ./$(DEPDIR)/ext-variables-dump.Plo \
+ ./$(DEPDIR)/ext-variables-modifiers.Plo \
+ ./$(DEPDIR)/ext-variables-name.Plo \
+ ./$(DEPDIR)/ext-variables-namespaces.Plo \
+ ./$(DEPDIR)/ext-variables-operands.Plo \
+ ./$(DEPDIR)/ext-variables.Plo ./$(DEPDIR)/tst-string.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_variables_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_variables_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkginc_libdir)"
+HEADERS = $(noinst_HEADERS) $(pkginc_lib_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_variables.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+cmds = \
+ cmd-set.c
+
+tsts = \
+ tst-string.c
+
+libsieve_ext_variables_la_SOURCES = \
+ ext-variables-common.c \
+ ext-variables-name.c \
+ ext-variables-namespaces.c \
+ ext-variables-arguments.c \
+ ext-variables-operands.c \
+ ext-variables-modifiers.c \
+ ext-variables-dump.c \
+ $(cmds) \
+ $(tsts) \
+ ext-variables.c
+
+public_headers = \
+ sieve-ext-variables.h
+
+headers = \
+ ext-variables-common.h \
+ ext-variables-limits.h \
+ ext-variables-name.h \
+ ext-variables-namespaces.h \
+ ext-variables-arguments.h \
+ ext-variables-operands.h \
+ ext-variables-modifiers.h \
+ ext-variables-dump.h
+
+pkginc_libdir = $(dovecot_pkgincludedir)/sieve
+pkginc_lib_HEADERS = $(public_headers)
+noinst_HEADERS = $(headers)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/variables/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/variables/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_variables.la: $(libsieve_ext_variables_la_OBJECTS) $(libsieve_ext_variables_la_DEPENDENCIES) $(EXTRA_libsieve_ext_variables_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_variables_la_OBJECTS) $(libsieve_ext_variables_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-set.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-variables-arguments.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-variables-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-variables-dump.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-variables-modifiers.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-variables-name.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-variables-namespaces.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-variables-operands.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-variables.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-string.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
+ done
+
+uninstall-pkginc_libHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(pkginc_libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/cmd-set.Plo
+ -rm -f ./$(DEPDIR)/ext-variables-arguments.Plo
+ -rm -f ./$(DEPDIR)/ext-variables-common.Plo
+ -rm -f ./$(DEPDIR)/ext-variables-dump.Plo
+ -rm -f ./$(DEPDIR)/ext-variables-modifiers.Plo
+ -rm -f ./$(DEPDIR)/ext-variables-name.Plo
+ -rm -f ./$(DEPDIR)/ext-variables-namespaces.Plo
+ -rm -f ./$(DEPDIR)/ext-variables-operands.Plo
+ -rm -f ./$(DEPDIR)/ext-variables.Plo
+ -rm -f ./$(DEPDIR)/tst-string.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkginc_libHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/cmd-set.Plo
+ -rm -f ./$(DEPDIR)/ext-variables-arguments.Plo
+ -rm -f ./$(DEPDIR)/ext-variables-common.Plo
+ -rm -f ./$(DEPDIR)/ext-variables-dump.Plo
+ -rm -f ./$(DEPDIR)/ext-variables-modifiers.Plo
+ -rm -f ./$(DEPDIR)/ext-variables-name.Plo
+ -rm -f ./$(DEPDIR)/ext-variables-namespaces.Plo
+ -rm -f ./$(DEPDIR)/ext-variables-operands.Plo
+ -rm -f ./$(DEPDIR)/ext-variables.Plo
+ -rm -f ./$(DEPDIR)/tst-string.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkginc_libHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-pkginc_libHEADERS install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-pkginc_libHEADERS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/cmd-set.c b/pigeonhole/src/lib-sieve/plugins/variables/cmd-set.c
new file mode 100644
index 0000000..d0fdc97
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/cmd-set.c
@@ -0,0 +1,235 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+
+#include "sieve-code.h"
+#include "sieve-ast.h"
+#include "sieve-commands.h"
+#include "sieve-binary.h"
+
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-variables-common.h"
+
+/*
+ * Set command
+ *
+ * Syntax:
+ * set [MODIFIER] <name: string> <value: string>
+ */
+
+static bool cmd_set_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool cmd_set_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool cmd_set_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+const struct sieve_command_def cmd_set = {
+ .identifier = "set",
+ .type = SCT_COMMAND,
+ .positional_args = 2,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = cmd_set_registered,
+ .validate = cmd_set_validate,
+ .generate = cmd_set_generate,
+};
+
+/*
+ * Set operation
+ */
+
+static bool cmd_set_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int cmd_set_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def cmd_set_operation = {
+ .mnemonic = "SET",
+ .ext_def = &variables_extension,
+ .code = EXT_VARIABLES_OPERATION_SET,
+ .dump = cmd_set_operation_dump,
+ .execute = cmd_set_operation_execute
+};
+
+/*
+ * Compiler context
+ */
+
+struct cmd_set_context {
+ ARRAY_TYPE(sieve_variables_modifier) modifiers;
+};
+
+/* Command registration */
+
+static bool cmd_set_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_variables_modifiers_link_tag(valdtr, ext, cmd_reg);
+
+ return TRUE;
+}
+
+/*
+ * Command validation
+ */
+
+static bool cmd_set_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd)
+{
+ const struct sieve_extension *this_ext = cmd->ext;
+ struct sieve_ast_argument *arg = cmd->first_positional;
+ pool_t pool = sieve_command_pool(cmd);
+ struct cmd_set_context *sctx;
+
+ /* Create command context */
+ sctx = p_new(pool, struct cmd_set_context, 1);
+ p_array_init(&sctx->modifiers, pool, 4);
+ cmd->data = (void *) sctx;
+
+ /* Validate modifiers */
+ if ( !sieve_variables_modifiers_validate
+ (valdtr, cmd, &sctx->modifiers) )
+ return FALSE;
+
+ /* Validate name argument */
+ if ( !sieve_validate_positional_argument
+ (valdtr, cmd, arg, "name", 1, SAAT_STRING) ) {
+ return FALSE;
+ }
+ if ( !sieve_variable_argument_activate
+ (this_ext, this_ext, valdtr, cmd, arg, TRUE) ) {
+ return FALSE;
+ }
+ arg = sieve_ast_argument_next(arg);
+
+ /* Validate value argument */
+ if ( !sieve_validate_positional_argument
+ (valdtr, cmd, arg, "value", 2, SAAT_STRING) ) {
+ return FALSE;
+ }
+ return sieve_validator_argument_activate
+ (valdtr, cmd, arg, FALSE);
+}
+
+/*
+ * Code generation
+ */
+
+static bool cmd_set_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ const struct sieve_extension *this_ext = cmd->ext;
+ struct sieve_binary_block *sblock = cgenv->sblock;
+ struct cmd_set_context *sctx = (struct cmd_set_context *) cmd->data;
+
+ sieve_operation_emit(sblock, this_ext, &cmd_set_operation);
+
+ /* Generate arguments */
+ if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
+ return FALSE;
+
+ /* Generate modifiers */
+ if ( !sieve_variables_modifiers_generate
+ (cgenv, &sctx->modifiers) )
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool cmd_set_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "SET");
+ sieve_code_descend(denv);
+
+ /* Print both variable name and string value */
+ if ( !sieve_opr_string_dump(denv, address, "variable") ||
+ !sieve_opr_string_dump(denv, address, "value") )
+ return FALSE;
+
+ return sieve_variables_modifiers_code_dump(denv, address);
+}
+
+/*
+ * Code execution
+ */
+
+static int cmd_set_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ struct sieve_variable_storage *storage;
+ ARRAY_TYPE(sieve_variables_modifier) modifiers;
+ unsigned int var_index;
+ string_t *value;
+ int ret = SIEVE_EXEC_OK;
+
+ /*
+ * Read the normal operands
+ */
+
+ if ( (ret=sieve_variable_operand_read
+ (renv, address, "variable", &storage, &var_index)) <= 0 )
+ return ret;
+
+ if ( (ret=sieve_opr_string_read(renv, address, "string", &value)) <= 0 )
+ return ret;
+
+ if ( (ret=sieve_variables_modifiers_code_read
+ (renv, this_ext, address, &modifiers)) <= 0 )
+ return ret;
+
+ /*
+ * Determine and assign the value
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "set command");
+ sieve_runtime_trace_descend(renv);
+
+ /* Apply modifiers */
+ if ( (ret=sieve_variables_modifiers_apply
+ (renv, this_ext, &modifiers, &value)) <= 0 )
+ return ret;
+
+ /* Actually assign the value if all is well */
+ i_assert ( value != NULL );
+ if ( !sieve_variable_assign(storage, var_index, value) )
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ /* Trace */
+ if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+ const char *var_name, *var_id;
+
+ (void)sieve_variable_get_identifier(storage, var_index, &var_name);
+ var_id = sieve_variable_get_varid(storage, var_index);
+
+ sieve_runtime_trace_here(renv, 0, "assign `%s' [%s] = \"%s\"",
+ var_name, var_id, str_c(value));
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+
+
+
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-arguments.c b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-arguments.c
new file mode 100644
index 0000000..2ac773c
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-arguments.c
@@ -0,0 +1,420 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-ast.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-dump.h"
+
+#include "ext-variables-common.h"
+#include "ext-variables-limits.h"
+#include "ext-variables-name.h"
+#include "ext-variables-operands.h"
+#include "ext-variables-namespaces.h"
+#include "ext-variables-arguments.h"
+
+/*
+ * Variable argument implementation
+ */
+
+static bool arg_variable_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *context);
+
+const struct sieve_argument_def variable_argument = {
+ .identifier = "@variable",
+ .generate = arg_variable_generate
+};
+
+static bool ext_variables_variable_argument_activate
+(const struct sieve_extension *var_ext,
+ const struct sieve_extension *this_ext,
+ struct sieve_validator *valdtr, struct sieve_ast_argument *arg,
+ const char *variable)
+{
+ struct sieve_ast *ast = arg->ast;
+ struct sieve_variable *var;
+
+ var = ext_variables_validator_declare_variable(this_ext, valdtr, variable);
+
+ if ( var == NULL ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "(implicit) declaration of new variable '%s' exceeds the limit "
+ "(max variables: %u)", variable,
+ sieve_variables_get_max_scope_size(var_ext));
+ return FALSE;
+ }
+
+ arg->argument = sieve_argument_create(ast, &variable_argument, this_ext, 0);
+ arg->argument->data = (void *) var;
+ return TRUE;
+}
+
+static struct sieve_ast_argument *ext_variables_variable_argument_create
+(const struct sieve_extension *this_ext, struct sieve_validator *valdtr,
+ struct sieve_ast_argument *parent_arg, const char *variable)
+{
+ struct sieve_ast *ast = parent_arg->ast;
+ struct sieve_ast_argument *new_arg;
+
+ new_arg = sieve_ast_argument_create(ast, sieve_ast_argument_line(parent_arg));
+ new_arg->type = SAAT_STRING;
+
+ if ( !ext_variables_variable_argument_activate
+ (this_ext, this_ext, valdtr, new_arg, variable) )
+ return NULL;
+
+ return new_arg;
+}
+
+static bool arg_variable_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *context ATTR_UNUSED)
+{
+ struct sieve_argument *argument = arg->argument;
+ struct sieve_variable *var = (struct sieve_variable *) argument->data;
+
+ sieve_variables_opr_variable_emit(cgenv->sblock, argument->ext, var);
+
+ return TRUE;
+}
+
+/*
+ * Match value argument implementation
+ */
+
+static bool arg_match_value_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *context ATTR_UNUSED);
+
+const struct sieve_argument_def match_value_argument = {
+ .identifier = "@match_value",
+ .generate = arg_match_value_generate
+};
+
+static bool ext_variables_match_value_argument_activate
+(const struct sieve_extension *this_ext,
+ struct sieve_validator *valdtr, struct sieve_ast_argument *arg,
+ unsigned int index, bool assignment)
+{
+ struct sieve_ast *ast = arg->ast;
+
+ if ( assignment ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "cannot assign to match variable");
+ return FALSE;
+ }
+
+ if ( index > EXT_VARIABLES_MAX_MATCH_INDEX ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "match value index %u out of range (max: %u)", index,
+ EXT_VARIABLES_MAX_MATCH_INDEX);
+ return FALSE;
+ }
+
+ arg->argument = sieve_argument_create
+ (ast, &match_value_argument, this_ext, 0);
+ arg->argument->data = (void *) POINTER_CAST(index);
+ return TRUE;
+}
+
+static struct sieve_ast_argument *ext_variables_match_value_argument_create
+(const struct sieve_extension *this_ext, struct sieve_validator *valdtr,
+ struct sieve_ast_argument *parent_arg, unsigned int index)
+{
+ struct sieve_ast *ast = parent_arg->ast;
+ struct sieve_ast_argument *new_arg;
+
+ new_arg = sieve_ast_argument_create(ast, sieve_ast_argument_line(parent_arg));
+ new_arg->type = SAAT_STRING;
+
+ if ( !ext_variables_match_value_argument_activate
+ (this_ext, valdtr, new_arg, index, FALSE) ) {
+ return NULL;
+ }
+
+ return new_arg;
+}
+
+static bool arg_match_value_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *context ATTR_UNUSED)
+{
+ struct sieve_argument *argument = arg->argument;
+ unsigned int index = POINTER_CAST_TO(argument->data, unsigned int);
+
+ sieve_variables_opr_match_value_emit(cgenv->sblock, argument->ext, index);
+
+ return TRUE;
+}
+
+/*
+ * Variable string argument implementation
+ */
+
+static bool arg_variable_string_validate
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+const struct sieve_argument_def variable_string_argument = {
+ .identifier = "@variable-string",
+ .validate = arg_variable_string_validate,
+ .generate = sieve_arg_catenated_string_generate,
+};
+
+static bool arg_variable_string_validate
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ const struct sieve_extension *this_ext = (*arg)->argument->ext;
+ enum { ST_NONE, ST_OPEN, ST_VARIABLE, ST_CLOSE } state = ST_NONE;
+ pool_t pool = sieve_ast_pool((*arg)->ast);
+ struct sieve_arg_catenated_string *catstr = NULL;
+ string_t *str = sieve_ast_argument_str(*arg);
+ const char *p, *strstart, *substart = NULL;
+ const char *strval = (const char *) str_data(str);
+ const char *strend = strval + str_len(str);
+ bool result = TRUE;
+ ARRAY_TYPE(sieve_variable_name) substitution;
+ int nelements = 0;
+
+ T_BEGIN {
+ /* Initialize substitution structure */
+ t_array_init(&substitution, 2);
+
+ p = strval;
+ strstart = p;
+ while ( result && p < strend ) {
+ switch ( state ) {
+
+ /* Nothing found yet */
+ case ST_NONE:
+ if ( *p == '$' ) {
+ substart = p;
+ state = ST_OPEN;
+ }
+ p++;
+ break;
+
+ /* Got '$' */
+ case ST_OPEN:
+ if ( *p == '{' ) {
+ state = ST_VARIABLE;
+ p++;
+ } else
+ state = ST_NONE;
+ break;
+
+ /* Got '${' */
+ case ST_VARIABLE:
+ nelements = ext_variable_name_parse(&substitution, &p, strend);
+
+ if ( nelements < 0 )
+ state = ST_NONE;
+ else
+ state = ST_CLOSE;
+
+ break;
+
+ /* Finished parsing name, expecting '}' */
+ case ST_CLOSE:
+ if ( *p == '}' ) {
+ struct sieve_ast_argument *strarg;
+
+ /* We now know that the substitution is valid */
+
+ if ( catstr == NULL ) {
+ catstr = sieve_arg_catenated_string_create(*arg);
+ }
+
+ /* Add the substring that is before the substitution to the
+ * variable-string AST.
+ *
+ * FIXME: For efficiency, if the variable is not found we should
+ * coalesce this substring with the one after the substitution.
+ */
+ if ( substart > strstart ) {
+ string_t *newstr = str_new(pool, substart - strstart);
+ str_append_data(newstr, strstart, substart - strstart);
+
+ strarg = sieve_ast_argument_string_create_raw
+ ((*arg)->ast, newstr, (*arg)->source_line);
+ sieve_arg_catenated_string_add_element(catstr, strarg);
+
+ /* Give other substitution extensions a chance to do their work */
+ if ( !sieve_validator_argument_activate_super
+ (valdtr, cmd, strarg, FALSE) ) {
+ result = FALSE;
+ break;
+ }
+ }
+
+ /* Find the variable */
+ if ( nelements == 1 ) {
+ const struct sieve_variable_name *cur_element =
+ array_idx(&substitution, 0);
+
+ if ( cur_element->num_variable == -1 ) {
+ /* Add variable argument '${identifier}' */
+
+ strarg = ext_variables_variable_argument_create
+ (this_ext, valdtr, *arg, str_c(cur_element->identifier));
+
+ } else {
+ /* Add match value argument '${000}' */
+
+ strarg = ext_variables_match_value_argument_create
+ (this_ext, valdtr, *arg, cur_element->num_variable);
+ }
+ } else {
+ strarg = ext_variables_namespace_argument_create
+ (this_ext, valdtr, *arg, cmd, &substitution);
+ }
+
+ if ( strarg != NULL )
+ sieve_arg_catenated_string_add_element(catstr, strarg);
+
+ strstart = p + 1;
+ substart = strstart;
+
+ p++;
+ }
+
+ /* Finished, reset for the next substitution */
+ state = ST_NONE;
+ }
+ }
+ } T_END;
+
+ /* Bail out early if substitution is invalid */
+ if ( !result ) return FALSE;
+
+ /* Check whether any substitutions were found */
+ if ( catstr == NULL ) {
+ /* No substitutions in this string, pass it on to any other substution
+ * extension.
+ */
+ return sieve_validator_argument_activate_super(valdtr, cmd, *arg, TRUE);
+ }
+
+ /* Add the final substring that comes after the last substitution to the
+ * variable-string AST.
+ */
+ if ( strend > strstart ) {
+ struct sieve_ast_argument *strarg;
+ string_t *newstr = str_new(pool, strend - strstart);
+ str_append_data(newstr, strstart, strend - strstart);
+
+ strarg = sieve_ast_argument_string_create_raw
+ ((*arg)->ast, newstr, (*arg)->source_line);
+ sieve_arg_catenated_string_add_element(catstr, strarg);
+
+ /* Give other substitution extensions a chance to do their work */
+ if ( !sieve_validator_argument_activate_super
+ (valdtr, cmd, strarg, FALSE) )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Variable argument interface
+ */
+
+static bool _sieve_variable_argument_activate
+(const struct sieve_extension *var_ext,
+ const struct sieve_extension *this_ext,
+ struct sieve_validator *valdtr, struct sieve_command *cmd,
+ struct sieve_ast_argument *arg, bool assignment)
+{
+ bool result = FALSE;
+ string_t *variable;
+ const char *varstr, *varend;
+ ARRAY_TYPE(sieve_variable_name) vname;
+ int nelements = 0;
+
+ T_BEGIN {
+ t_array_init(&vname, 2);
+
+ variable = sieve_ast_argument_str(arg);
+ varstr = str_c(variable);
+ varend = PTR_OFFSET(varstr, str_len(variable));
+ nelements = ext_variable_name_parse(&vname, &varstr, varend);
+
+ /* Check whether name parsing succeeded */
+ if ( nelements <= 0 || varstr != varend ) {
+ /* Parse failed */
+ sieve_argument_validate_error(valdtr, arg,
+ "invalid variable name '%s'", str_sanitize(str_c(variable),80));
+ } else if ( nelements == 1 ) {
+ /* Normal (match) variable */
+
+ const struct sieve_variable_name *cur_element =
+ array_idx(&vname, 0);
+
+ if ( cur_element->num_variable < 0 ) {
+ /* Variable */
+ result = ext_variables_variable_argument_activate(var_ext,
+ this_ext, valdtr, arg, str_c(cur_element->identifier));
+
+ } else {
+ /* Match value */
+ result = ext_variables_match_value_argument_activate
+ (this_ext, valdtr, arg, cur_element->num_variable, assignment);
+ }
+
+ } else {
+ /* Namespace variable */
+ result = ext_variables_namespace_argument_activate
+ (this_ext, valdtr, arg, cmd, &vname, assignment);
+ }
+ } T_END;
+
+ return result;
+}
+
+bool sieve_variable_argument_activate
+(const struct sieve_extension *var_ext,
+ const struct sieve_extension *this_ext,
+ struct sieve_validator *valdtr, struct sieve_command *cmd,
+ struct sieve_ast_argument *arg, bool assignment)
+{
+ if ( sieve_ast_argument_type(arg) == SAAT_STRING ) {
+ /* Single string */
+ return _sieve_variable_argument_activate(var_ext,
+ this_ext, valdtr, cmd, arg, assignment);
+
+ } else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) {
+ /* String list */
+ struct sieve_ast_argument *stritem;
+
+ i_assert ( !assignment );
+
+ stritem = sieve_ast_strlist_first(arg);
+ while ( stritem != NULL ) {
+ if ( !_sieve_variable_argument_activate(var_ext,
+ this_ext, valdtr, cmd, stritem, assignment) )
+ return FALSE;
+
+ stritem = sieve_ast_strlist_next(stritem);
+ }
+
+ arg->argument = sieve_argument_create
+ (arg->ast, &string_list_argument, NULL, 0);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-arguments.h b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-arguments.h
new file mode 100644
index 0000000..87413c8
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-arguments.h
@@ -0,0 +1,24 @@
+#ifndef EXT_VARIABLES_ARGUMENTS_H
+#define EXT_VARIABLES_ARGUMENTS_H
+
+#include "sieve-common.h"
+
+/*
+ * Variable argument
+ */
+
+extern const struct sieve_argument_def variable_argument;
+
+/*
+ * Match value argument
+ */
+
+extern const struct sieve_argument_def match_value_argument;
+
+/*
+ * Variable string argument
+ */
+
+extern const struct sieve_argument_def variable_string_argument;
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-common.c b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-common.c
new file mode 100644
index 0000000..be9f677
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-common.c
@@ -0,0 +1,950 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "hash.h"
+#include "str.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-settings.h"
+
+#include "sieve-ast.h"
+#include "sieve-binary.h"
+#include "sieve-code.h"
+#include "sieve-objects.h"
+#include "sieve-match-types.h"
+
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-dump.h"
+#include "sieve-interpreter.h"
+
+#include "ext-variables-common.h"
+#include "ext-variables-limits.h"
+#include "ext-variables-name.h"
+#include "ext-variables-modifiers.h"
+
+/*
+ * Limits
+ */
+
+unsigned int
+sieve_variables_get_max_scope_size(const struct sieve_extension *var_ext)
+{
+ const struct ext_variables_config *config =
+ ext_variables_get_config(var_ext);
+
+ return config->max_scope_size;
+}
+
+size_t
+sieve_variables_get_max_variable_size(const struct sieve_extension *var_ext)
+{
+ const struct ext_variables_config *config =
+ ext_variables_get_config(var_ext);
+
+ return config->max_variable_size;
+}
+
+/*
+ * Extension configuration
+ */
+
+bool
+ext_variables_load(const struct sieve_extension *ext, void **context)
+{
+ struct sieve_instance *svinst = ext->svinst;
+ struct ext_variables_config *config;
+ unsigned long long int uint_setting;
+ size_t size_setting;
+
+ if (*context != NULL)
+ ext_variables_unload(ext);
+
+ config = i_new(struct ext_variables_config, 1);
+
+ /* Get limits */
+ config->max_scope_size = EXT_VARIABLES_DEFAULT_MAX_SCOPE_SIZE;
+ config->max_variable_size = EXT_VARIABLES_DEFAULT_MAX_VARIABLE_SIZE;
+
+ if (sieve_setting_get_uint_value(
+ svinst, "sieve_variables_max_scope_size", &uint_setting)) {
+ if (uint_setting < EXT_VARIABLES_REQUIRED_MAX_SCOPE_SIZE) {
+ e_warning(svinst->event, "variables: "
+ "setting sieve_variables_max_scope_size "
+ "is lower than required by standards "
+ "(>= %llu items)",
+ (unsigned long long)EXT_VARIABLES_REQUIRED_MAX_SCOPE_SIZE);
+ } else {
+ config->max_scope_size = (unsigned int)uint_setting;
+ }
+ }
+
+ if (sieve_setting_get_size_value(
+ svinst, "sieve_variables_max_variable_size", &size_setting)) {
+ if (size_setting < EXT_VARIABLES_REQUIRED_MAX_VARIABLE_SIZE) {
+ e_warning(svinst->event, "variables: "
+ "setting sieve_variables_max_variable_size "
+ "is lower than required by standards "
+ "(>= %zu bytes)",
+ (size_t)EXT_VARIABLES_REQUIRED_MAX_VARIABLE_SIZE);
+ } else {
+ config->max_variable_size = size_setting;
+ }
+ }
+
+ *context = (void *)config;
+ return TRUE;
+}
+
+void ext_variables_unload(const struct sieve_extension *ext)
+{
+ struct ext_variables_config *config =
+ (struct ext_variables_config *)ext->context;
+
+ i_free(config);
+}
+
+const struct ext_variables_config *
+ext_variables_get_config(const struct sieve_extension *var_ext)
+{
+ const struct ext_variables_config *config =
+ (const struct ext_variables_config *)var_ext->context;
+
+ i_assert(var_ext->def == &variables_extension);
+ return config;
+}
+
+/*
+ * Variable scope
+ */
+
+struct sieve_variable_scope {
+ pool_t pool;
+ int refcount;
+
+ struct sieve_instance *svinst;
+ const struct sieve_extension *var_ext;
+ const struct sieve_extension *ext;
+
+ struct sieve_variable *error_var;
+
+ HASH_TABLE(const char *, struct sieve_variable *) variables;
+ ARRAY(struct sieve_variable *) variable_index;
+};
+
+struct sieve_variable_scope_binary {
+ struct sieve_variable_scope *scope;
+
+ unsigned int size;
+ struct sieve_binary_block *sblock;
+ sieve_size_t address;
+};
+
+struct sieve_variable_scope_iter {
+ struct sieve_variable_scope *scope;
+ struct hash_iterate_context *hctx;
+};
+
+struct sieve_variable_scope *
+sieve_variable_scope_create(struct sieve_instance *svinst,
+ const struct sieve_extension *var_ext,
+ const struct sieve_extension *ext)
+{
+ struct sieve_variable_scope *scope;
+ pool_t pool;
+
+ i_assert(var_ext->def == &variables_extension);
+
+ pool = pool_alloconly_create("sieve_variable_scope", 4096);
+ scope = p_new(pool, struct sieve_variable_scope, 1);
+ scope->pool = pool;
+ scope->refcount = 1;
+
+ scope->svinst = svinst;
+ scope->var_ext = var_ext;
+ scope->ext = ext;
+
+ hash_table_create(&scope->variables, pool, 0, strcase_hash, strcasecmp);
+ p_array_init(&scope->variable_index, pool, 128);
+
+ return scope;
+}
+
+void sieve_variable_scope_ref(struct sieve_variable_scope *scope)
+{
+ scope->refcount++;
+}
+
+void sieve_variable_scope_unref(struct sieve_variable_scope **_scope)
+{
+ struct sieve_variable_scope *scope = *_scope;
+
+ i_assert(scope->refcount > 0);
+
+ if (--scope->refcount != 0)
+ return;
+
+ hash_table_destroy(&scope->variables);
+
+ *_scope = NULL;
+ pool_unref(&scope->pool);
+}
+
+pool_t sieve_variable_scope_pool(struct sieve_variable_scope *scope)
+{
+ return scope->pool;
+}
+
+struct sieve_variable *
+sieve_variable_scope_declare(struct sieve_variable_scope *scope,
+ const char *identifier)
+{
+ unsigned int max_scope_size;
+ struct sieve_variable *var;
+
+ var = hash_table_lookup(scope->variables, identifier);
+ if (var != NULL)
+ return var;
+
+ max_scope_size = sieve_variables_get_max_scope_size(scope->var_ext);
+ if (array_count(&scope->variable_index) >= max_scope_size) {
+ if (scope->error_var == NULL) {
+ var = p_new(scope->pool, struct sieve_variable, 1);
+ var->identifier = "@ERROR@";
+ var->index = 0;
+
+ scope->error_var = var;
+ return NULL;
+ }
+
+ return scope->error_var;
+ }
+
+ var = p_new(scope->pool, struct sieve_variable, 1);
+ var->ext = scope->ext;
+ var->identifier = p_strdup(scope->pool, identifier);
+ var->index = array_count(&scope->variable_index);
+
+ hash_table_insert(scope->variables, var->identifier, var);
+ array_append(&scope->variable_index, &var, 1);
+ return var;
+}
+
+struct sieve_variable *
+sieve_variable_scope_get_variable(struct sieve_variable_scope *scope,
+ const char *identifier)
+{
+ return hash_table_lookup(scope->variables, identifier);
+}
+
+struct sieve_variable *
+sieve_variable_scope_import(struct sieve_variable_scope *scope,
+ struct sieve_variable *var)
+{
+ struct sieve_variable *old_var, *new_var;
+
+ old_var = sieve_variable_scope_get_variable(scope, var->identifier);
+ if (old_var != NULL) {
+ i_assert(memcmp(old_var, var, sizeof(*var)) == 0);
+ return old_var;
+ }
+
+ new_var = p_new(scope->pool, struct sieve_variable, 1);
+ memcpy(new_var, var, sizeof(*new_var));
+
+ hash_table_insert(scope->variables, new_var->identifier, new_var);
+
+ /* Not entered into the index because it is an external variable
+ (This can be done unlimited; only limited by the size of the external
+ scope)
+ */
+ return new_var;
+}
+
+struct sieve_variable_scope_iter *
+sieve_variable_scope_iterate_init(struct sieve_variable_scope *scope)
+{
+ struct sieve_variable_scope_iter *iter;
+
+ iter = t_new(struct sieve_variable_scope_iter, 1);
+ iter->scope = scope;
+ iter->hctx = hash_table_iterate_init(scope->variables);
+
+ return iter;
+}
+
+bool sieve_variable_scope_iterate(struct sieve_variable_scope_iter *iter,
+ struct sieve_variable **var_r)
+{
+ const char *key;
+
+ return hash_table_iterate(iter->hctx, iter->scope->variables,
+ &key, var_r);
+}
+
+void sieve_variable_scope_iterate_deinit(
+ struct sieve_variable_scope_iter **iter)
+{
+ hash_table_iterate_deinit(&(*iter)->hctx);
+ *iter = NULL;
+}
+
+unsigned int
+sieve_variable_scope_declarations(struct sieve_variable_scope *scope)
+{
+ return hash_table_count(scope->variables);
+}
+
+unsigned int sieve_variable_scope_size(struct sieve_variable_scope *scope)
+{
+ return array_count(&scope->variable_index);
+}
+
+struct sieve_variable * const *
+sieve_variable_scope_get_variables(struct sieve_variable_scope *scope,
+ unsigned int *size_r)
+{
+ return array_get(&scope->variable_index, size_r);
+}
+
+struct sieve_variable *
+sieve_variable_scope_get_indexed(struct sieve_variable_scope *scope,
+ unsigned int index)
+{
+ struct sieve_variable * const *var;
+
+ if (index >= array_count(&scope->variable_index))
+ return NULL;
+
+ var = array_idx(&scope->variable_index, index);
+ return *var;
+}
+
+/* Scope binary */
+
+struct sieve_variable_scope *
+sieve_variable_scope_binary_dump(struct sieve_instance *svinst,
+ const struct sieve_extension *var_ext,
+ const struct sieve_extension *ext,
+ const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ struct sieve_variable_scope *local_scope;
+ unsigned int i, scope_size;
+ sieve_size_t pc;
+ sieve_offset_t end_offset;
+
+ /* Read scope size */
+ sieve_code_mark(denv);
+ if (!sieve_binary_read_unsigned(denv->sblock, address, &scope_size))
+ return NULL;
+
+ /* Read offset */
+ pc = *address;
+ if (!sieve_binary_read_offset(denv->sblock, address, &end_offset))
+ return NULL;
+
+ /* Create scope */
+ local_scope = sieve_variable_scope_create(svinst, var_ext, ext);
+
+ /* Read and dump scope itself */
+
+ sieve_code_dumpf(denv, "VARIABLES SCOPE [%u] (end: %08x)",
+ scope_size, (unsigned int)(pc + end_offset));
+
+ for (i = 0; i < scope_size; i++) {
+ string_t *identifier;
+
+ sieve_code_mark(denv);
+ if (!sieve_binary_read_string(denv->sblock, address,
+ &identifier))
+ return NULL;
+
+ sieve_code_dumpf(denv, "%3d: '%s'", i, str_c(identifier));
+
+ (void)sieve_variable_scope_declare(local_scope,
+ str_c(identifier));
+ }
+
+ return local_scope;
+}
+
+struct sieve_variable_scope_binary *
+sieve_variable_scope_binary_create(struct sieve_variable_scope *scope)
+{
+ struct sieve_variable_scope_binary *scpbin;
+
+ scpbin = p_new(scope->pool, struct sieve_variable_scope_binary, 1);
+ scpbin->scope = scope;
+
+ return scpbin;
+}
+
+void sieve_variable_scope_binary_ref(struct sieve_variable_scope_binary *scpbin)
+{
+ sieve_variable_scope_ref(scpbin->scope);
+}
+
+void sieve_variable_scope_binary_unref(
+ struct sieve_variable_scope_binary **scpbin)
+{
+ sieve_variable_scope_unref(&(*scpbin)->scope);
+ *scpbin = NULL;
+}
+
+struct sieve_variable_scope_binary *
+sieve_variable_scope_binary_read(struct sieve_instance *svinst,
+ const struct sieve_extension *var_ext,
+ const struct sieve_extension *ext,
+ struct sieve_binary_block *sblock,
+ sieve_size_t *address)
+{
+ struct sieve_variable_scope *scope;
+ struct sieve_variable_scope_binary *scpbin;
+ unsigned int scope_size, max_scope_size;
+ const char *ext_name = (ext == NULL ? "variables" :
+ sieve_extension_name(ext));
+ sieve_size_t pc;
+ sieve_offset_t end_offset;
+
+ /* Read scope size */
+ if (!sieve_binary_read_unsigned(sblock, address, &scope_size)) {
+ e_error(svinst->event, "%s: "
+ "variable scope: failed to read size", ext_name);
+ return NULL;
+ }
+
+ /* Check size limit */
+ max_scope_size = sieve_variables_get_max_scope_size(var_ext);
+ if (scope_size > max_scope_size) {
+ e_error(svinst->event, "%s: "
+ "variable scope: size exceeds the limit (%u > %u)",
+ ext_name, scope_size, max_scope_size);
+ return NULL;
+ }
+
+ /* Read offset */
+ pc = *address;
+ if (!sieve_binary_read_offset(sblock, address, &end_offset)) {
+ e_error(svinst->event, "%s: "
+ "variable scope: failed to read end offset", ext_name);
+ return NULL;
+ }
+
+ /* Create scope */
+ scope = sieve_variable_scope_create(svinst, var_ext, ext);
+
+ scpbin = sieve_variable_scope_binary_create(scope);
+ scpbin->size = scope_size;
+ scpbin->sblock = sblock;
+ scpbin->address = *address;
+
+ *address = pc + end_offset;
+
+ return scpbin;
+}
+
+struct sieve_variable_scope *
+sieve_variable_scope_binary_get(struct sieve_variable_scope_binary *scpbin)
+{
+ const struct sieve_extension *ext = scpbin->scope->ext;
+ struct sieve_instance *svinst = scpbin->scope->svinst;
+ const char *ext_name = (ext == NULL ? "variables" :
+ sieve_extension_name(ext));
+ unsigned int i;
+
+ if (scpbin->sblock != NULL) {
+ sieve_size_t *address = &scpbin->address;
+
+ /* Read scope itself */
+ for (i = 0; i < scpbin->size; i++) {
+ struct sieve_variable *var;
+ string_t *identifier;
+
+ if (!sieve_binary_read_string(scpbin->sblock, address,
+ &identifier)) {
+ e_error(svinst->event, "%s: variable scope: "
+ "failed to read variable name",
+ ext_name);
+ return NULL;
+ }
+
+ var = sieve_variable_scope_declare(scpbin->scope,
+ str_c(identifier));
+
+ i_assert(var != NULL);
+ i_assert(var->index == i);
+ }
+
+ scpbin->sblock = NULL;
+ }
+
+ return scpbin->scope;
+}
+
+unsigned int
+sieve_variable_scope_binary_get_size(
+ struct sieve_variable_scope_binary *scpbin)
+{
+ if (scpbin->sblock != NULL)
+ return scpbin->size;
+
+ return array_count(&scpbin->scope->variable_index);
+}
+
+/*
+ * Variable storage
+ */
+
+struct sieve_variable_storage {
+ pool_t pool;
+ const struct sieve_extension *var_ext;
+ struct sieve_variable_scope *scope;
+ struct sieve_variable_scope_binary *scope_bin;
+ unsigned int max_size;
+ ARRAY(string_t *) var_values;
+};
+
+struct sieve_variable_storage *
+sieve_variable_storage_create(const struct sieve_extension *var_ext,
+ pool_t pool,
+ struct sieve_variable_scope_binary *scpbin)
+{
+ struct sieve_variable_storage *storage;
+
+ storage = p_new(pool, struct sieve_variable_storage, 1);
+ storage->pool = pool;
+ storage->var_ext = var_ext;
+ storage->scope_bin = scpbin;
+ storage->scope = NULL;
+
+ storage->max_size = sieve_variable_scope_binary_get_size(scpbin);
+
+ p_array_init(&storage->var_values, pool, 4);
+
+ return storage;
+}
+
+static inline bool
+sieve_variable_valid(struct sieve_variable_storage *storage,
+ unsigned int index)
+{
+ if (storage->scope_bin == NULL)
+ return TRUE;
+
+ return (index < storage->max_size);
+}
+
+bool sieve_variable_get_identifier(struct sieve_variable_storage *storage,
+ unsigned int index, const char **identifier)
+{
+ struct sieve_variable * const *var;
+
+ *identifier = NULL;
+
+ if (storage->scope_bin == NULL)
+ return TRUE;
+
+ if (storage->scope == NULL) {
+ storage->scope =
+ sieve_variable_scope_binary_get(storage->scope_bin);
+ if (storage->scope == NULL)
+ return FALSE;
+ }
+
+ /* FIXME: direct invasion of the scope object is a bit ugly */
+ if (index >= array_count(&storage->scope->variable_index))
+ return FALSE;
+
+ var = array_idx(&storage->scope->variable_index, index);
+ if (*var != NULL)
+ *identifier = (*var)->identifier;
+ return TRUE;
+}
+
+const char *
+sieve_variable_get_varid(struct sieve_variable_storage *storage,
+ unsigned int index)
+{
+ if (storage->scope_bin == NULL)
+ return t_strdup_printf("%ld", (long)index);
+
+ if (storage->scope == NULL) {
+ storage->scope =
+ sieve_variable_scope_binary_get(storage->scope_bin);
+ if (storage->scope == NULL)
+ return NULL;
+ }
+
+ return sieve_ext_variables_get_varid(storage->scope->ext, index);
+}
+
+bool sieve_variable_get(struct sieve_variable_storage *storage,
+ unsigned int index, string_t **value)
+{
+ *value = NULL;
+
+ if (index < array_count(&storage->var_values)) {
+ string_t * const *varent;
+
+ varent = array_idx(&storage->var_values, index);
+
+ *value = *varent;
+ } else if (!sieve_variable_valid(storage, index)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+bool sieve_variable_get_modifiable(struct sieve_variable_storage *storage,
+ unsigned int index, string_t **value)
+{
+ string_t *dummy;
+
+ if (value == NULL)
+ value = &dummy;
+
+ if (!sieve_variable_get(storage, index, value))
+ return FALSE;
+
+ if (*value == NULL) {
+ *value = str_new(storage->pool, 256);
+ array_idx_set(&storage->var_values, index, value);
+ }
+ return TRUE;
+}
+
+bool sieve_variable_assign(struct sieve_variable_storage *storage,
+ unsigned int index, const string_t *value)
+{
+ const struct ext_variables_config *config =
+ ext_variables_get_config(storage->var_ext);
+ string_t *varval;
+
+ if (!sieve_variable_get_modifiable(storage, index, &varval))
+ return FALSE;
+
+ str_truncate(varval, 0);
+ str_append_str(varval, value);
+
+ /* Just a precaution, caller should prevent this in the first place */
+ if (str_len(varval) > config->max_variable_size)
+ str_truncate_utf8(varval, config->max_variable_size);
+
+ return TRUE;
+}
+
+bool sieve_variable_assign_cstr(struct sieve_variable_storage *storage,
+ unsigned int index, const char *value)
+{
+ const struct ext_variables_config *config =
+ ext_variables_get_config(storage->var_ext);
+ string_t *varval;
+
+ if (!sieve_variable_get_modifiable(storage, index, &varval))
+ return FALSE;
+
+ str_truncate(varval, 0);
+ str_append(varval, value);
+
+ /* Just a precaution, caller should prevent this in the first place */
+ if (str_len(varval) > config->max_variable_size)
+ str_truncate_utf8(varval, config->max_variable_size);
+
+ return TRUE;
+}
+
+/*
+ * AST Context
+ */
+
+static void
+ext_variables_ast_free(const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_ast *ast ATTR_UNUSED, void *context)
+{
+ struct sieve_variable_scope *local_scope =
+ (struct sieve_variable_scope *)context;
+
+ /* Unreference main variable scope */
+ sieve_variable_scope_unref(&local_scope);
+}
+
+static const struct sieve_ast_extension variables_ast_extension = {
+ &variables_extension,
+ ext_variables_ast_free
+};
+
+static struct sieve_variable_scope *
+ext_variables_create_local_scope(const struct sieve_extension *this_ext,
+ struct sieve_ast *ast)
+{
+ struct sieve_variable_scope *scope;
+
+ scope = sieve_variable_scope_create(this_ext->svinst, this_ext, NULL);
+
+ sieve_ast_extension_register(ast, this_ext, &variables_ast_extension,
+ (void *)scope);
+ return scope;
+}
+
+static struct sieve_variable_scope *
+ext_variables_ast_get_local_scope(const struct sieve_extension *this_ext,
+ struct sieve_ast *ast)
+{
+ struct sieve_variable_scope *local_scope =
+ (struct sieve_variable_scope *)
+ sieve_ast_extension_get_context(ast, this_ext);
+
+ return local_scope;
+}
+
+/*
+ * Validator context
+ */
+
+static struct ext_variables_validator_context *
+ext_variables_validator_context_create(const struct sieve_extension *this_ext,
+ struct sieve_validator *valdtr)
+{
+ pool_t pool = sieve_validator_pool(valdtr);
+ struct ext_variables_validator_context *ctx;
+ struct sieve_ast *ast = sieve_validator_ast(valdtr);
+
+ ctx = p_new(pool, struct ext_variables_validator_context, 1);
+ ctx->modifiers = sieve_validator_object_registry_create(valdtr);
+ ctx->namespaces = sieve_validator_object_registry_create(valdtr);
+ ctx->local_scope = ext_variables_create_local_scope(this_ext, ast);
+
+ sieve_validator_extension_set_context(valdtr, this_ext, (void *)ctx);
+ return ctx;
+}
+
+struct ext_variables_validator_context *
+ext_variables_validator_context_get(const struct sieve_extension *this_ext,
+ struct sieve_validator *valdtr)
+{
+ struct ext_variables_validator_context *ctx;
+
+ i_assert(sieve_extension_is(this_ext, variables_extension));
+ ctx = (struct ext_variables_validator_context *)
+ sieve_validator_extension_get_context(valdtr, this_ext);
+
+ if (ctx == NULL)
+ ctx = ext_variables_validator_context_create(this_ext, valdtr);
+ return ctx;
+}
+
+void ext_variables_validator_initialize(const struct sieve_extension *this_ext,
+ struct sieve_validator *valdtr)
+{
+ struct ext_variables_validator_context *ctx;
+
+ /* Create our context */
+ ctx = ext_variables_validator_context_get(this_ext, valdtr);
+
+ ext_variables_register_core_modifiers(this_ext, ctx);
+
+ ctx->active = TRUE;
+}
+
+struct sieve_variable *ext_variables_validator_get_variable(
+ const struct sieve_extension *this_ext,
+ struct sieve_validator *validator, const char *variable)
+{
+ struct ext_variables_validator_context *ctx =
+ ext_variables_validator_context_get(this_ext, validator);
+
+ return sieve_variable_scope_get_variable(ctx->local_scope, variable);
+}
+
+struct sieve_variable *
+ext_variables_validator_declare_variable(const struct sieve_extension *this_ext,
+ struct sieve_validator *validator,
+ const char *variable)
+{
+ struct ext_variables_validator_context *ctx =
+ ext_variables_validator_context_get(this_ext, validator);
+
+ return sieve_variable_scope_declare(ctx->local_scope, variable);
+}
+
+struct sieve_variable_scope *
+sieve_ext_variables_get_local_scope(const struct sieve_extension *var_ext,
+ struct sieve_validator *validator)
+{
+ struct ext_variables_validator_context *ctx =
+ ext_variables_validator_context_get(var_ext, validator);
+
+ return ctx->local_scope;
+}
+
+bool sieve_ext_variables_is_active(const struct sieve_extension *var_ext,
+ struct sieve_validator *valdtr)
+{
+ struct ext_variables_validator_context *ctx =
+ ext_variables_validator_context_get(var_ext, valdtr);
+
+ return (ctx != NULL && ctx->active);
+}
+
+/*
+ * Code generation
+ */
+
+bool ext_variables_generator_load(const struct sieve_extension *ext,
+ const struct sieve_codegen_env *cgenv)
+{
+ struct sieve_variable_scope *local_scope =
+ ext_variables_ast_get_local_scope(ext, cgenv->ast);
+ unsigned int count = sieve_variable_scope_size(local_scope);
+ sieve_size_t jump;
+
+ sieve_binary_emit_unsigned(cgenv->sblock, count);
+
+ jump = sieve_binary_emit_offset(cgenv->sblock, 0);
+
+ if (count > 0) {
+ unsigned int size, i;
+ struct sieve_variable *const *vars =
+ sieve_variable_scope_get_variables(local_scope, &size);
+
+ for (i = 0; i < size; i++) {
+ sieve_binary_emit_cstring(cgenv->sblock,
+ vars[i]->identifier);
+ }
+ }
+
+ sieve_binary_resolve_offset(cgenv->sblock, jump);
+ return TRUE;
+}
+
+/*
+ * Interpreter context
+ */
+
+struct ext_variables_interpreter_context {
+ pool_t pool;
+
+ struct sieve_variable_scope *local_scope;
+ struct sieve_variable_scope_binary *local_scope_bin;
+
+ struct sieve_variable_storage *local_storage;
+ ARRAY(struct sieve_variable_storage *) ext_storages;
+};
+
+static void
+ext_variables_interpreter_free(const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_interpreter *interp ATTR_UNUSED,
+ void *context)
+{
+ struct ext_variables_interpreter_context *ctx =
+ (struct ext_variables_interpreter_context *)context;
+
+ sieve_variable_scope_binary_unref(&ctx->local_scope_bin);
+}
+
+static struct sieve_interpreter_extension
+variables_interpreter_extension = {
+ .ext_def = &variables_extension,
+ .free = ext_variables_interpreter_free
+};
+
+static struct ext_variables_interpreter_context *
+ext_variables_interpreter_context_create(
+ const struct sieve_extension *this_ext,
+ struct sieve_interpreter *interp,
+ struct sieve_variable_scope_binary *scpbin)
+{
+ pool_t pool = sieve_interpreter_pool(interp);
+ struct ext_variables_interpreter_context *ctx;
+
+ ctx = p_new(pool, struct ext_variables_interpreter_context, 1);
+ ctx->pool = pool;
+ ctx->local_scope = NULL;
+ ctx->local_scope_bin = scpbin;
+ ctx->local_storage =
+ sieve_variable_storage_create(this_ext, pool, scpbin);
+ p_array_init(&ctx->ext_storages, pool,
+ sieve_extensions_get_count(this_ext->svinst));
+
+ sieve_interpreter_extension_register(interp, this_ext,
+ &variables_interpreter_extension,
+ (void *)ctx);
+ return ctx;
+}
+
+bool ext_variables_interpreter_load(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ struct sieve_variable_scope_binary *scpbin;
+
+ scpbin = sieve_variable_scope_binary_read(eenv->svinst, ext, NULL,
+ renv->sblock, address);
+ if (scpbin == NULL)
+ return FALSE;
+
+ /* Create our context */
+ (void)ext_variables_interpreter_context_create(ext, renv->interp,
+ scpbin);
+
+ /* Enable support for match values */
+ (void)sieve_match_values_set_enabled(renv, TRUE);
+
+ return TRUE;
+}
+
+static inline struct ext_variables_interpreter_context *
+ext_variables_interpreter_context_get(const struct sieve_extension *this_ext,
+ struct sieve_interpreter *interp)
+{
+ struct ext_variables_interpreter_context *ctx;
+
+ i_assert(sieve_extension_is(this_ext, variables_extension));
+ ctx = (struct ext_variables_interpreter_context *)
+ sieve_interpreter_extension_get_context(interp, this_ext);
+ return ctx;
+}
+
+struct sieve_variable_storage *
+sieve_ext_variables_runtime_get_storage(const struct sieve_extension *var_ext,
+ const struct sieve_runtime_env *renv,
+ const struct sieve_extension *ext)
+{
+ struct ext_variables_interpreter_context *ctx =
+ ext_variables_interpreter_context_get(var_ext, renv->interp);
+ struct sieve_variable_storage * const *storage;
+
+ if (ext == NULL)
+ return ctx->local_storage;
+
+ if (ext->id >= (int)array_count(&ctx->ext_storages))
+ storage = NULL;
+ else
+ storage = array_idx(&ctx->ext_storages, ext->id);
+
+ if (storage == NULL)
+ return NULL;
+ return *storage;
+}
+
+void sieve_ext_variables_runtime_set_storage(
+ const struct sieve_extension *var_ext,
+ const struct sieve_runtime_env *renv, const struct sieve_extension *ext,
+ struct sieve_variable_storage *storage)
+{
+ struct ext_variables_interpreter_context *ctx =
+ ext_variables_interpreter_context_get(var_ext, renv->interp);
+
+ if (ctx == NULL || ext == NULL || storage == NULL)
+ return;
+ if (ext->id < 0)
+ return;
+
+ array_idx_set(&ctx->ext_storages, (unsigned int) ext->id, &storage);
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-common.h b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-common.h
new file mode 100644
index 0000000..401d943
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-common.h
@@ -0,0 +1,102 @@
+#ifndef EXT_VARIABLES_COMMON_H
+#define EXT_VARIABLES_COMMON_H
+
+#include "sieve-common.h"
+#include "sieve-validator.h"
+
+#include "sieve-ext-variables.h"
+
+/*
+ * Extension
+ */
+
+struct ext_variables_config {
+ /* Maximum number of variables (in a scope) */
+ unsigned int max_scope_size;
+ /* Maximum size of variable value */
+ size_t max_variable_size;
+};
+
+extern const struct sieve_extension_def variables_extension;
+
+bool ext_variables_load(const struct sieve_extension *ext, void **context);
+void ext_variables_unload(const struct sieve_extension *ext);
+
+const struct ext_variables_config *
+ext_variables_get_config(const struct sieve_extension *var_ext);
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def cmd_set;
+extern const struct sieve_command_def tst_string;
+
+/*
+ * Operands
+ */
+
+enum ext_variables_operand {
+ EXT_VARIABLES_OPERAND_VARIABLE,
+ EXT_VARIABLES_OPERAND_MATCH_VALUE,
+ EXT_VARIABLES_OPERAND_NAMESPACE_VARIABLE,
+ EXT_VARIABLES_OPERAND_MODIFIER
+};
+
+/*
+ * Operations
+ */
+
+extern const struct sieve_operation_def cmd_set_operation;
+extern const struct sieve_operation_def tst_string_operation;
+
+enum ext_variables_opcode {
+ EXT_VARIABLES_OPERATION_SET,
+ EXT_VARIABLES_OPERATION_STRING
+};
+
+/*
+ * Validator context
+ */
+
+struct ext_variables_validator_context {
+ bool active;
+
+ struct sieve_validator_object_registry *modifiers;
+ struct sieve_validator_object_registry *namespaces;
+
+ struct sieve_variable_scope *local_scope;
+};
+
+void ext_variables_validator_initialize(const struct sieve_extension *this_ext,
+ struct sieve_validator *validator);
+
+struct ext_variables_validator_context *
+ext_variables_validator_context_get(const struct sieve_extension *this_ext,
+ struct sieve_validator *valdtr);
+
+struct sieve_variable *
+ext_variables_validator_get_variable(const struct sieve_extension *this_ext,
+ struct sieve_validator *validator,
+ const char *variable);
+struct sieve_variable *
+ext_variables_validator_declare_variable(const struct sieve_extension *this_ext,
+ struct sieve_validator *validator,
+ const char *variable);
+
+/*
+ * Code generation
+ */
+
+bool ext_variables_generator_load(const struct sieve_extension *ext,
+ const struct sieve_codegen_env *cgenv);
+
+/*
+ * Interpreter context
+ */
+
+bool ext_variables_interpreter_load(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-dump.c b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-dump.c
new file mode 100644
index 0000000..26bd015
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-dump.c
@@ -0,0 +1,137 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve-common.h"
+#include "sieve-dump.h"
+#include "sieve-binary.h"
+#include "sieve-code.h"
+
+#include "ext-variables-common.h"
+#include "ext-variables-dump.h"
+
+/*
+ * Code dumper extension
+ */
+
+static void ext_variables_code_dumper_free
+ (struct sieve_code_dumper *dumper, void *context);
+
+static const struct sieve_code_dumper_extension
+variables_dump_extension = {
+ &variables_extension,
+ ext_variables_code_dumper_free
+};
+
+/*
+ * Code dump context
+ */
+
+struct ext_variables_dump_context {
+ struct sieve_variable_scope *local_scope;
+ ARRAY(struct sieve_variable_scope *) ext_scopes;
+};
+
+static void ext_variables_code_dumper_free
+(struct sieve_code_dumper *dumper ATTR_UNUSED, void *context)
+{
+ struct ext_variables_dump_context *dctx =
+ (struct ext_variables_dump_context *) context;
+
+ if ( dctx == NULL || dctx->local_scope == NULL )
+ return;
+
+ sieve_variable_scope_unref(&dctx->local_scope);
+}
+
+static struct ext_variables_dump_context *ext_variables_dump_get_context
+(const struct sieve_extension *this_ext, const struct sieve_dumptime_env *denv)
+{
+ struct sieve_code_dumper *dumper = denv->cdumper;
+ struct ext_variables_dump_context *dctx;
+ pool_t pool;
+
+ i_assert( sieve_extension_is(this_ext, variables_extension) );
+ dctx = sieve_dump_extension_get_context(dumper, this_ext);
+
+ if ( dctx == NULL ) {
+ /* Create dumper context */
+ pool = sieve_code_dumper_pool(dumper);
+ dctx = p_new(pool, struct ext_variables_dump_context, 1);
+ p_array_init(&dctx->ext_scopes, pool,
+ sieve_extensions_get_count(this_ext->svinst));
+
+ sieve_dump_extension_register
+ (dumper, this_ext, &variables_dump_extension, dctx);
+ }
+
+ return dctx;
+}
+
+bool ext_variables_code_dump
+(const struct sieve_extension *ext,
+ const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ struct ext_variables_dump_context *dctx;
+ struct sieve_variable_scope *local_scope;
+
+ local_scope = sieve_variable_scope_binary_dump
+ (ext->svinst, ext, NULL, denv, address);
+
+ dctx = ext_variables_dump_get_context(ext, denv);
+ dctx->local_scope = local_scope;
+
+ return TRUE;
+}
+
+/*
+ * Scope registry
+ */
+
+void sieve_ext_variables_dump_set_scope
+(const struct sieve_extension *var_ext, const struct sieve_dumptime_env *denv,
+ const struct sieve_extension *ext, struct sieve_variable_scope *scope)
+{
+ struct ext_variables_dump_context *dctx =
+ ext_variables_dump_get_context(var_ext, denv);
+
+ if ( ext->id < 0 ) return;
+
+ array_idx_set(&dctx->ext_scopes, (unsigned int) ext->id, &scope);
+}
+
+/*
+ * Variable identifier dump
+ */
+
+const char *ext_variables_dump_get_identifier
+(const struct sieve_extension *var_ext, const struct sieve_dumptime_env *denv,
+ const struct sieve_extension *ext, unsigned int index)
+{
+ struct ext_variables_dump_context *dctx =
+ ext_variables_dump_get_context(var_ext, denv);
+ struct sieve_variable_scope *scope;
+ struct sieve_variable *var;
+
+ if ( ext == NULL )
+ scope = dctx->local_scope;
+ else {
+ struct sieve_variable_scope *const *ext_scope;
+
+ if ( ext->id < 0 || ext->id >= (int) array_count(&dctx->ext_scopes) )
+ return NULL;
+
+ ext_scope = array_idx(&dctx->ext_scopes, (unsigned int) ext->id);
+ scope = *ext_scope;
+ }
+
+ if ( scope == NULL )
+ return NULL;
+
+ var = sieve_variable_scope_get_indexed(scope, index);
+
+ return var->identifier;
+}
+
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-dump.h b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-dump.h
new file mode 100644
index 0000000..da72a5d
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-dump.h
@@ -0,0 +1,22 @@
+#ifndef EXT_VARIABLES_DUMP_H
+#define EXT_VARIABLES_DUMP_H
+
+#include "sieve-common.h"
+
+/*
+ * Code dump context
+ */
+
+bool ext_variables_code_dump
+ (const struct sieve_extension *ext, const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+
+/*
+ * Variable identifier dump
+ */
+
+const char *ext_variables_dump_get_identifier
+(const struct sieve_extension *var_ext, const struct sieve_dumptime_env *denv,
+ const struct sieve_extension *ext, unsigned int index);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-limits.h b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-limits.h
new file mode 100644
index 0000000..61260c8
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-limits.h
@@ -0,0 +1,35 @@
+#ifndef EXT_VARIABLES_LIMITS_H
+#define EXT_VARIABLES_LIMITS_H
+
+#include "sieve-limits.h"
+
+/* From RFC 5229:
+ *
+ * 6. Implementation Limits
+ *
+ * An implementation of this document MUST support at least 128 distinct
+ * variables. The supported length of variable names MUST be at least
+ * 32 characters. Each variable MUST be able to hold at least 4000
+ * characters. Attempts to set the variable to a value larger than what
+ * the implementation supports SHOULD be reported as an error at
+ * compile-time if possible. If the attempt is discovered during run-
+ * time, the value SHOULD be truncated, and it MUST NOT be treated as an
+ * error.
+
+ * Match variables ${1} through ${9} MUST be supported. References to
+ * higher indices than those the implementation supports MUST be treated
+ * as a syntax error, which SHOULD be discovered at compile-time.
+ */
+
+#define EXT_VARIABLES_DEFAULT_MAX_SCOPE_SIZE 255
+#define EXT_VARIABLES_DEFAULT_MAX_VARIABLE_SIZE (4 * 1024)
+
+#define EXT_VARIABLES_REQUIRED_MAX_SCOPE_SIZE 128
+#define EXT_VARIABLES_REQUIRED_MAX_VARIABLE_SIZE 4000
+
+#define EXT_VARIABLES_MAX_VARIABLE_NAME_LEN 64
+#define EXT_VARIABLES_MAX_NAMESPACE_ELEMENTS 10
+
+#define EXT_VARIABLES_MAX_MATCH_INDEX SIEVE_MAX_MATCH_VALUES
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-modifiers.c b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-modifiers.c
new file mode 100644
index 0000000..dd21c88
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-modifiers.c
@@ -0,0 +1,578 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "unichar.h"
+#include "str-sanitize.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-runtime.h"
+
+#include "ext-variables-common.h"
+#include "ext-variables-limits.h"
+#include "ext-variables-modifiers.h"
+
+#include <ctype.h>
+
+/*
+ * Core modifiers
+ */
+
+extern const struct sieve_variables_modifier_def lower_modifier;
+extern const struct sieve_variables_modifier_def upper_modifier;
+extern const struct sieve_variables_modifier_def lowerfirst_modifier;
+extern const struct sieve_variables_modifier_def upperfirst_modifier;
+extern const struct sieve_variables_modifier_def quotewildcard_modifier;
+extern const struct sieve_variables_modifier_def length_modifier;
+
+enum ext_variables_modifier_code {
+ EXT_VARIABLES_MODIFIER_LOWER,
+ EXT_VARIABLES_MODIFIER_UPPER,
+ EXT_VARIABLES_MODIFIER_LOWERFIRST,
+ EXT_VARIABLES_MODIFIER_UPPERFIRST,
+ EXT_VARIABLES_MODIFIER_QUOTEWILDCARD,
+ EXT_VARIABLES_MODIFIER_LENGTH
+};
+
+const struct sieve_variables_modifier_def *ext_variables_core_modifiers[] = {
+ &lower_modifier,
+ &upper_modifier,
+ &lowerfirst_modifier,
+ &upperfirst_modifier,
+ &quotewildcard_modifier,
+ &length_modifier
+};
+
+const unsigned int ext_variables_core_modifiers_count =
+ N_ELEMENTS(ext_variables_core_modifiers);
+
+#define ext_variables_modifier_name(modf) \
+ (modf)->object->def->name
+#define ext_variables_modifiers_equal(modf1, modf2) \
+ ( (modf1)->def == (modf2)->def )
+#define ext_variables_modifiers_equal_precedence(modf1, modf2) \
+ ( (modf1)->def->precedence == (modf2)->def->precendence )
+
+/*
+ * Modifier registry
+ */
+
+void sieve_variables_modifier_register
+(const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ const struct sieve_variables_modifier_def *smodf_def)
+{
+ struct ext_variables_validator_context *ctx =
+ ext_variables_validator_context_get(var_ext, valdtr);
+
+ sieve_validator_object_registry_add(ctx->modifiers, ext, &smodf_def->obj_def);
+}
+
+bool ext_variables_modifier_exists
+(const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
+ const char *identifier)
+{
+ struct ext_variables_validator_context *ctx =
+ ext_variables_validator_context_get(var_ext, valdtr);
+
+ return sieve_validator_object_registry_find(ctx->modifiers, identifier, NULL);
+}
+
+const struct sieve_variables_modifier *ext_variables_modifier_create_instance
+(const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
+ struct sieve_command *cmd, const char *identifier)
+{
+ struct ext_variables_validator_context *ctx =
+ ext_variables_validator_context_get(var_ext, valdtr);
+ struct sieve_object object;
+ struct sieve_variables_modifier *modf;
+ pool_t pool;
+
+ if ( !sieve_validator_object_registry_find
+ (ctx->modifiers, identifier, &object) )
+ return NULL;
+
+ pool = sieve_command_pool(cmd);
+ modf = p_new(pool, struct sieve_variables_modifier, 1);
+ modf->object = object;
+ modf->var_ext = var_ext;
+ modf->def = (const struct sieve_variables_modifier_def *) object.def;
+
+ return modf;
+}
+
+void ext_variables_register_core_modifiers
+(const struct sieve_extension *ext, struct ext_variables_validator_context *ctx)
+{
+ unsigned int i;
+
+ /* Register core modifiers*/
+ for ( i = 0; i < ext_variables_core_modifiers_count; i++ ) {
+ sieve_validator_object_registry_add
+ (ctx->modifiers, ext, &(ext_variables_core_modifiers[i]->obj_def));
+ }
+}
+
+/*
+ * Core modifiers
+ */
+
+/* Forward declarations */
+
+static bool
+mod_lower_modify(const struct sieve_variables_modifier *modf,
+ string_t *in, string_t **result);
+static bool
+mod_upper_modify(const struct sieve_variables_modifier *modf,
+ string_t *in, string_t **result);
+static bool
+mod_lowerfirst_modify(const struct sieve_variables_modifier *modf,
+ string_t *in, string_t **result);
+static bool
+mod_upperfirst_modify(const struct sieve_variables_modifier *modf,
+ string_t *in, string_t **result);
+static bool
+mod_length_modify(const struct sieve_variables_modifier *modf,
+ string_t *in, string_t **result);
+static bool
+mod_quotewildcard_modify(const struct sieve_variables_modifier *modf,
+ string_t *in, string_t **result);
+
+/* Modifier objects */
+
+const struct sieve_variables_modifier_def lower_modifier = {
+ SIEVE_OBJECT("lower", &modifier_operand, EXT_VARIABLES_MODIFIER_LOWER),
+ 40,
+ mod_lower_modify
+};
+
+const struct sieve_variables_modifier_def upper_modifier = {
+ SIEVE_OBJECT("upper", &modifier_operand, EXT_VARIABLES_MODIFIER_UPPER),
+ 40,
+ mod_upper_modify
+};
+
+const struct sieve_variables_modifier_def lowerfirst_modifier = {
+ SIEVE_OBJECT
+ ("lowerfirst", &modifier_operand, EXT_VARIABLES_MODIFIER_LOWERFIRST),
+ 30,
+ mod_lowerfirst_modify
+};
+
+const struct sieve_variables_modifier_def upperfirst_modifier = {
+ SIEVE_OBJECT
+ ("upperfirst", &modifier_operand, EXT_VARIABLES_MODIFIER_UPPERFIRST),
+ 30,
+ mod_upperfirst_modify
+};
+
+const struct sieve_variables_modifier_def quotewildcard_modifier = {
+ SIEVE_OBJECT
+ ("quotewildcard", &modifier_operand, EXT_VARIABLES_MODIFIER_QUOTEWILDCARD),
+ 20,
+ mod_quotewildcard_modify
+};
+
+const struct sieve_variables_modifier_def length_modifier = {
+ SIEVE_OBJECT("length", &modifier_operand, EXT_VARIABLES_MODIFIER_LENGTH),
+ 10,
+ mod_length_modify
+};
+
+/* Modifier implementations */
+
+static bool
+mod_upperfirst_modify(const struct sieve_variables_modifier *modf ATTR_UNUSED,
+ string_t *in, string_t **result)
+{
+ char *content;
+
+ if ( str_len(in) == 0 ) {
+ *result = in;
+ return TRUE;
+ }
+
+ *result = t_str_new(str_len(in));
+ str_append_str(*result, in);
+
+ content = str_c_modifiable(*result);
+ content[0] = i_toupper(content[0]);
+
+ return TRUE;
+}
+
+static bool
+mod_lowerfirst_modify(const struct sieve_variables_modifier *modf ATTR_UNUSED,
+ string_t *in, string_t **result)
+{
+ char *content;
+
+ if ( str_len(in) == 0 ) {
+ *result = in;
+ return TRUE;
+ }
+
+ *result = t_str_new(str_len(in));
+ str_append_str(*result, in);
+
+ content = str_c_modifiable(*result);
+ content[0] = i_tolower(content[0]);
+
+ return TRUE;
+}
+
+static bool
+mod_upper_modify(const struct sieve_variables_modifier *modf ATTR_UNUSED,
+ string_t *in, string_t **result)
+{
+ char *content;
+
+ if ( str_len(in) == 0 ) {
+ *result = in;
+ return TRUE;
+ }
+
+ *result = t_str_new(str_len(in));
+ str_append_str(*result, in);
+
+ content = str_c_modifiable(*result);
+ (void)str_ucase(content);
+
+ return TRUE;
+}
+
+static bool
+mod_lower_modify(const struct sieve_variables_modifier *modf ATTR_UNUSED,
+ string_t *in, string_t **result)
+{
+ char *content;
+
+ if ( str_len(in) == 0 ) {
+ *result = in;
+ return TRUE;
+ }
+
+ *result = t_str_new(str_len(in));
+ str_append_str(*result, in);
+
+ content = str_c_modifiable(*result);
+ (void)str_lcase(content);
+
+ return TRUE;
+}
+
+static bool
+mod_length_modify(const struct sieve_variables_modifier *modf ATTR_UNUSED,
+ string_t *in, string_t **result)
+{
+ *result = t_str_new(64);
+ str_printfa(*result, "%llu", (unsigned long long)
+ uni_utf8_strlen_n(str_data(in), str_len(in)));
+ return TRUE;
+}
+
+static bool
+mod_quotewildcard_modify(const struct sieve_variables_modifier *modf,
+ string_t *in, string_t **result)
+{
+ size_t max_var_size =
+ sieve_variables_get_max_variable_size(modf->var_ext);
+ const unsigned char *p, *poff, *pend;
+ size_t new_size;
+
+ if ( str_len(in) == 0 ) {
+ /* empty string */
+ *result = in;
+ return TRUE;
+ }
+
+ /* allocate new string */
+ new_size = str_len(in) + 16;
+ if (new_size > max_var_size)
+ new_size = max_var_size;
+ *result = t_str_new(new_size + 1);
+
+ /* escape string */
+ p = str_data(in);
+ pend = p + str_len(in);
+ poff = p;
+ while (p < pend) {
+ unsigned int n = uni_utf8_char_bytes((char)*p);
+
+ if (n == 1 && (*p == '*' || *p == '?' || *p == '\\')) {
+ str_append_data(*result, poff, p - poff);
+ poff = p;
+
+ if (str_len(*result) + 2 > max_var_size)
+ break;
+
+ str_append_c(*result, '\\');
+ } else if ((str_len(*result) + (p - poff) + n) > max_var_size) {
+ break;
+ }
+ if (p + n > pend) {
+ p = pend;
+ break;
+ }
+ p += n;
+ }
+
+ str_append_data(*result, poff, p - poff);
+
+ return TRUE;
+}
+
+/*
+ * Modifier argument
+ */
+
+/* [MODIFIER]:
+ * ":lower" / ":upper" / ":lowerfirst" / ":upperfirst" /
+ * ":quotewildcard" / ":length"
+ */
+
+/* Forward declarations */
+
+static bool tag_modifier_is_instance_of
+ (struct sieve_validator *valdtr, struct sieve_command *cmd,
+ const struct sieve_extension *ext, const char *identifier, void **context);
+
+/* Modifier tag object */
+
+static const struct sieve_argument_def modifier_tag = {
+ .identifier = "MODIFIER",
+ .flags = SIEVE_ARGUMENT_FLAG_MULTIPLE,
+ .is_instance_of = tag_modifier_is_instance_of
+};
+
+/* Modifier tag implementation */
+
+static bool tag_modifier_is_instance_of
+(struct sieve_validator *valdtr, struct sieve_command *cmd,
+ const struct sieve_extension *ext, const char *identifier, void **data)
+{
+ const struct sieve_variables_modifier *modf;
+
+ if ( data == NULL ) {
+ return ext_variables_modifier_exists(ext, valdtr, identifier);
+ }
+
+ if ( (modf=ext_variables_modifier_create_instance
+ (ext, valdtr, cmd, identifier)) == NULL )
+ return FALSE;
+
+ *data = (void *) modf;
+
+ return TRUE;
+}
+
+/* Registration */
+
+void sieve_variables_modifiers_link_tag
+(struct sieve_validator *valdtr, const struct sieve_extension *var_ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_validator_register_tag(valdtr, cmd_reg, var_ext, &modifier_tag, 0);
+}
+
+/* Validation */
+
+bool sieve_variables_modifiers_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd,
+ ARRAY_TYPE(sieve_variables_modifier) *modifiers)
+{
+ struct sieve_ast_argument *arg;
+
+ arg = sieve_command_first_argument(cmd);
+ while ( arg != NULL && arg != cmd->first_positional ) {
+ const struct sieve_variables_modifier *modfs;
+ const struct sieve_variables_modifier *modf;
+ unsigned int i, modf_count;
+ bool inserted;
+
+ if ( !sieve_argument_is(arg, modifier_tag) ) {
+ arg = sieve_ast_argument_next(arg);
+ continue;
+ }
+ modf = (const struct sieve_variables_modifier *)
+ arg->argument->data;
+
+ inserted = FALSE;
+ modfs = array_get(modifiers, &modf_count);
+ for ( i = 0; i < modf_count && !inserted; i++ ) {
+
+ if ( modfs[i].def->precedence == modf->def->precedence ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "modifiers :%s and :%s specified for the set command conflict "
+ "having equal precedence",
+ modfs[i].def->obj_def.identifier, modf->def->obj_def.identifier);
+ return FALSE;
+ }
+
+ if ( modfs[i].def->precedence < modf->def->precedence ) {
+ array_insert(modifiers, i, modf, 1);
+ inserted = TRUE;
+ }
+ }
+
+ if ( !inserted )
+ array_append(modifiers, modf, 1);
+
+ /* Added to modifier list;
+ self-destruct to prevent implicit code generation */
+ arg = sieve_ast_arguments_detach(arg, 1);
+ }
+ return TRUE;
+}
+
+bool sieve_variables_modifiers_generate
+(const struct sieve_codegen_env *cgenv,
+ ARRAY_TYPE(sieve_variables_modifier) *modifiers)
+{
+ struct sieve_binary_block *sblock = cgenv->sblock;
+ const struct sieve_variables_modifier *modfs;
+ unsigned int i, modf_count;
+
+ sieve_binary_emit_byte(sblock, array_count(modifiers));
+
+ modfs = array_get(modifiers, &modf_count);
+ for ( i = 0; i < modf_count; i++ ) {
+ ext_variables_opr_modifier_emit(sblock,
+ modfs[i].object.ext, modfs[i].def);
+ }
+ return TRUE;
+}
+
+/*
+ * Modifier coding
+ */
+
+const struct sieve_operand_class sieve_variables_modifier_operand_class =
+ { "modifier" };
+
+static const struct sieve_extension_objects core_modifiers =
+ SIEVE_VARIABLES_DEFINE_MODIFIERS(ext_variables_core_modifiers);
+
+const struct sieve_operand_def modifier_operand = {
+ .name = "modifier",
+ .ext_def = &variables_extension,
+ .code = EXT_VARIABLES_OPERAND_MODIFIER,
+ .class = &sieve_variables_modifier_operand_class,
+ .interface = &core_modifiers
+};
+
+bool sieve_variables_modifiers_code_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ unsigned int mdfs, i;
+
+ /* Read the number of applied modifiers we need to read */
+ if ( !sieve_binary_read_byte(denv->sblock, address, &mdfs) )
+ return FALSE;
+
+ /* Print all modifiers (sorted during code generation already) */
+ for ( i = 0; i < mdfs; i++ ) {
+ if ( !ext_variables_opr_modifier_dump(denv, address) )
+ return FALSE;
+ }
+ return TRUE;
+}
+
+int sieve_variables_modifiers_code_read(
+ const struct sieve_runtime_env *renv,
+ const struct sieve_extension *var_ext, sieve_size_t *address,
+ ARRAY_TYPE(sieve_variables_modifier) *modifiers)
+{
+ unsigned int lprec, mdfs, i;
+
+ if ( !sieve_binary_read_byte(renv->sblock, address, &mdfs) ) {
+ sieve_runtime_trace_error(renv, "invalid modifier count");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ t_array_init(modifiers, mdfs);
+
+ lprec = (unsigned int)-1;
+ for ( i = 0; i < mdfs; i++ ) {
+ struct sieve_variables_modifier modf;
+
+ if ( !ext_variables_opr_modifier_read(renv, var_ext,
+ address, &modf) )
+ return SIEVE_EXEC_BIN_CORRUPT;
+ if ( modf.def != NULL ) {
+ if ( modf.def->precedence >= lprec ) {
+ sieve_runtime_trace_error(renv,
+ "unsorted modifier precedence");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ lprec = modf.def->precedence;
+ }
+
+ array_append(modifiers, &modf, 1);
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Modifier application
+ */
+
+int sieve_variables_modifiers_apply
+(const struct sieve_runtime_env *renv,
+ const struct sieve_extension *var_ext,
+ ARRAY_TYPE(sieve_variables_modifier) *modifiers,
+ string_t **value)
+{
+ const struct ext_variables_config *config =
+ ext_variables_get_config(var_ext);
+ const struct sieve_variables_modifier *modfs;
+ unsigned int i, modf_count;
+
+ /* Hold value within limits */
+ if ( str_len(*value) > config->max_variable_size ) {
+ /* assume variable originates from code, so copy it first */
+ string_t *new_value = t_str_new(config->max_variable_size+3);
+ str_append_str(new_value, *value);
+ *value = new_value;
+ str_truncate_utf8(*value, config->max_variable_size);
+ }
+
+ if ( !array_is_created(modifiers) )
+ return SIEVE_EXEC_OK;
+
+ modfs = array_get(modifiers, &modf_count);
+ if ( modf_count == 0 )
+ return SIEVE_EXEC_OK;
+
+ for ( i = 0; i < modf_count; i++ ) {
+ string_t *new_value;
+ const struct sieve_variables_modifier *modf = &modfs[i];
+
+ if ( modf->def != NULL && modf->def->modify != NULL ) {
+ if ( !modf->def->modify(modf, *value, &new_value) )
+ return SIEVE_EXEC_FAILURE;
+
+ *value = new_value;
+ if ( *value == NULL )
+ return SIEVE_EXEC_FAILURE;
+
+ sieve_runtime_trace_here
+ (renv, SIEVE_TRLVL_COMMANDS,
+ "modify :%s \"%s\" => \"%s\"",
+ sieve_variables_modifier_name(modf),
+ str_sanitize(str_c(*value), 256),
+ str_sanitize(str_c(new_value), 256));
+
+ /* Hold value within limits */
+ if ( str_len(*value) > config->max_variable_size )
+ str_truncate_utf8(*value, config->max_variable_size);
+ }
+ }
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-modifiers.h b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-modifiers.h
new file mode 100644
index 0000000..50b4256
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-modifiers.h
@@ -0,0 +1,66 @@
+#ifndef EXT_VARIABLES_MODIFIERS_H
+#define EXT_VARIABLES_MODIFIERS_H
+
+#include "sieve-common.h"
+#include "sieve-runtime-trace.h"
+
+#include "ext-variables-common.h"
+
+#define ext_variables_namespace_name(nspc) \
+ (nspc)->object->def->name
+#define ext_variables_namespaces_equal(nspc1, nspc2) \
+ ( (nspc1)->def == (nspc2)->def ))
+
+/*
+ * Modifier registry
+ */
+
+bool ext_variables_modifier_exists
+ (const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
+ const char *identifier);
+const struct sieve_variables_modifier *ext_variables_modifier_create_instance
+ (const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
+ struct sieve_command *cmd, const char *identifier);
+
+void ext_variables_register_core_modifiers
+ (const struct sieve_extension *var_ext,
+ struct ext_variables_validator_context *ctx);
+
+/*
+ * Modifier operand
+ */
+
+extern const struct sieve_operand_def modifier_operand;
+
+static inline void ext_variables_opr_modifier_emit
+(struct sieve_binary_block *sblock, const struct sieve_extension *ext,
+ const struct sieve_variables_modifier_def *modf_def)
+{
+ sieve_opr_object_emit(sblock, ext, &modf_def->obj_def);
+}
+
+static inline bool
+ext_variables_opr_modifier_read(const struct sieve_runtime_env *renv,
+ const struct sieve_extension *var_ext,
+ sieve_size_t *address,
+ struct sieve_variables_modifier *modf)
+{
+ if ( !sieve_opr_object_read
+ (renv, &sieve_variables_modifier_operand_class, address, &modf->object) ) {
+ sieve_runtime_trace_error(renv, "invalid modifier operand");
+ return FALSE;
+ }
+
+ modf->def = (const struct sieve_variables_modifier_def *) modf->object.def;
+ modf->var_ext = var_ext;
+ return TRUE;
+}
+
+static inline bool ext_variables_opr_modifier_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ return sieve_opr_object_dump
+ (denv, &sieve_variables_modifier_operand_class, address, NULL);
+}
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-name.c b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-name.c
new file mode 100644
index 0000000..fac0b71
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-name.c
@@ -0,0 +1,110 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "array.h"
+
+#include "sieve-common.h"
+
+#include "ext-variables-common.h"
+#include "ext-variables-limits.h"
+#include "ext-variables-name.h"
+
+#include <ctype.h>
+
+bool sieve_variable_identifier_is_valid(const char *identifier)
+{
+ const char *p = identifier;
+ size_t plen = strlen(identifier);
+ const char *pend;
+
+ if ( plen == 0 || plen >= EXT_VARIABLES_MAX_VARIABLE_NAME_LEN )
+ return FALSE;
+
+ pend = PTR_OFFSET(identifier, plen);
+
+ if ( *p == '_' || i_isalpha(*p) ) {
+ p++;
+
+ while ( p < pend && (*p == '_' || i_isalnum(*p)) ) {
+ p++;
+ }
+ }
+
+ return ( p == pend );
+}
+
+int ext_variable_name_parse
+(ARRAY_TYPE(sieve_variable_name) *vname, const char **str, const char *strend)
+{
+ const char *p = *str;
+
+ array_clear(vname);
+
+ while ( p < strend ) {
+ struct sieve_variable_name *cur_element;
+ string_t *cur_ident;
+
+ /* Acquire current position in the array */
+
+ if ( array_count(vname) >= EXT_VARIABLES_MAX_NAMESPACE_ELEMENTS )
+ return -1;
+
+ cur_element = array_append_space(vname);
+ cur_ident = cur_element->identifier = t_str_new(32);
+
+ /* Parse element */
+
+ /* Identifier */
+ if ( *p == '_' || i_isalpha(*p) ) {
+ cur_element->num_variable = -1;
+ str_truncate(cur_ident, 0);
+ str_append_c(cur_ident, *p);
+ p++;
+
+ while ( p < strend && (*p == '_' || i_isalnum(*p)) ) {
+ if ( str_len(cur_ident) >= EXT_VARIABLES_MAX_VARIABLE_NAME_LEN )
+ return -1;
+ str_append_c(cur_ident, *p);
+ p++;
+ }
+
+ /* Num-variable */
+ } else if ( i_isdigit(*p) ) {
+ cur_element->num_variable = *p - '0';
+ p++;
+
+ while ( p < strend && i_isdigit(*p) ) {
+ cur_element->num_variable = cur_element->num_variable*10 + (*p - '0');
+ p++;
+ }
+
+ /* If a num-variable is first, no more elements can follow because no
+ * namespace is specified.
+ */
+ if ( array_count(vname) == 1 ) {
+ *str = p;
+ return 1;
+ }
+ } else {
+ *str = p;
+ return -1;
+ }
+
+ /* Check whether next name element is present */
+ if ( p < strend && *p == '.' ) {
+ p++;
+
+ /* It may not be empty */
+ if ( p >= strend )
+ return -1;
+ } else
+ break;
+ }
+
+ *str = p;
+ return array_count(vname);
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-name.h b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-name.h
new file mode 100644
index 0000000..289a978
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-name.h
@@ -0,0 +1,43 @@
+#ifndef EXT_VARIABLES_NAME_H
+#define EXT_VARIABLES_NAME_H
+
+/* Variable Substitution
+ * ---------------------
+ *
+ * The variable strings are preprocessed into an AST list consisting of variable
+ * substitutions and constant parts of the string. The variables to which
+ * the substitutions link are looked up and their index in their scope storage
+ * is what is added to the list and eventually emitted as byte code. So, in
+ * bytecode a variable string will look as a series of substrings interrupted by
+ * integer operands that refer to variables. During execution, the strings and
+ * the looked-up variables are concatenated to obtain the desired result. The
+ * the variable references are simple indexes into an array of variables, so
+ * looking these up during execution is a trivial process.
+ *
+ * However (RFC 5229):
+ * Tests or actions in future extensions may need to access the
+ * unexpanded version of the string argument and, e.g., do the expansion
+ * after setting variables in its namespace. The design of the
+ * implementation should allow this.
+ *
+ * Various options exist to provide this feature. If the extension is entirely
+ * namespace-based there is actually not very much of a problem. The variable
+ * list can easily be extended with new argument-types that refer to a variable
+ * identifier instead of an index in the variable's storage.
+ */
+
+#include "lib.h"
+#include "array.h"
+
+#include "sieve-common.h"
+
+#include "ext-variables-common.h"
+
+/*
+ * Variable name parsing
+ */
+
+int ext_variable_name_parse
+ (ARRAY_TYPE(sieve_variable_name) *vname, const char **str, const char *strend);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-namespaces.c b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-namespaces.c
new file mode 100644
index 0000000..4df62e2
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-namespaces.c
@@ -0,0 +1,236 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+
+#include "ext-variables-common.h"
+#include "ext-variables-namespaces.h"
+
+#include <ctype.h>
+
+/*
+ * Namespace registry
+ */
+
+void sieve_variables_namespace_register
+(const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ const struct sieve_variables_namespace_def *nspc_def)
+{
+ struct ext_variables_validator_context *ctx =
+ ext_variables_validator_context_get(var_ext, valdtr);
+
+ sieve_validator_object_registry_add(ctx->namespaces, ext, &nspc_def->obj_def);
+}
+
+bool ext_variables_namespace_exists
+(const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
+ const char *identifier)
+{
+ struct ext_variables_validator_context *ctx =
+ ext_variables_validator_context_get(var_ext, valdtr);
+
+ return sieve_validator_object_registry_find
+ (ctx->namespaces, identifier, NULL);
+}
+
+const struct sieve_variables_namespace *ext_variables_namespace_create_instance
+(const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
+ struct sieve_command *cmd, const char *identifier)
+{
+ struct ext_variables_validator_context *ctx =
+ ext_variables_validator_context_get(var_ext, valdtr);
+ struct sieve_object object;
+ struct sieve_variables_namespace *nspc;
+ pool_t pool;
+
+ if ( !sieve_validator_object_registry_find
+ (ctx->namespaces, identifier, &object) )
+ return NULL;
+
+ pool = sieve_command_pool(cmd);
+ nspc = p_new(pool, struct sieve_variables_namespace, 1);
+ nspc->object = object;
+ nspc->def = (const struct sieve_variables_namespace_def *) object.def;
+
+ return nspc;
+}
+
+/*
+ * Namespace variable argument
+ */
+
+struct arg_namespace_variable {
+ const struct sieve_variables_namespace *namespace;
+
+ void *data;
+};
+
+static bool arg_namespace_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *context ATTR_UNUSED);
+
+const struct sieve_argument_def namespace_argument = {
+ .identifier = "@namespace",
+ .generate = arg_namespace_generate
+};
+
+bool ext_variables_namespace_argument_activate
+(const struct sieve_extension *this_ext, struct sieve_validator *valdtr,
+ struct sieve_ast_argument *arg, struct sieve_command *cmd,
+ ARRAY_TYPE(sieve_variable_name) *var_name, bool assignment)
+{
+ pool_t pool = sieve_command_pool(cmd);
+ struct sieve_ast *ast = arg->ast;
+ const struct sieve_variables_namespace *nspc;
+ struct arg_namespace_variable *var;
+ const struct sieve_variable_name *name_element = array_idx(var_name, 0);
+ void *var_data = NULL;
+
+ nspc = ext_variables_namespace_create_instance
+ (this_ext, valdtr, cmd, str_c(name_element->identifier));
+ if ( nspc == NULL ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "referring to variable in unknown namespace '%s'",
+ str_c(name_element->identifier));
+ return FALSE;
+ }
+
+ if ( nspc->def != NULL && nspc->def->validate != NULL &&
+ !nspc->def->validate
+ (valdtr, nspc, arg, cmd, var_name, &var_data, assignment) ) {
+ return FALSE;
+ }
+
+ var = p_new(pool, struct arg_namespace_variable, 1);
+ var->namespace = nspc;
+ var->data = var_data;
+
+ arg->argument = sieve_argument_create(ast, &namespace_argument, this_ext, 0);
+ arg->argument->data = (void *) var;
+
+ return TRUE;
+}
+
+struct sieve_ast_argument *ext_variables_namespace_argument_create
+(const struct sieve_extension *this_ext,
+ struct sieve_validator *valdtr, struct sieve_ast_argument *parent_arg,
+ struct sieve_command *cmd, ARRAY_TYPE(sieve_variable_name) *var_name)
+{
+ struct sieve_ast *ast = parent_arg->ast;
+ struct sieve_ast_argument *new_arg;
+
+ new_arg = sieve_ast_argument_create(ast, sieve_ast_argument_line(parent_arg));
+ new_arg->type = SAAT_STRING;
+
+ if ( !ext_variables_namespace_argument_activate
+ (this_ext, valdtr, new_arg, cmd, var_name, FALSE) )
+ return NULL;
+
+ return new_arg;
+}
+
+static bool arg_namespace_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_argument *argument = arg->argument;
+ struct arg_namespace_variable *var =
+ (struct arg_namespace_variable *) argument->data;
+ const struct sieve_variables_namespace *nspc = var->namespace;
+
+ if ( nspc->def != NULL && nspc->def->generate != NULL )
+ return nspc->def->generate(cgenv, nspc, arg, cmd, var->data);
+
+ return TRUE;
+}
+
+/*
+ * Namespace variable operands
+ */
+
+const struct sieve_operand_class sieve_variables_namespace_operand_class =
+ { "variable-namespace" };
+
+static bool opr_namespace_variable_dump
+ (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address);
+static int opr_namespace_variable_read
+ (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, string_t **str_r);
+
+static const struct sieve_opr_string_interface namespace_variable_interface = {
+ opr_namespace_variable_dump,
+ opr_namespace_variable_read
+};
+
+const struct sieve_operand_def namespace_variable_operand = {
+ .name = "namespace",
+ .ext_def = &variables_extension,
+ .code = EXT_VARIABLES_OPERAND_NAMESPACE_VARIABLE,
+ .class = &string_class,
+ .interface = &namespace_variable_interface
+};
+
+void sieve_variables_opr_namespace_variable_emit
+(struct sieve_binary_block *sblock, const struct sieve_extension *var_ext,
+ const struct sieve_extension *ext,
+ const struct sieve_variables_namespace_def *nspc_def)
+{
+ i_assert( sieve_extension_is(var_ext, variables_extension) );
+ sieve_operand_emit(sblock, var_ext, &namespace_variable_operand);
+ sieve_opr_object_emit(sblock, ext, &nspc_def->obj_def);
+}
+
+static bool opr_namespace_variable_dump
+(const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address)
+{
+ struct sieve_variables_namespace nspc;
+ struct sieve_operand nsoprnd;
+
+ if ( !sieve_operand_read(denv->sblock, address, NULL, &nsoprnd) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_opr_object_read_data
+ (denv->sblock, &nsoprnd, &sieve_variables_namespace_operand_class, address,
+ &nspc.object) ) {
+ return FALSE;
+ }
+
+ nspc.def = (const struct sieve_variables_namespace_def *) nspc.object.def;
+
+ if ( nspc.def == NULL || nspc.def->dump_variable == NULL )
+ return FALSE;
+
+ return nspc.def->dump_variable(denv, &nspc, oprnd, address);
+}
+
+static int opr_namespace_variable_read
+(const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, string_t **str_r)
+{
+ struct sieve_variables_namespace nspc;
+
+ if ( !sieve_opr_object_read
+ (renv, &sieve_variables_namespace_operand_class, address, &nspc.object) ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "variable namespace operand corrupt: failed to read");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ nspc.def = (const struct sieve_variables_namespace_def *) nspc.object.def;
+
+ if ( nspc.def == NULL || nspc.def->read_variable == NULL )
+ return SIEVE_EXEC_FAILURE;
+
+ return nspc.def->read_variable(renv, &nspc, oprnd, address, str_r);
+}
+
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-namespaces.h b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-namespaces.h
new file mode 100644
index 0000000..a687582
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-namespaces.h
@@ -0,0 +1,43 @@
+#ifndef EXT_VARIABLES_NAMESPACES_H
+#define EXT_VARIABLES_NAMESPACES_H
+
+#include "sieve-common.h"
+
+#include "ext-variables-common.h"
+#include "sieve-ext-variables.h"
+
+/*
+ * Namespace registry
+ */
+
+bool ext_variables_namespace_exists
+ (const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
+ const char *identifier);
+const struct sieve_variables_namespace *ext_variables_namespace_create_instance
+ (const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
+ struct sieve_command *cmd, const char *identifier);
+
+void ext_variables_register_core_namespaces
+ (const struct sieve_extension *var_ext,
+ struct ext_variables_validator_context *ctx);
+
+/*
+ * Namespace argument
+ */
+
+struct sieve_ast_argument *ext_variables_namespace_argument_create
+ (const struct sieve_extension *this_ext,
+ struct sieve_validator *valdtr, struct sieve_ast_argument *parent_arg,
+ struct sieve_command *cmd, ARRAY_TYPE(sieve_variable_name) *var_name);
+bool ext_variables_namespace_argument_activate
+ (const struct sieve_extension *this_ext, struct sieve_validator *valdtr,
+ struct sieve_ast_argument *arg, struct sieve_command *cmd,
+ ARRAY_TYPE(sieve_variable_name) *var_name, bool assignment);
+
+/*
+ * Namespace operand
+ */
+
+extern const struct sieve_operand_def namespace_variable_operand;
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-operands.c b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-operands.c
new file mode 100644
index 0000000..359f3bf
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-operands.c
@@ -0,0 +1,279 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "hash.h"
+#include "str.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+#include "sieve-ast.h"
+#include "sieve-binary.h"
+#include "sieve-code.h"
+#include "sieve-match-types.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-dump.h"
+#include "sieve-interpreter.h"
+
+#include "ext-variables-common.h"
+#include "ext-variables-limits.h"
+#include "ext-variables-name.h"
+#include "ext-variables-dump.h"
+#include "ext-variables-operands.h"
+
+/*
+ * Variable operand
+ */
+
+static bool opr_variable_dump
+ (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address);
+static int opr_variable_read_value
+ (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, string_t **str_r);
+
+const struct sieve_opr_string_interface variable_interface = {
+ opr_variable_dump,
+ opr_variable_read_value
+};
+
+const struct sieve_operand_def variable_operand = {
+ .name = "variable",
+ .ext_def = &variables_extension,
+ .code = EXT_VARIABLES_OPERAND_VARIABLE,
+ .class = &string_class,
+ .interface = &variable_interface
+};
+
+void sieve_variables_opr_variable_emit
+(struct sieve_binary_block *sblock, const struct sieve_extension *var_ext,
+ struct sieve_variable *var)
+{
+ i_assert( sieve_extension_is(var_ext, variables_extension) );
+
+ if ( var->ext == NULL ) {
+ /* Default variable storage */
+ (void) sieve_operand_emit(sblock, var_ext, &variable_operand);
+ (void) sieve_binary_emit_byte(sblock, 0); /* Default */
+ (void) sieve_binary_emit_unsigned(sblock, var->index);
+ return;
+ }
+
+ (void) sieve_operand_emit(sblock, var_ext, &variable_operand);
+ (void) sieve_binary_emit_extension(sblock, var->ext, 1); /* Extension */
+ (void) sieve_binary_emit_unsigned(sblock, var->index);
+}
+
+static bool opr_variable_dump
+(const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address)
+{
+ const struct sieve_extension *this_ext = oprnd->ext;
+ unsigned int index = 0;
+ const struct sieve_extension *ext;
+ unsigned int code = 1; /* Initially set to offset value */
+ const char *identifier;
+
+ if ( !sieve_binary_read_extension(denv->sblock, address, &code, &ext) )
+ return FALSE;
+
+ if ( !sieve_binary_read_unsigned(denv->sblock, address, &index) )
+ return FALSE;
+
+ identifier = ext_variables_dump_get_identifier(this_ext, denv, ext, index);
+ identifier = identifier == NULL ? "??" : identifier;
+
+ if ( oprnd->field_name != NULL )
+ sieve_code_dumpf(denv, "%s: VAR[%s] ${%s}",
+ oprnd->field_name, sieve_ext_variables_get_varid(ext, index), identifier);
+ else
+ sieve_code_dumpf(denv, "VAR[%s] ${%s}",
+ sieve_ext_variables_get_varid(ext, index), identifier);
+
+ return TRUE;
+}
+
+static int opr_variable_read_value
+(const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, string_t **str_r)
+{
+ const struct sieve_extension *this_ext = oprnd->ext;
+ const struct sieve_extension *ext;
+ unsigned int code = 1; /* Initially set to offset value */
+ struct sieve_variable_storage *storage;
+ unsigned int index = 0;
+
+ if ( !sieve_binary_read_extension(renv->sblock, address, &code, &ext) ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "variable operand corrupt: invalid extension byte");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ storage = sieve_ext_variables_runtime_get_storage
+ (this_ext, renv, ext);
+ if ( storage == NULL ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "variable operand corrupt: extension has no storage");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if ( sieve_binary_read_unsigned(renv->sblock, address, &index) ) {
+ /* Parameter str can be NULL if we are requested to only skip and not
+ * actually read the argument.
+ */
+ if ( str_r != NULL ) {
+ if ( !sieve_variable_get(storage, index, str_r) )
+ return SIEVE_EXEC_FAILURE;
+
+ if ( *str_r == NULL ) *str_r = t_str_new(0);
+ }
+
+ return SIEVE_EXEC_OK;
+ }
+
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "variable operand corrupt: invalid variable index");
+ return SIEVE_EXEC_BIN_CORRUPT;
+}
+
+int sieve_variable_operand_read_data
+(const struct sieve_runtime_env *renv, struct sieve_operand *oprnd,
+ sieve_size_t *address, const char *field_name,
+ struct sieve_variable_storage **storage_r, unsigned int *var_index_r)
+{
+ const struct sieve_extension *ext;
+ unsigned int code = 1; /* Initially set to offset value */
+ unsigned int idx = 0;
+
+ oprnd->field_name = field_name;
+
+ if ( !sieve_operand_is_variable(oprnd) ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "expected variable operand but found %s", sieve_operand_name(oprnd));
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if ( !sieve_binary_read_extension(renv->sblock, address, &code, &ext) ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "variable operand corrupt: invalid extension byte");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ *storage_r = sieve_ext_variables_runtime_get_storage
+ (oprnd->ext, renv, ext);
+ if ( *storage_r == NULL ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "variable operand corrupt: extension has no storage");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if ( !sieve_binary_read_unsigned(renv->sblock, address, &idx) ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "variable operand corrupt: invalid variable index");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ *var_index_r = idx;
+ return SIEVE_EXEC_OK;
+}
+
+int sieve_variable_operand_read
+(const struct sieve_runtime_env *renv, sieve_size_t *address,
+ const char *field_name, struct sieve_variable_storage **storage_r,
+ unsigned int *var_index_r)
+{
+ struct sieve_operand operand;
+ int ret;
+
+ if ( (ret=sieve_operand_runtime_read(renv, address, field_name, &operand))
+ <= 0)
+ return ret;
+
+ return sieve_variable_operand_read_data
+ (renv, &operand, address, field_name, storage_r, var_index_r);
+}
+
+/*
+ * Match value operand
+ */
+
+static bool opr_match_value_dump
+ (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address);
+static int opr_match_value_read
+ (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, string_t **str_r);
+
+const struct sieve_opr_string_interface match_value_interface = {
+ opr_match_value_dump,
+ opr_match_value_read
+};
+
+const struct sieve_operand_def match_value_operand = {
+ .name = "match-value",
+ .ext_def = &variables_extension,
+ .code = EXT_VARIABLES_OPERAND_MATCH_VALUE,
+ .class = &string_class,
+ .interface = &match_value_interface
+};
+
+void sieve_variables_opr_match_value_emit
+(struct sieve_binary_block *sblock, const struct sieve_extension *var_ext,
+ unsigned int index)
+{
+ i_assert( sieve_extension_is(var_ext, variables_extension) );
+ (void) sieve_operand_emit(sblock, var_ext, &match_value_operand);
+ (void) sieve_binary_emit_unsigned(sblock, index);
+}
+
+static bool opr_match_value_dump
+(const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address)
+{
+ unsigned int index = 0;
+
+ if (sieve_binary_read_unsigned(denv->sblock, address, &index) ) {
+ if ( oprnd->field_name != NULL )
+ sieve_code_dumpf
+ (denv, "%s: MATCHVAL %lu", oprnd->field_name, (unsigned long) index);
+ else
+ sieve_code_dumpf(denv, "MATCHVAL %lu", (unsigned long) index);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int opr_match_value_read
+(const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, string_t **str_r)
+{
+ const struct sieve_extension *this_ext = oprnd->ext;
+ const struct ext_variables_config *config =
+ ext_variables_get_config(this_ext);
+ unsigned int index = 0;
+
+ if ( sieve_binary_read_unsigned(renv->sblock, address, &index) ) {
+ /* Parameter str can be NULL if we are requested to only skip and not
+ * actually read the argument.
+ */
+ if ( str_r != NULL ) {
+ sieve_match_values_get(renv, index, str_r);
+
+ if ( *str_r == NULL )
+ *str_r = t_str_new(0);
+ else if ( str_len(*str_r) > config->max_variable_size )
+ str_truncate_utf8(*str_r, config->max_variable_size);
+ }
+
+ return SIEVE_EXEC_OK;
+ }
+
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "match value operand corrupt: invalid index data");
+ return SIEVE_EXEC_BIN_CORRUPT;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-operands.h b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-operands.h
new file mode 100644
index 0000000..64a7781
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-operands.h
@@ -0,0 +1,37 @@
+#ifndef EXT_VARIABLES_OPERANDS_H
+#define EXT_VARIABLES_OPERANDS_H
+
+#include "lib.h"
+#include "hash.h"
+#include "str.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "ext-variables-common.h"
+
+/*
+ * Variable operand
+ */
+
+extern const struct sieve_operand_def variable_operand;
+
+bool ext_variables_opr_variable_read
+ (const struct sieve_runtime_env *renv, sieve_size_t *address,
+ struct sieve_variable_storage **storage, unsigned int *var_index);
+
+/*
+ * Match value operand
+ */
+
+extern const struct sieve_operand_def match_value_operand;
+
+/*
+ * Variable string operand
+ */
+
+void ext_variables_opr_variable_string_emit
+ (struct sieve_binary *sbin, unsigned int elements);
+
+
+#endif
+
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables.c b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables.c
new file mode 100644
index 0000000..6bdef58
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables.c
@@ -0,0 +1,84 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension variables
+ * -------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 5229
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "unichar.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+
+#include "sieve-validator.h"
+
+#include "ext-variables-common.h"
+#include "ext-variables-arguments.h"
+#include "ext-variables-operands.h"
+#include "ext-variables-namespaces.h"
+#include "ext-variables-modifiers.h"
+#include "ext-variables-dump.h"
+
+/*
+ * Operations
+ */
+
+const struct sieve_operation_def *ext_variables_operations[] = {
+ &cmd_set_operation,
+ &tst_string_operation
+};
+
+/*
+ * Operands
+ */
+
+const struct sieve_operand_def *ext_variables_operands[] = {
+ &variable_operand,
+ &match_value_operand,
+ &namespace_variable_operand,
+ &modifier_operand
+};
+
+/*
+ * Extension
+ */
+
+static bool ext_variables_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *validator);
+
+const struct sieve_extension_def variables_extension = {
+ .name = "variables",
+ .load = ext_variables_load,
+ .unload = ext_variables_unload,
+ .validator_load = ext_variables_validator_load,
+ .generator_load = ext_variables_generator_load,
+ .interpreter_load = ext_variables_interpreter_load,
+ .code_dump = ext_variables_code_dump,
+ SIEVE_EXT_DEFINE_OPERATIONS(ext_variables_operations),
+ SIEVE_EXT_DEFINE_OPERANDS(ext_variables_operands)
+};
+
+static bool ext_variables_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *validator)
+{
+ sieve_validator_argument_override
+ (validator, SAT_VAR_STRING, ext, &variable_string_argument);
+
+ sieve_validator_register_command(validator, ext, &cmd_set);
+ sieve_validator_register_command(validator, ext, &tst_string);
+
+ ext_variables_validator_initialize(ext, validator);
+
+ return TRUE;
+}
+
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/sieve-ext-variables.h b/pigeonhole/src/lib-sieve/plugins/variables/sieve-ext-variables.h
new file mode 100644
index 0000000..ce0d0bc
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/sieve-ext-variables.h
@@ -0,0 +1,364 @@
+#ifndef SIEVE_EXT_VARIABLES_H
+#define SIEVE_EXT_VARIABLES_H
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+#include "sieve-objects.h"
+#include "sieve-code.h"
+
+/* Public interface for other extensions to use
+ */
+
+/*
+ * Limits
+ */
+
+unsigned int
+sieve_variables_get_max_scope_size(const struct sieve_extension *var_ext);
+size_t
+sieve_variables_get_max_variable_size(const struct sieve_extension *var_ext);
+
+/*
+ * Variable extension
+ */
+
+/* FIXME: this is not suitable for future plugin support */
+
+extern const struct sieve_extension_def variables_extension;
+
+static inline const struct sieve_extension *sieve_ext_variables_get_extension
+(struct sieve_instance *svinst)
+{
+ return sieve_extension_register(svinst, &variables_extension, FALSE);
+}
+
+/*
+ * Variable name
+ */
+
+struct sieve_variable_name {
+ string_t *identifier;
+ int num_variable;
+};
+
+ARRAY_DEFINE_TYPE(sieve_variable_name, struct sieve_variable_name);
+
+bool sieve_variable_identifier_is_valid(const char *identifier);
+
+/*
+ * Variable scope
+ */
+
+struct sieve_variable {
+ const char *identifier;
+ unsigned int index;
+
+ const struct sieve_extension *ext;
+ void *context;
+};
+
+struct sieve_variable_scope;
+
+struct sieve_variable_scope *sieve_variable_scope_create
+ (struct sieve_instance *svinst, const struct sieve_extension *var_ext,
+ const struct sieve_extension *ext);
+void sieve_variable_scope_ref
+ (struct sieve_variable_scope *scope);
+void sieve_variable_scope_unref
+ (struct sieve_variable_scope **scope);
+pool_t sieve_variable_scope_pool
+ (struct sieve_variable_scope *scope);
+
+struct sieve_variable *sieve_variable_scope_declare
+ (struct sieve_variable_scope *scope, const char *identifier);
+struct sieve_variable *sieve_variable_scope_import
+ (struct sieve_variable_scope *scope, struct sieve_variable *var);
+struct sieve_variable *sieve_variable_scope_get_variable
+ (struct sieve_variable_scope *scope, const char *identifier);
+struct sieve_variable *sieve_variable_scope_get_indexed
+ (struct sieve_variable_scope *scope, unsigned int index);
+
+/* Binary */
+
+struct sieve_variable_scope_binary *sieve_variable_scope_binary_create
+ (struct sieve_variable_scope *scope);
+
+void sieve_variable_scope_binary_ref
+ (struct sieve_variable_scope_binary *scpbin);
+void sieve_variable_scope_binary_unref
+ (struct sieve_variable_scope_binary **scpbin);
+
+struct sieve_variable_scope *sieve_variable_scope_binary_dump
+ (struct sieve_instance *svinst,
+ const struct sieve_extension *var_ext,
+ const struct sieve_extension *ext,
+ const struct sieve_dumptime_env *denv, sieve_size_t *address);
+struct sieve_variable_scope_binary *sieve_variable_scope_binary_read
+ (struct sieve_instance *svinst,
+ const struct sieve_extension *var_ext,
+ const struct sieve_extension *ext,
+ struct sieve_binary_block *sblock, sieve_size_t *address);
+
+struct sieve_variable_scope *sieve_variable_scope_binary_get
+ (struct sieve_variable_scope_binary *scpbin);
+unsigned int sieve_variable_scope_binary_get_size
+ (struct sieve_variable_scope_binary *scpbin);
+
+/*
+ * Variable namespaces
+ */
+
+struct sieve_variables_namespace;
+
+struct sieve_variables_namespace_def {
+ struct sieve_object_def obj_def;
+
+ bool (*validate)
+ (struct sieve_validator *valdtr,
+ const struct sieve_variables_namespace *nspc,
+ struct sieve_ast_argument *arg, struct sieve_command *cmd,
+ ARRAY_TYPE(sieve_variable_name) *var_name, void **var_data,
+ bool assignment);
+ bool (*generate)
+ (const struct sieve_codegen_env *cgenv,
+ const struct sieve_variables_namespace *nspc,
+ struct sieve_ast_argument *arg, struct sieve_command *cmd,
+ void *var_data);
+
+ bool (*dump_variable)
+ (const struct sieve_dumptime_env *denv,
+ const struct sieve_variables_namespace *nspc,
+ const struct sieve_operand *oprnd, sieve_size_t *address);
+ int (*read_variable)
+ (const struct sieve_runtime_env *renv,
+ const struct sieve_variables_namespace *nspc,
+ const struct sieve_operand *oprnd, sieve_size_t *address, string_t **str);
+};
+
+#define SIEVE_VARIABLES_DEFINE_NAMESPACE(OP) SIEVE_EXT_DEFINE_OBJECT(OP)
+#define SIEVE_VARIABLES_DEFINE_NAMESPACES(OPS) SIEVE_EXT_DEFINE_OBJECTS(OPS)
+
+struct sieve_variables_namespace {
+ struct sieve_object object;
+
+ const struct sieve_variables_namespace_def *def;
+};
+
+void sieve_variables_namespace_register
+(const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ const struct sieve_variables_namespace_def *nspc_def);
+
+extern const struct sieve_operand_class sieve_variables_namespace_operand_class;
+
+void sieve_variables_opr_namespace_variable_emit
+ (struct sieve_binary_block *sblock, const struct sieve_extension *var_ext,
+ const struct sieve_extension *ext,
+ const struct sieve_variables_namespace_def *nspc_def);
+
+/* Iteration over all declared variables */
+
+struct sieve_variable_scope_iter;
+
+struct sieve_variable_scope_iter *sieve_variable_scope_iterate_init
+ (struct sieve_variable_scope *scope);
+bool sieve_variable_scope_iterate
+ (struct sieve_variable_scope_iter *iter, struct sieve_variable **var_r);
+void sieve_variable_scope_iterate_deinit
+ (struct sieve_variable_scope_iter **iter);
+
+/* Statistics */
+
+unsigned int sieve_variable_scope_declarations
+ (struct sieve_variable_scope *scope);
+unsigned int sieve_variable_scope_size
+ (struct sieve_variable_scope *scope);
+
+/* Get all native variables */
+
+struct sieve_variable * const *sieve_variable_scope_get_variables
+ (struct sieve_variable_scope *scope, unsigned int *size_r);
+
+/*
+ * Variable storage
+ */
+
+struct sieve_variable_storage;
+
+struct sieve_variable_storage *sieve_variable_storage_create
+ (const struct sieve_extension *var_ext, pool_t pool,
+ struct sieve_variable_scope_binary *scpbin);
+bool sieve_variable_get
+ (struct sieve_variable_storage *storage, unsigned int index,
+ string_t **value);
+bool sieve_variable_get_modifiable
+ (struct sieve_variable_storage *storage, unsigned int index,
+ string_t **value);
+bool sieve_variable_assign
+ (struct sieve_variable_storage *storage, unsigned int index,
+ const string_t *value);
+bool sieve_variable_assign_cstr
+ (struct sieve_variable_storage *storage, unsigned int index,
+ const char *value);
+bool sieve_variable_get_identifier
+ (struct sieve_variable_storage *storage, unsigned int index,
+ const char **identifier);
+const char *sieve_variable_get_varid
+ (struct sieve_variable_storage *storage, unsigned int index);
+
+/*
+ * Variables access
+ */
+
+bool sieve_ext_variables_is_active
+ (const struct sieve_extension *var_ext, struct sieve_validator *valdtr);
+
+struct sieve_variable_scope *sieve_ext_variables_get_local_scope
+ (const struct sieve_extension *var_ext, struct sieve_validator *valdtr);
+
+/* Runtime */
+
+static inline const char *sieve_ext_variables_get_varid
+(const struct sieve_extension *ext, unsigned int index)
+{
+ if ( ext == NULL )
+ return t_strdup_printf("%ld", (long) index);
+
+ return t_strdup_printf("%s:%ld", sieve_extension_name(ext), (long) index);
+}
+
+struct sieve_variable_storage *sieve_ext_variables_runtime_get_storage
+ (const struct sieve_extension *var_ext, const struct sieve_runtime_env *renv,
+ const struct sieve_extension *ext);
+void sieve_ext_variables_runtime_set_storage
+ (const struct sieve_extension *var_ext, const struct sieve_runtime_env *renv,
+ const struct sieve_extension *ext, struct sieve_variable_storage *storage);
+
+const char *sieve_ext_variables_runtime_get_identifier
+(const struct sieve_extension *var_ext, const struct sieve_runtime_env *renv,
+ const struct sieve_extension *ext, unsigned int index);
+
+/*
+ * Variable arguments
+ */
+
+bool sieve_variable_argument_activate
+ (const struct sieve_extension *var_ext,
+ const struct sieve_extension *this_ext,
+ struct sieve_validator *valdtr, struct sieve_command *cmd,
+ struct sieve_ast_argument *arg, bool assignment);
+
+/*
+ * Variable operands
+ */
+
+extern const struct sieve_operand_def variable_operand;
+
+void sieve_variables_opr_variable_emit
+ (struct sieve_binary_block *sblock, const struct sieve_extension *var_ext,
+ struct sieve_variable *var);
+void sieve_variables_opr_match_value_emit
+ (struct sieve_binary_block *sblock, const struct sieve_extension *var_ext,
+ unsigned int index);
+
+int sieve_variable_operand_read_data
+ (const struct sieve_runtime_env *renv, struct sieve_operand *operand,
+ sieve_size_t *address, const char *field_name,
+ struct sieve_variable_storage **storage_r, unsigned int *var_index_r);
+int sieve_variable_operand_read
+ (const struct sieve_runtime_env *renv, sieve_size_t *address,
+ const char *field_name, struct sieve_variable_storage **storage_r,
+ unsigned int *var_index_r);
+
+static inline bool sieve_operand_is_variable
+(const struct sieve_operand *operand)
+{
+ return ( operand != NULL && operand->def != NULL &&
+ operand->def == &variable_operand );
+}
+
+/*
+ * Modifiers
+ */
+
+/* Definition */
+
+struct sieve_variables_modifier;
+
+struct sieve_variables_modifier_def {
+ struct sieve_object_def obj_def;
+
+ unsigned int precedence;
+
+ bool (*modify)(const struct sieve_variables_modifier *modf,
+ string_t *in, string_t **result);
+};
+
+struct sieve_variables_modifier {
+ struct sieve_object object;
+ const struct sieve_extension *var_ext;
+
+ const struct sieve_variables_modifier_def *def;
+};
+
+#define SIEVE_VARIABLES_DEFINE_MODIFIER(OP) SIEVE_EXT_DEFINE_OBJECT(OP)
+#define SIEVE_VARIABLES_DEFINE_MODIFIERS(OPS) SIEVE_EXT_DEFINE_OBJECTS(OPS)
+
+#define sieve_variables_modifier_name(smodf) \
+ ( (smodf)->object.def->identifier )
+
+ARRAY_DEFINE_TYPE(sieve_variables_modifier,
+ struct sieve_variables_modifier);
+
+/* Registry */
+
+void sieve_variables_modifier_register
+ (const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ const struct sieve_variables_modifier_def *smodf);
+
+/* Tagged argument */
+
+void sieve_variables_modifiers_link_tag
+ (struct sieve_validator *valdtr, const struct sieve_extension *var_ext,
+ struct sieve_command_registration *cmd_reg);
+
+bool sieve_variables_modifiers_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd,
+ ARRAY_TYPE(sieve_variables_modifier) *modifiers);
+
+bool sieve_variables_modifiers_generate
+ (const struct sieve_codegen_env *cgenv,
+ ARRAY_TYPE(sieve_variables_modifier) *modifiers);
+
+/* Coding */
+
+extern const struct sieve_operand_class
+ sieve_variables_modifier_operand_class;
+
+bool sieve_variables_modifiers_code_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+int sieve_variables_modifiers_code_read(
+ const struct sieve_runtime_env *renv,
+ const struct sieve_extension *var_ext, sieve_size_t *address,
+ ARRAY_TYPE(sieve_variables_modifier) *modifiers);
+
+/* Application */
+
+int sieve_variables_modifiers_apply
+(const struct sieve_runtime_env *renv,
+ const struct sieve_extension *var_ext,
+ ARRAY_TYPE(sieve_variables_modifier) *modifiers,
+ string_t **value);
+
+/*
+ * Code dumping
+ */
+
+void sieve_ext_variables_dump_set_scope
+(const struct sieve_extension *var_ext, const struct sieve_dumptime_env *denv,
+ const struct sieve_extension *ext, struct sieve_variable_scope *scope);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/tst-string.c b/pigeonhole/src/lib-sieve/plugins/variables/tst-string.c
new file mode 100644
index 0000000..91b0b82
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/variables/tst-string.c
@@ -0,0 +1,271 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-match.h"
+
+#include "ext-variables-common.h"
+
+/*
+ * String test
+ *
+ * Syntax:
+ * string [COMPARATOR] [MATCH-TYPE]
+ * <source: string-list> <key-list: string-list>
+ */
+
+static bool tst_string_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool tst_string_validate
+ (struct sieve_validator *valdtr, struct sieve_command *tst);
+static bool tst_string_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+const struct sieve_command_def tst_string = {
+ .identifier = "string",
+ .type = SCT_TEST,
+ .positional_args = 2,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_string_registered,
+ .validate = tst_string_validate,
+ .generate = tst_string_generate
+};
+
+/*
+ * String operation
+ */
+
+static bool tst_string_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int tst_string_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def tst_string_operation = {
+ .mnemonic = "STRING",
+ .ext_def = &variables_extension,
+ .code = EXT_VARIABLES_OPERATION_STRING,
+ .dump = tst_string_operation_dump,
+ .execute = tst_string_operation_execute
+};
+
+/*
+ * Optional arguments
+ */
+
+enum tst_string_optional {
+ OPT_END,
+ OPT_COMPARATOR,
+ OPT_MATCH_TYPE
+};
+
+/*
+ * Test registration
+ */
+
+static bool tst_string_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_command_registration *cmd_reg)
+{
+ /* The order of these is not significant */
+ sieve_comparators_link_tag(valdtr, cmd_reg, OPT_COMPARATOR);
+ sieve_match_types_link_tags(valdtr, cmd_reg, OPT_MATCH_TYPE);
+
+ return TRUE;
+}
+
+/*
+ * Test validation
+ */
+
+static bool tst_string_validate
+(struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+ const struct sieve_match_type mcht_default =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ const struct sieve_comparator cmp_default =
+ SIEVE_COMPARATOR_DEFAULT(i_octet_comparator);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "source", 1, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ arg = sieve_ast_argument_next(arg);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "key list", 2, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ /* Validate the key argument to a specified match type */
+ return sieve_match_type_validate
+ (valdtr, tst, arg, &mcht_default, &cmp_default);
+}
+
+/*
+ * Test generation
+ */
+
+static bool tst_string_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &tst_string_operation);
+
+ /* Generate arguments */
+ if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool tst_string_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "STRING-TEST");
+ sieve_code_descend(denv);
+
+ /* Optional operands */
+ if ( sieve_match_opr_optional_dump(denv, address, NULL) != 0 )
+ return FALSE;
+
+ return
+ sieve_opr_stringlist_dump(denv, address, "source") &&
+ sieve_opr_stringlist_dump(denv, address, "key list");
+}
+
+/*
+ * Code execution
+ */
+
+static int tst_string_stringlist_next_item
+ (struct sieve_stringlist *_strlist, string_t **str_r);
+static void tst_string_stringlist_reset
+ (struct sieve_stringlist *_strlist);
+static int tst_string_stringlist_get_length
+ (struct sieve_stringlist *_strlist);
+
+struct tst_string_stringlist {
+ struct sieve_stringlist strlist;
+
+ struct sieve_stringlist *value_list;
+};
+
+static struct sieve_stringlist *tst_string_stringlist_create
+(const struct sieve_runtime_env *renv, struct sieve_stringlist *value_list)
+{
+ struct tst_string_stringlist *strlist;
+
+ strlist = t_new(struct tst_string_stringlist, 1);
+ strlist->strlist.runenv = renv;
+ strlist->strlist.exec_status = SIEVE_EXEC_OK;
+ strlist->strlist.next_item = tst_string_stringlist_next_item;
+ strlist->strlist.reset = tst_string_stringlist_reset;
+ strlist->strlist.get_length = tst_string_stringlist_get_length;
+ strlist->value_list = value_list;
+
+ return &strlist->strlist;
+}
+
+static int tst_string_stringlist_next_item
+(struct sieve_stringlist *_strlist, string_t **str_r)
+{
+ struct tst_string_stringlist *strlist =
+ (struct tst_string_stringlist *)_strlist;
+
+ return sieve_stringlist_next_item(strlist->value_list, str_r);
+}
+
+static void tst_string_stringlist_reset
+(struct sieve_stringlist *_strlist)
+{
+ struct tst_string_stringlist *strlist =
+ (struct tst_string_stringlist *)_strlist;
+
+ sieve_stringlist_reset(strlist->value_list);
+}
+
+static int tst_string_stringlist_get_length
+(struct sieve_stringlist *_strlist)
+{
+ struct tst_string_stringlist *strlist =
+ (struct tst_string_stringlist *)_strlist;
+ string_t *item;
+ int length = 0;
+ int ret;
+
+ while ( (ret=sieve_stringlist_next_item(strlist->value_list, &item)) > 0 ) {
+ if ( str_len(item) > 0 )
+ length++;
+ }
+
+ return ( ret < 0 ? -1 : length );
+}
+
+static int tst_string_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ struct sieve_match_type mcht =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ struct sieve_comparator cmp =
+ SIEVE_COMPARATOR_DEFAULT(i_octet_comparator);
+ struct sieve_stringlist *source, *value_list, *key_list;
+ int match, ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Handle match-type and comparator operands */
+ if ( sieve_match_opr_optional_read
+ (renv, address, NULL, &ret, &cmp, &mcht) < 0 )
+ return ret;
+
+ /* Read source */
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "source", &source)) <= 0 )
+ return ret;
+
+ /* Read key-list */
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "key-list", &key_list))
+ <= 0 )
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "string test");
+
+ /* Create wrapper string list wich does not count empty string items */
+ value_list = tst_string_stringlist_create(renv, source);
+
+ /* Perform match */
+ if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret)) < 0 )
+ return ret;
+
+ /* Set test result for subsequent conditional jump */
+ sieve_interpreter_set_test_result(renv->interp, match > 0);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/Makefile.am b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/Makefile.am
new file mode 100644
index 0000000..f409e2b
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = debug environment report
+
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/Makefile.in b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/Makefile.in
new file mode 100644
index 0000000..43680f1
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/Makefile.in
@@ -0,0 +1,692 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/vnd.dovecot
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = debug environment report
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/vnd.dovecot/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/vnd.dovecot/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/Makefile.am b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/Makefile.am
new file mode 100644
index 0000000..1e08946
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/Makefile.am
@@ -0,0 +1,15 @@
+noinst_LTLIBRARIES = libsieve_ext_debug.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+commands = \
+ cmd-debug-log.c
+
+libsieve_ext_debug_la_SOURCES = \
+ $(commands) \
+ ext-debug.c
+
+noinst_HEADERS = \
+ ext-debug-common.h
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/Makefile.in b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/Makefile.in
new file mode 100644
index 0000000..f9b5450
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/Makefile.in
@@ -0,0 +1,687 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/vnd.dovecot/debug
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_debug_la_LIBADD =
+am__objects_1 = cmd-debug-log.lo
+am_libsieve_ext_debug_la_OBJECTS = $(am__objects_1) ext-debug.lo
+libsieve_ext_debug_la_OBJECTS = $(am_libsieve_ext_debug_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cmd-debug-log.Plo \
+ ./$(DEPDIR)/ext-debug.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_debug_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_debug_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_debug.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../../.. \
+ $(LIBDOVECOT_INCLUDE)
+
+commands = \
+ cmd-debug-log.c
+
+libsieve_ext_debug_la_SOURCES = \
+ $(commands) \
+ ext-debug.c
+
+noinst_HEADERS = \
+ ext-debug-common.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/vnd.dovecot/debug/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/vnd.dovecot/debug/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_debug.la: $(libsieve_ext_debug_la_OBJECTS) $(libsieve_ext_debug_la_DEPENDENCIES) $(EXTRA_libsieve_ext_debug_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_debug_la_OBJECTS) $(libsieve_ext_debug_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-debug-log.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-debug.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/cmd-debug-log.Plo
+ -rm -f ./$(DEPDIR)/ext-debug.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/cmd-debug-log.Plo
+ -rm -f ./$(DEPDIR)/ext-debug.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/cmd-debug-log.c b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/cmd-debug-log.c
new file mode 100644
index 0000000..355daa5
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/cmd-debug-log.c
@@ -0,0 +1,130 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-debug-common.h"
+
+/*
+ * Debug_log command
+ *
+ * Syntax
+ * debug_log <message: string>
+ */
+
+static bool cmd_debug_log_validate
+ (struct sieve_validator *valdtr, struct sieve_command *tst);
+static bool cmd_debug_log_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+const struct sieve_command_def debug_log_command = {
+ .identifier = "debug_log",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_debug_log_validate,
+ .generate = cmd_debug_log_generate
+};
+
+/*
+ * Body operation
+ */
+
+static bool cmd_debug_log_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int cmd_debug_log_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def debug_log_operation = {
+ .mnemonic = "DEBUG_LOG",
+ .ext_def = &vnd_debug_extension,
+ .dump = cmd_debug_log_operation_dump,
+ .execute = cmd_debug_log_operation_execute
+};
+
+/*
+ * Validation
+ */
+
+static bool cmd_debug_log_validate
+(struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "message", 1, SAAT_STRING) ) {
+ return FALSE;
+ }
+
+ return sieve_validator_argument_activate(valdtr, tst, arg, FALSE);
+}
+
+/*
+ * Code generation
+ */
+
+static bool cmd_debug_log_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ (void)sieve_operation_emit(cgenv->sblock, cmd->ext, &debug_log_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, cmd, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool cmd_debug_log_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "DEBUG_LOG");
+ sieve_code_descend(denv);
+
+ return sieve_opr_string_dump(denv, address, "key list");
+}
+
+/*
+ * Interpretation
+ */
+
+static int cmd_debug_log_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ string_t *message;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Read message */
+
+ if ( (ret=sieve_opr_string_read(renv, address, "message", &message)) <= 0 )
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "debug_log \"%s\"",
+ str_sanitize(str_c(message), 80));
+
+ sieve_runtime_log(renv, NULL, "DEBUG: %s", str_c(message));
+
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug-common.h b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug-common.h
new file mode 100644
index 0000000..88ae3db
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug-common.h
@@ -0,0 +1,22 @@
+#ifndef EXT_DEBUG_COMMON_H
+#define EXT_DEBUG_COMMON_H
+
+/*
+ * Extensions
+ */
+
+extern const struct sieve_extension_def vnd_debug_extension;
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def debug_log_command;
+
+/*
+ * Operations
+ */
+
+extern const struct sieve_operation_def debug_log_operation;
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c
new file mode 100644
index 0000000..2781e83
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/debug/ext-debug.c
@@ -0,0 +1,70 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension debug
+ * ---------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: vendor-defined; spec-bosch-sieve-debug
+ * Implementation: full
+ * Status: experimental
+ *
+ */
+
+#include "lib.h"
+#include "array.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-address-parts.h"
+
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-debug-common.h"
+
+/*
+ * Extension
+ */
+
+static bool ext_debug_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *validator);
+static bool ext_debug_interpreter_load
+ (const struct sieve_extension *ext ATTR_UNUSED,
+ const struct sieve_runtime_env *renv, sieve_size_t *address ATTR_UNUSED);
+
+
+const struct sieve_extension_def vnd_debug_extension = {
+ .name = "vnd.dovecot.debug",
+ .validator_load = ext_debug_validator_load,
+ .interpreter_load = ext_debug_interpreter_load,
+ SIEVE_EXT_DEFINE_OPERATION(debug_log_operation),
+};
+
+static bool ext_debug_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *validator)
+{
+ /* Register new test */
+ sieve_validator_register_command(validator, ext, &debug_log_command);
+
+ return TRUE;
+}
+
+static bool ext_debug_interpreter_load
+(const struct sieve_extension *ext ATTR_UNUSED,
+ const struct sieve_runtime_env *renv, sieve_size_t *address ATTR_UNUSED)
+{
+ if ( renv->ehandler != NULL ) {
+ sieve_error_handler_accept_infolog(renv->ehandler, TRUE);
+ }
+
+ return TRUE;
+}
+
+
+
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/Makefile.am b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/Makefile.am
new file mode 100644
index 0000000..96618ff
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/Makefile.am
@@ -0,0 +1,16 @@
+noinst_LTLIBRARIES = libsieve_ext_vnd_environment.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../../.. \
+ -I$(srcdir)/../../environment \
+ -I$(srcdir)/../../variables \
+ $(LIBDOVECOT_INCLUDE)
+
+libsieve_ext_vnd_environment_la_SOURCES = \
+ ext-vnd-environment.c \
+ ext-vnd-environment-items.c \
+ ext-vnd-environment-variables.c
+
+noinst_HEADERS = \
+ ext-vnd-environment-common.h
+
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/Makefile.in b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/Makefile.in
new file mode 100644
index 0000000..b5d8b20
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/Makefile.in
@@ -0,0 +1,692 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/vnd.dovecot/environment
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_vnd_environment_la_LIBADD =
+am_libsieve_ext_vnd_environment_la_OBJECTS = ext-vnd-environment.lo \
+ ext-vnd-environment-items.lo ext-vnd-environment-variables.lo
+libsieve_ext_vnd_environment_la_OBJECTS = \
+ $(am_libsieve_ext_vnd_environment_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ext-vnd-environment-items.Plo \
+ ./$(DEPDIR)/ext-vnd-environment-variables.Plo \
+ ./$(DEPDIR)/ext-vnd-environment.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_vnd_environment_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_vnd_environment_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_vnd_environment.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../../.. \
+ -I$(srcdir)/../../environment \
+ -I$(srcdir)/../../variables \
+ $(LIBDOVECOT_INCLUDE)
+
+libsieve_ext_vnd_environment_la_SOURCES = \
+ ext-vnd-environment.c \
+ ext-vnd-environment-items.c \
+ ext-vnd-environment-variables.c
+
+noinst_HEADERS = \
+ ext-vnd-environment-common.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/vnd.dovecot/environment/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/vnd.dovecot/environment/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_vnd_environment.la: $(libsieve_ext_vnd_environment_la_OBJECTS) $(libsieve_ext_vnd_environment_la_DEPENDENCIES) $(EXTRA_libsieve_ext_vnd_environment_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_vnd_environment_la_OBJECTS) $(libsieve_ext_vnd_environment_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-vnd-environment-items.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-vnd-environment-variables.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-vnd-environment.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ext-vnd-environment-items.Plo
+ -rm -f ./$(DEPDIR)/ext-vnd-environment-variables.Plo
+ -rm -f ./$(DEPDIR)/ext-vnd-environment.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ext-vnd-environment-items.Plo
+ -rm -f ./$(DEPDIR)/ext-vnd-environment-variables.Plo
+ -rm -f ./$(DEPDIR)/ext-vnd-environment.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-common.h b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-common.h
new file mode 100644
index 0000000..980c830
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-common.h
@@ -0,0 +1,37 @@
+#ifndef EXT_VND_ENVIRONMENT_COMMON_H
+#define EXT_VND_ENVIRONMENT_COMMON_H
+
+#include "sieve-ext-environment.h"
+
+/*
+ * Extension
+ */
+
+struct ext_vnd_environment_context {
+ const struct sieve_extension *env_ext;
+ const struct sieve_extension *var_ext;
+};
+
+extern const struct sieve_extension_def vnd_environment_extension;
+
+/*
+ * Operands
+ */
+
+extern const struct sieve_operand_def environment_namespace_operand;
+
+/*
+ * Environment items
+ */
+
+void ext_vnd_environment_items_register
+(const struct sieve_extension *ext, const struct sieve_runtime_env *renv);
+
+/*
+ * Variables
+ */
+
+void ext_environment_variables_init
+(const struct sieve_extension *this_ext, struct sieve_validator *valdtr);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-items.c b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-items.c
new file mode 100644
index 0000000..af03255
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-items.c
@@ -0,0 +1,95 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+
+#include "sieve-settings.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-address-parts.h"
+
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "ext-vnd-environment-common.h"
+
+/*
+ * Environment items
+ */
+
+/* default_mailbox */
+
+static const char *
+envit_default_mailbox_get_value(const struct sieve_runtime_env *renv,
+ const char *name ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+
+ i_assert(eenv->scriptenv->default_mailbox != NULL);
+ return eenv->scriptenv->default_mailbox;
+}
+
+const struct sieve_environment_item default_mailbox_env_item = {
+ .name = "vnd.dovecot.default-mailbox",
+ .get_value = envit_default_mailbox_get_value
+};
+
+/* username */
+
+static const char *
+envit_username_get_value(const struct sieve_runtime_env *renv,
+ const char *name ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+
+ return eenv->svinst->username;
+}
+
+const struct sieve_environment_item username_env_item = {
+ .name = "vnd.dovecot.username",
+ .get_value = envit_username_get_value
+};
+
+/* config.* */
+
+static const char *
+envit_config_get_value(const struct sieve_runtime_env *renv, const char *name)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+
+ if (*name == '\0')
+ return NULL;
+
+ return sieve_setting_get(eenv->svinst,
+ t_strconcat("sieve_env_", name, NULL));
+}
+
+const struct sieve_environment_item config_env_item = {
+ .name = "vnd.dovecot.config",
+ .prefix = TRUE,
+ .get_value = envit_config_get_value
+};
+
+/*
+ * Register
+ */
+
+void ext_vnd_environment_items_register(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv)
+{
+ struct ext_vnd_environment_context *ectx =
+ (struct ext_vnd_environment_context *)ext->context;
+
+ sieve_environment_item_register(ectx->env_ext, renv->interp,
+ &default_mailbox_env_item);
+ sieve_environment_item_register(ectx->env_ext, renv->interp,
+ &username_env_item);
+ sieve_environment_item_register(ectx->env_ext, renv->interp,
+ &config_env_item);
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-variables.c b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-variables.c
new file mode 100644
index 0000000..1466ee7
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-variables.c
@@ -0,0 +1,206 @@
+/* Copyright (c) 2015-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve-common.h"
+#include "sieve-ast.h"
+#include "sieve-binary.h"
+#include "sieve-code.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "sieve-ext-variables.h"
+
+#include "ext-vnd-environment-common.h"
+
+static bool vnspc_vnd_environment_validate
+ (struct sieve_validator *valdtr,
+ const struct sieve_variables_namespace *nspc,
+ struct sieve_ast_argument *arg, struct sieve_command *cmd,
+ ARRAY_TYPE(sieve_variable_name) *var_name, void **var_data,
+ bool assignment);
+static bool vnspc_vnd_environment_generate
+ (const struct sieve_codegen_env *cgenv,
+ const struct sieve_variables_namespace *nspc,
+ struct sieve_ast_argument *arg,
+ struct sieve_command *cmd, void *var_data);
+static bool vnspc_vnd_environment_dump_variable
+ (const struct sieve_dumptime_env *denv,
+ const struct sieve_variables_namespace *nspc,
+ const struct sieve_operand *oprnd, sieve_size_t *address);
+static int vnspc_vnd_environment_read_variable
+ (const struct sieve_runtime_env *renv,
+ const struct sieve_variables_namespace *nspc,
+ const struct sieve_operand *oprnd,
+ sieve_size_t *address, string_t **str_r);
+
+static const struct sieve_variables_namespace_def
+environment_namespace = {
+ SIEVE_OBJECT("env", &environment_namespace_operand, 0),
+ .validate = vnspc_vnd_environment_validate,
+ .generate = vnspc_vnd_environment_generate,
+ .dump_variable = vnspc_vnd_environment_dump_variable,
+ .read_variable = vnspc_vnd_environment_read_variable
+};
+
+static bool vnspc_vnd_environment_validate
+(struct sieve_validator *valdtr,
+ const struct sieve_variables_namespace *nspc ATTR_UNUSED,
+ struct sieve_ast_argument *arg, struct sieve_command *cmd ATTR_UNUSED,
+ ARRAY_TYPE(sieve_variable_name) *var_name, void **var_data,
+ bool assignment)
+{
+ struct sieve_ast *ast = arg->ast;
+ const struct sieve_variable_name *name_elements;
+ unsigned int i, count;
+ const char *variable;
+ string_t *name;
+
+ /* Compose environment name from parsed variable name */
+ name = t_str_new(64);
+ name_elements = array_get(var_name, &count);
+ i_assert(count > 1);
+ for (i = 1; i < count; i++) {
+ if ( name_elements[i].num_variable >= 0 ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "vnd.dovecot.environment: invalid variable name within "
+ "env namespace `env.%d': "
+ "encountered numeric variable name",
+ name_elements[i].num_variable);
+ return FALSE;
+ }
+ if (str_len(name) > 0)
+ str_append_c(name, '.');
+ str_append_str(name, name_elements[i].identifier);
+ }
+
+ variable = str_c(name);
+
+ if ( assignment ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "vnd.dovecot.environment: cannot assign to environment "
+ "variable `env.%s'", variable);
+ return FALSE;
+ }
+
+ *var_data = (void *) p_strdup(sieve_ast_pool(ast), variable);
+ return TRUE;
+}
+
+static bool vnspc_vnd_environment_generate
+(const struct sieve_codegen_env *cgenv,
+ const struct sieve_variables_namespace *nspc,
+ struct sieve_ast_argument *arg ATTR_UNUSED,
+ struct sieve_command *cmd ATTR_UNUSED, void *var_data)
+{
+ const struct sieve_extension *this_ext = SIEVE_OBJECT_EXTENSION(nspc);
+ const char *variable = (const char *) var_data;
+ struct ext_vnd_environment_context *ext_data;
+
+ if ( this_ext == NULL )
+ return FALSE;
+
+ ext_data = (struct ext_vnd_environment_context *) this_ext->context;
+
+ sieve_variables_opr_namespace_variable_emit
+ (cgenv->sblock, ext_data->var_ext, this_ext, &environment_namespace);
+ sieve_binary_emit_cstring(cgenv->sblock, variable);
+
+ return TRUE;
+}
+
+static bool vnspc_vnd_environment_dump_variable
+(const struct sieve_dumptime_env *denv,
+ const struct sieve_variables_namespace *nspc ATTR_UNUSED,
+ const struct sieve_operand *oprnd, sieve_size_t *address)
+{
+ string_t *var_name;
+
+ if ( !sieve_binary_read_string(denv->sblock, address, &var_name) )
+ return FALSE;
+
+ if ( oprnd->field_name != NULL )
+ sieve_code_dumpf(denv, "%s: VAR ${env.%s}",
+ oprnd->field_name, str_c(var_name));
+ else
+ sieve_code_dumpf(denv, "VAR ${env.%s}",
+ str_c(var_name));
+
+ return TRUE;
+}
+
+static int vnspc_vnd_environment_read_variable
+(const struct sieve_runtime_env *renv,
+ const struct sieve_variables_namespace *nspc,
+ const struct sieve_operand *oprnd, sieve_size_t *address,
+ string_t **str_r)
+{
+ const struct sieve_extension *this_ext = SIEVE_OBJECT_EXTENSION(nspc);
+ struct ext_vnd_environment_context *ectx =
+ (struct ext_vnd_environment_context *) this_ext->context;
+ string_t *var_name;
+ const char *ext_value;
+
+ if ( !sieve_binary_read_string(renv->sblock, address, &var_name) ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "environment variable operand corrupt: invalid name");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if ( str_r != NULL ) {
+ const char *vname = str_c(var_name);
+
+ ext_value = ext_environment_item_get_value
+ (ectx->env_ext, renv, vname);
+
+ if ( ext_value == NULL && strchr(vname, '_') != NULL) {
+ char *p, *aname;
+
+ /* Try again with '_' replaced with '-' */
+ aname = t_strdup_noconst(vname);
+ for (p = aname; *p != '\0'; p++) {
+ if (*p == '_')
+ *p = '-';
+ }
+ ext_value = ext_environment_item_get_value
+ (ectx->env_ext, renv, aname);
+ }
+
+ if ( ext_value == NULL ) {
+ *str_r = t_str_new_const("", 0);
+ return SIEVE_EXEC_OK;
+ }
+
+ *str_r = t_str_new_const(ext_value, strlen(ext_value));
+ }
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Namespace registration
+ */
+
+static const struct sieve_extension_objects environment_namespaces =
+ SIEVE_VARIABLES_DEFINE_NAMESPACE(environment_namespace);
+
+const struct sieve_operand_def environment_namespace_operand = {
+ .name = "env-namespace",
+ .ext_def = &vnd_environment_extension,
+ .class = &sieve_variables_namespace_operand_class,
+ .interface = &environment_namespaces
+};
+
+void ext_environment_variables_init
+(const struct sieve_extension *this_ext, struct sieve_validator *valdtr)
+{
+ struct ext_vnd_environment_context *ext_data =
+ (struct ext_vnd_environment_context *) this_ext->context;
+
+ sieve_variables_namespace_register
+ (ext_data->var_ext, valdtr, this_ext, &environment_namespace);
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment.c b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment.c
new file mode 100644
index 0000000..f8c7028
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment.c
@@ -0,0 +1,112 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension vnd.dovecot.environment
+ * ---------------------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: vendor-defined;
+ * spec-bosch-sieve-dovecot-environment
+ * Implementation: preliminary
+ * Status: experimental
+ *
+ */
+
+#include "lib.h"
+#include "array.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-address-parts.h"
+
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "sieve-ext-variables.h"
+
+#include "ext-vnd-environment-common.h"
+
+/*
+ * Extension
+ */
+
+static bool ext_vnd_environment_load
+ (const struct sieve_extension *ext, void **context);
+static void ext_vnd_environment_unload
+ (const struct sieve_extension *ext);
+static bool ext_vnd_environment_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+static bool ext_vnd_environment_interpreter_load
+ (const struct sieve_extension *ext, const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_extension_def vnd_environment_extension = {
+ .name = "vnd.dovecot.environment",
+ .load = ext_vnd_environment_load,
+ .unload = ext_vnd_environment_unload,
+ .validator_load = ext_vnd_environment_validator_load,
+ .interpreter_load = ext_vnd_environment_interpreter_load,
+ SIEVE_EXT_DEFINE_OPERAND(environment_namespace_operand)
+};
+
+static bool ext_vnd_environment_load
+(const struct sieve_extension *ext, void **context)
+{
+ struct ext_vnd_environment_context *ectx;
+
+ if ( *context != NULL )
+ ext_vnd_environment_unload(ext);
+
+ ectx = i_new(struct ext_vnd_environment_context, 1);
+ ectx->env_ext = sieve_ext_environment_require_extension(ext->svinst);
+ ectx->var_ext = sieve_ext_variables_get_extension(ext->svinst);
+ *context = (void *) ectx;
+
+ return TRUE;
+}
+
+static void ext_vnd_environment_unload
+(const struct sieve_extension *ext)
+{
+ struct ext_vnd_environment_context *ectx =
+ (struct ext_vnd_environment_context *) ext->context;
+
+ i_free(ectx);
+}
+
+/*
+ * Validator
+ */
+
+static bool ext_vnd_environment_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ const struct sieve_extension *env_ext;
+
+ /* Load environment extension implicitly */
+
+ env_ext = sieve_validator_extension_load_implicit
+ (valdtr, environment_extension.name);
+ if ( env_ext == NULL )
+ return FALSE;
+
+ ext_environment_variables_init(ext, valdtr);
+ return TRUE;
+}
+
+/*
+ * Interpreter
+ */
+
+static bool ext_vnd_environment_interpreter_load
+(const struct sieve_extension *ext, const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ ext_vnd_environment_items_register(ext, renv);
+ return TRUE;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/Makefile.am b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/Makefile.am
new file mode 100644
index 0000000..599765f
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/Makefile.am
@@ -0,0 +1,17 @@
+noinst_LTLIBRARIES = libsieve_ext_vnd_report.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../../.. \
+ -I$(srcdir)/../../../util \
+ $(LIBDOVECOT_INCLUDE)
+
+commands = \
+ cmd-report.c
+
+libsieve_ext_vnd_report_la_SOURCES = \
+ ext-vnd-report.c \
+ ext-vnd-report-common.c \
+ $(commands)
+
+noinst_HEADERS = \
+ ext-vnd-report-common.h
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/Makefile.in b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/Makefile.in
new file mode 100644
index 0000000..1c2ec8c
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/Makefile.in
@@ -0,0 +1,695 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/plugins/vnd.dovecot/report
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_ext_vnd_report_la_LIBADD =
+am__objects_1 = cmd-report.lo
+am_libsieve_ext_vnd_report_la_OBJECTS = ext-vnd-report.lo \
+ ext-vnd-report-common.lo $(am__objects_1)
+libsieve_ext_vnd_report_la_OBJECTS = \
+ $(am_libsieve_ext_vnd_report_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cmd-report.Plo \
+ ./$(DEPDIR)/ext-vnd-report-common.Plo \
+ ./$(DEPDIR)/ext-vnd-report.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_ext_vnd_report_la_SOURCES)
+DIST_SOURCES = $(libsieve_ext_vnd_report_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_ext_vnd_report.la
+AM_CPPFLAGS = \
+ -I$(srcdir)/../../.. \
+ -I$(srcdir)/../../../util \
+ $(LIBDOVECOT_INCLUDE)
+
+commands = \
+ cmd-report.c
+
+libsieve_ext_vnd_report_la_SOURCES = \
+ ext-vnd-report.c \
+ ext-vnd-report-common.c \
+ $(commands)
+
+noinst_HEADERS = \
+ ext-vnd-report-common.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/vnd.dovecot/report/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/plugins/vnd.dovecot/report/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_ext_vnd_report.la: $(libsieve_ext_vnd_report_la_OBJECTS) $(libsieve_ext_vnd_report_la_DEPENDENCIES) $(EXTRA_libsieve_ext_vnd_report_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_ext_vnd_report_la_OBJECTS) $(libsieve_ext_vnd_report_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-report.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-vnd-report-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-vnd-report.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/cmd-report.Plo
+ -rm -f ./$(DEPDIR)/ext-vnd-report-common.Plo
+ -rm -f ./$(DEPDIR)/ext-vnd-report.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/cmd-report.Plo
+ -rm -f ./$(DEPDIR)/ext-vnd-report-common.Plo
+ -rm -f ./$(DEPDIR)/ext-vnd-report.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
new file mode 100644
index 0000000..af53e42
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
@@ -0,0 +1,692 @@
+/* Copyright (c) 2016-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "ioloop.h"
+#include "hostpid.h"
+#include "str-sanitize.h"
+#include "istream.h"
+#include "ostream.h"
+#include "message-date.h"
+#include "message-size.h"
+#include "mail-storage.h"
+
+#include "rfc2822.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-address.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-message.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-result.h"
+#include "sieve-address.h"
+#include "sieve-message.h"
+#include "sieve-smtp.h"
+
+#include "ext-vnd-report-common.h"
+
+#include <ctype.h>
+
+/* Report command
+ *
+ * Syntax:
+ * report [:headers_only] <feedback-type: string>
+ * <message: string> <address: string>
+ *
+ */
+
+static bool
+cmd_report_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool
+cmd_report_validate(struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool
+cmd_report_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+const struct sieve_command_def cmd_report = {
+ .identifier = "report",
+ .type = SCT_COMMAND,
+ .positional_args = 3,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = cmd_report_registered,
+ .validate = cmd_report_validate,
+ .generate = cmd_report_generate
+};
+
+/*
+ * Tagged arguments
+ */
+
+static const struct sieve_argument_def report_headers_only_tag = {
+ .identifier = "headers_only"
+};
+
+/*
+ * Report operation
+ */
+
+static bool
+cmd_report_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_report_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def report_operation = {
+ .mnemonic = "REPORT",
+ .ext_def = &vnd_report_extension,
+ .code = 0,
+ .dump = cmd_report_operation_dump,
+ .execute = cmd_report_operation_execute
+};
+
+/* Codes for optional operands */
+
+enum cmd_report_optional {
+ OPT_END,
+ OPT_HEADERS_ONLY
+};
+
+/*
+ * Report action
+ */
+
+/* Forward declarations */
+
+static int
+act_report_check_duplicate(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other);
+static void
+act_report_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv, bool *keep);
+static int
+act_report_commit(const struct sieve_action_exec_env *aenv, void *tr_context);
+
+/* Action object */
+
+const struct sieve_action_def act_report = {
+ .name = "report",
+ .check_duplicate = act_report_check_duplicate,
+ .print = act_report_print,
+ .commit = act_report_commit
+};
+
+/* Action data */
+
+struct act_report_data {
+ const char *feedback_type;
+ const char *message;
+ struct smtp_address *to_address;
+ bool headers_only:1;
+};
+
+/*
+ * Command registration
+ */
+
+static bool
+cmd_report_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &report_headers_only_tag,
+ OPT_HEADERS_ONLY);
+ return TRUE;
+}
+
+/*
+ * Command validation
+ */
+
+static bool
+cmd_report_validate(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+
+ /* type */
+ if (!sieve_validate_positional_argument(valdtr, cmd, arg,
+ "feedback-type", 1,
+ SAAT_STRING))
+ return FALSE;
+ if (!sieve_validator_argument_activate(valdtr, cmd, arg, FALSE))
+ return FALSE;
+
+ if (sieve_argument_is_string_literal(arg)) {
+ string_t *fbtype = sieve_ast_argument_str(arg);
+ const char *feedback_type;
+
+ T_BEGIN {
+ /* Check feedback type */
+ feedback_type =
+ ext_vnd_report_parse_feedback_type(str_c(fbtype));
+
+ if (feedback_type == NULL) {
+ sieve_argument_validate_error(
+ valdtr, arg,
+ "specified feedback type `%s' is invalid",
+ str_sanitize(str_c(fbtype),128));
+ }
+ } T_END;
+
+ if (feedback_type == NULL)
+ return FALSE;
+ }
+ arg = sieve_ast_argument_next(arg);
+
+ /* message */
+ if (!sieve_validate_positional_argument(valdtr, cmd, arg, "message",
+ 2, SAAT_STRING))
+ return FALSE;
+ if (!sieve_validator_argument_activate(valdtr, cmd, arg, FALSE))
+ return FALSE;
+ arg = sieve_ast_argument_next(arg);
+
+ /* address */
+ if (!sieve_validate_positional_argument(valdtr, cmd, arg, "address",
+ 3, SAAT_STRING))
+ return FALSE;
+ if (!sieve_validator_argument_activate(valdtr, cmd, arg, FALSE))
+ return FALSE;
+
+ /* We can only assess the validity of the outgoing address when it is a
+ string literal. For runtime-generated strings this needs to be done
+ at runtime.
+ */
+ if (sieve_argument_is_string_literal(arg)) {
+ string_t *raw_address = sieve_ast_argument_str(arg);
+ const char *error;
+ bool result;
+
+ T_BEGIN {
+ /* Parse the address */
+ result = sieve_address_validate_str(raw_address, &error);
+ if (!result) {
+ sieve_argument_validate_error(
+ valdtr, arg,
+ "specified report address '%s' is invalid: %s",
+ str_sanitize(str_c(raw_address),128),
+ error);
+ }
+ } T_END;
+
+ return result;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+cmd_report_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &report_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, cmd, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+cmd_report_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "REPORT");
+ sieve_code_descend(denv);
+
+ /* Dump optional operands */
+ for (;;) {
+ int opt;
+
+ if ((opt = sieve_opr_optional_dump(denv, address,
+ &opt_code)) < 0)
+ return FALSE;
+
+ if (opt == 0)
+ break;
+
+ switch (opt_code) {
+ case OPT_HEADERS_ONLY:
+ sieve_code_dumpf(denv, "headers_only");
+ break;
+ default:
+ return FALSE;
+ }
+ }
+
+ return (sieve_opr_string_dump(denv, address, "feedback-type") &&
+ sieve_opr_string_dump(denv, address, "message") &&
+ sieve_opr_string_dump(denv, address, "address"));
+}
+
+/*
+ * Code execution
+ */
+
+
+static int
+cmd_report_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ struct act_report_data *act;
+ string_t *fbtype, *message, *to_address;
+ const char *feedback_type, *error;
+ const struct smtp_address *parsed_address;
+ int opt_code = 0, ret = 0;
+ bool headers_only = FALSE;
+ pool_t pool;
+
+ /*
+ * Read operands
+ */
+
+ /* Optional operands */
+
+ for (;;) {
+ int opt;
+
+ if ((opt = sieve_opr_optional_read(renv, address,
+ &opt_code)) < 0)
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ if (opt == 0)
+ break;
+
+ switch (opt_code) {
+ case OPT_HEADERS_ONLY:
+ headers_only = TRUE;
+ break;
+ default:
+ sieve_runtime_trace_error(
+ renv, "unknown optional operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ }
+
+ /* Fixed operands */
+
+ if ((ret = sieve_opr_string_read(renv, address, "feedback-type",
+ &fbtype)) <= 0)
+ return ret;
+ if ((ret = sieve_opr_string_read(renv, address, "message",
+ &message)) <= 0)
+ return ret;
+ if ((ret = sieve_opr_string_read(renv, address, "address",
+ &to_address)) <= 0)
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ /* Verify and trim feedback type */
+ feedback_type = ext_vnd_report_parse_feedback_type(str_c(fbtype));
+ if (feedback_type == NULL) {
+ sieve_runtime_error(
+ renv, NULL,
+ "specified report feedback type `%s' is invalid",
+ str_sanitize(str_c(fbtype), 256));
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ /* Verify and normalize the address to 'local_part@domain' */
+ parsed_address = sieve_address_parse_str(to_address, &error);
+ if (parsed_address == NULL) {
+ sieve_runtime_error(
+ renv, NULL,
+ "specified report address '%s' is invalid: %s",
+ str_sanitize(str_c(to_address),128), error);
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ /* Trace */
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_ACTIONS)) {
+ sieve_runtime_trace(renv, 0, "report action");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(
+ renv, 0, "report incoming message as `%s' to address %s",
+ str_sanitize(str_c(fbtype), 32),
+ smtp_address_encode_path(parsed_address));
+ }
+
+ /* Add report action to the result */
+
+ pool = sieve_result_pool(renv->result);
+ act = p_new(pool, struct act_report_data, 1);
+ act->headers_only = headers_only;
+ act->feedback_type = p_strdup(pool, feedback_type);
+ act->message = p_strdup(pool, str_c(message));
+ act->to_address = smtp_address_clone(pool, parsed_address);
+
+ if (sieve_result_add_action(renv, this_ext, "report", &act_report, NULL,
+ (void *)act, 0, TRUE) < 0)
+ return SIEVE_EXEC_FAILURE;
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Action
+ */
+
+/* Runtime verification */
+
+static bool
+act_report_equals(const struct sieve_script_env *senv ATTR_UNUSED,
+ const struct sieve_action *act1,
+ const struct sieve_action *act2)
+{
+ struct act_report_data *rdd1 = (struct act_report_data *)act1->context;
+ struct act_report_data *rdd2 = (struct act_report_data *)act2->context;
+
+ /* Address is already normalized */
+ return (smtp_address_equals(rdd1->to_address, rdd2->to_address));
+}
+
+static int
+act_report_check_duplicate(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+
+ return (act_report_equals(eenv->scriptenv, act, act_other) ? 1 : 0);
+}
+
+/* Result printing */
+
+static void
+act_report_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv,
+ bool *keep ATTR_UNUSED)
+{
+ const struct act_report_data *rdd =
+ (struct act_report_data *)action->context;
+
+ sieve_result_action_printf(rpenv,
+ "report incoming message as `%s' to: %s",
+ str_sanitize(rdd->feedback_type, 32),
+ smtp_address_encode_path(rdd->to_address));
+}
+
+/* Result execution */
+
+static bool _contains_8bit(const char *msg)
+{
+ const unsigned char *s = (const unsigned char *)msg;
+
+ for (; *s != '\0'; s++) {
+ if ((*s & 0x80) != 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static int
+act_report_send(const struct sieve_action_exec_env *aenv,
+ const struct ext_report_config *config,
+ const struct act_report_data *act)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_instance *svinst = eenv->svinst;
+ struct sieve_message_context *msgctx = aenv->msgctx;
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ const struct sieve_message_data *msgdata = eenv->msgdata;
+ struct sieve_address_source report_from = config->report_from;
+ const struct smtp_address *sender, *user;
+ struct sieve_smtp_context *sctx;
+ struct istream *input;
+ struct ostream *output;
+ string_t *msg;
+ const char *const *headers;
+ const char *outmsgid, *boundary, *error, *subject, *from;
+ int ret;
+
+ /* Just to be sure */
+ if (!sieve_smtp_available(senv)) {
+ sieve_result_global_warning(
+ aenv, "report action has no means to send mail");
+ return SIEVE_EXEC_OK;
+ }
+
+ /* Make sure we have a subject for our report */
+ if ((ret = mail_get_headers_utf8(msgdata->mail, "subject",
+ &headers)) < 0) {
+ return sieve_result_mail_error(
+ aenv, msgdata->mail,
+ "failed to read header field `subject'");
+ }
+ if (ret > 0 && headers[0] != NULL)
+ subject = t_strconcat("Report: ", headers[0], NULL);
+ else
+ subject = "Report: (message without subject)";
+
+ /* Determine from address */
+ if (report_from.type == SIEVE_ADDRESS_SOURCE_POSTMASTER) {
+ report_from.type = SIEVE_ADDRESS_SOURCE_DEFAULT;
+ report_from.address = NULL;
+ }
+ if (sieve_address_source_get_address(
+ &report_from, svinst, senv, msgctx, eenv->flags,
+ &sender) > 0 && sender != NULL)
+ from = smtp_address_encode_path(sender);
+ else
+ from = sieve_get_postmaster_address(senv);
+
+ /* Start message */
+ sctx = sieve_smtp_start_single(senv, act->to_address, NULL, &output);
+
+ outmsgid = sieve_message_get_new_id(svinst);
+ boundary = t_strdup_printf("%s/%s", my_pid, svinst->hostname);
+
+ /* Compose main report headers */
+ msg = t_str_new(512);
+ rfc2822_header_write(msg, "X-Sieve", SIEVE_IMPLEMENTATION);
+ rfc2822_header_write(msg, "Message-ID", outmsgid);
+ rfc2822_header_write(msg, "Date", message_date_create(ioloop_time));
+
+ rfc2822_header_write(msg, "From", from);
+ rfc2822_header_write(msg, "To",
+ smtp_address_encode_path(act->to_address));
+
+ if (_contains_8bit(subject))
+ rfc2822_header_utf8_printf(msg, "Subject", "%s", subject);
+ else
+ rfc2822_header_printf(msg, "Subject", "%s", subject);
+
+ rfc2822_header_write(msg, "Auto-Submitted", "auto-generated (report)");
+
+ rfc2822_header_write(msg, "MIME-Version", "1.0");
+ rfc2822_header_printf(msg, "Content-Type",
+ "multipart/report; report-type=feedback-report;\n"
+ "boundary=\"%s\"", boundary);
+
+ str_append(msg, "\r\nThis is a MIME-encapsulated message\r\n\r\n");
+
+ /* Human-readable report */
+ str_printfa(msg, "--%s\r\n", boundary);
+ if (_contains_8bit(act->message)) {
+ rfc2822_header_write(msg, "Content-Type",
+ "text/plain; charset=utf-8");
+ rfc2822_header_write(msg, "Content-Transfer-Encoding", "8bit");
+ } else {
+ rfc2822_header_write(msg, "Content-Type",
+ "text/plain; charset=us-ascii");
+ rfc2822_header_write(msg, "Content-Transfer-Encoding", "7bit");
+ }
+ rfc2822_header_write(msg, "Content-Disposition", "inline");
+
+ str_printfa(msg, "\r\n%s\r\n\r\n", act->message);
+ o_stream_nsend(output, str_data(msg), str_len(msg));
+
+ /* Machine-readable report */
+ str_truncate(msg, 0);
+ str_printfa(msg, "--%s\r\n", boundary);
+ rfc2822_header_write(msg, "Content-Type", "message/feedback-report");
+ str_append(msg, "\r\n");
+
+ rfc2822_header_write(msg, "Version", "1");
+ rfc2822_header_write(msg, "Feedback-Type", act->feedback_type);
+ rfc2822_header_write(msg, "User-Agent",
+ PACKAGE_NAME "/" PACKAGE_VERSION " "
+ PIGEONHOLE_NAME "/" PIGEONHOLE_VERSION);
+
+ if ((eenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0) {
+ const struct smtp_address *sender, *orig_recipient;
+
+ sender = sieve_message_get_sender(msgctx);
+ orig_recipient = sieve_message_get_orig_recipient(msgctx);
+
+ rfc2822_header_write(msg, "Original-Mail-From",
+ smtp_address_encode_path(sender));
+ if (orig_recipient != NULL) {
+ rfc2822_header_write(
+ msg, "Original-Rcpt-To",
+ smtp_address_encode_path(orig_recipient));
+ }
+ }
+ if (svinst->user_email != NULL)
+ user = svinst->user_email;
+ else if ((eenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) != 0 ||
+ (user = sieve_message_get_orig_recipient(msgctx)) == NULL)
+ user = sieve_get_user_email(svinst);
+ if (user != NULL) {
+ rfc2822_header_write(msg, "Dovecot-Reporting-User",
+ smtp_address_encode_path(user));
+ }
+ str_append(msg, "\r\n");
+
+ o_stream_nsend(output, str_data(msg), str_len(msg));
+
+ /* Original message */
+ str_truncate(msg, 0);
+ str_printfa(msg, "--%s\r\n", boundary);
+ if (act->headers_only) {
+ rfc2822_header_write(msg, "Content-Type",
+ "text/rfc822-headers");
+ } else {
+ rfc2822_header_write(msg, "Content-Type", "message/rfc822");
+ }
+ rfc2822_header_write(msg, "Content-Disposition", "attachment");
+ str_append(msg, "\r\n");
+ o_stream_nsend(output, str_data(msg), str_len(msg));
+
+ if (act->headers_only) {
+ struct message_size hdr_size;
+ ret = mail_get_hdr_stream(msgdata->mail, &hdr_size, &input);
+ if (ret >= 0) {
+ input = i_stream_create_limit(
+ input, hdr_size.physical_size);
+ }
+ } else {
+ ret = mail_get_stream(msgdata->mail, NULL, NULL, &input);
+ if (ret >= 0)
+ i_stream_ref(input);
+ }
+ if (ret < 0) {
+ sieve_smtp_abort(sctx);
+ return sieve_result_mail_error(aenv, msgdata->mail,
+ "failed to read input message");
+ }
+
+ o_stream_nsend_istream(output, input);
+
+ if (input->stream_errno != 0) {
+ /* Error; clean up */
+ sieve_result_critical(aenv, "failed to read input message",
+ "read(%s) failed: %s",
+ i_stream_get_name(input),
+ i_stream_get_error(input));
+ i_stream_unref(&input);
+ sieve_smtp_abort(sctx);
+ return SIEVE_EXEC_OK;
+ }
+ i_stream_unref(&input);
+
+ str_truncate(msg, 0);
+ if (!act->headers_only)
+ str_printfa(msg, "\r\n");
+ str_printfa(msg, "\r\n--%s--\r\n", boundary);
+ o_stream_nsend(output, str_data(msg), str_len(msg));
+
+ /* Finish sending message */
+ if ((ret = sieve_smtp_finish(sctx, &error)) <= 0) {
+ if (ret < 0) {
+ sieve_result_global_error(
+ aenv, "failed to send `%s' report to <%s>: %s "
+ "(temporary failure)",
+ str_sanitize(act->feedback_type, 32),
+ smtp_address_encode(act->to_address),
+ str_sanitize(error, 512));
+ } else {
+ sieve_result_global_log_error(
+ aenv, "failed to send `%s' report to <%s>: %s "
+ "(permanent failure)",
+ str_sanitize(act->feedback_type, 32),
+ smtp_address_encode(act->to_address),
+ str_sanitize(error, 512));
+ }
+ } else {
+ eenv->exec_status->significant_action_executed = TRUE;
+
+ struct event_passthrough *e =
+ sieve_action_create_finish_event(aenv)->
+ add_str("report_target",
+ smtp_address_encode(act->to_address))->
+ add_str("report_type",
+ str_sanitize(act->feedback_type, 32));
+
+ sieve_result_event_log(aenv, e->event(),
+ "sent `%s' report to <%s>",
+ str_sanitize(act->feedback_type, 32),
+ smtp_address_encode(act->to_address));
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+static int
+act_report_commit(const struct sieve_action_exec_env *aenv,
+ void *tr_context ATTR_UNUSED)
+{
+ const struct sieve_action *action = aenv->action;
+ const struct sieve_extension *ext = action->ext;
+ const struct ext_report_config *config =
+ (const struct ext_report_config *)ext->context;
+ const struct act_report_data *act =
+ (const struct act_report_data *)action->context;
+ int ret;
+
+ T_BEGIN {
+ ret = act_report_send(aenv, config, act);
+ } T_END;
+
+ if (ret == SIEVE_EXEC_TEMP_FAILURE)
+ return SIEVE_EXEC_TEMP_FAILURE;
+
+ /* Ignore all other errors */
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.c b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.c
new file mode 100644
index 0000000..d22ad16
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.c
@@ -0,0 +1,51 @@
+/* Copyright (c) 2016-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "rfc822-parser.h"
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+
+#include "ext-vnd-report-common.h"
+
+bool ext_report_load
+(const struct sieve_extension *ext, void **context)
+{
+ struct sieve_instance *svinst = ext->svinst;
+ struct ext_report_config *config;
+
+ config = p_new(svinst->pool, struct ext_report_config, 1);
+
+ (void)sieve_address_source_parse_from_setting(svinst,
+ svinst->pool, "sieve_report_from", &config->report_from);
+
+ *context = (void *) config;
+ return TRUE;
+}
+
+const char *
+ext_vnd_report_parse_feedback_type(const char *feedback_type)
+{
+ struct rfc822_parser_context parser;
+ string_t *token;
+
+ /* Initialize parsing */
+ rfc822_parser_init(&parser,
+ (const unsigned char *)feedback_type, strlen(feedback_type), NULL);
+ (void)rfc822_skip_lwsp(&parser);
+
+ /* Parse MIME token */
+ token = t_str_new(64);
+ if (rfc822_parse_mime_token(&parser, token) < 0)
+ return NULL;
+
+ /* Content-type value must end here, otherwise it is invalid after all */
+ (void)rfc822_skip_lwsp(&parser);
+ if ( parser.data != parser.end )
+ return NULL;
+
+ /* Success */
+ return str_c(token);
+}
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.h b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.h
new file mode 100644
index 0000000..11a3757
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.h
@@ -0,0 +1,40 @@
+#ifndef EXT_REPORT_COMMON_H
+#define EXT_REPORT_COMMON_H
+
+/*
+ * Extension configuration
+ */
+
+struct ext_report_config {
+ struct sieve_address_source report_from;
+};
+
+/*
+ * Extension
+ */
+
+extern const struct sieve_extension_def vnd_report_extension;
+
+bool ext_report_load
+ (const struct sieve_extension *ext, void **context);
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def cmd_report;
+
+/*
+ * Operations
+ */
+
+extern const struct sieve_operation_def report_operation;
+
+/*
+ * RFC 5965 feedback-type
+ */
+
+const char *
+ext_vnd_report_parse_feedback_type(const char *feedback_type);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report.c b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report.c
new file mode 100644
index 0000000..a5fb64c
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report.c
@@ -0,0 +1,52 @@
+/* Copyright (c) 2016-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension report
+ * ----------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: draft-ietf-sieve-report-00.txt
+ * Implementation: full, but deprecated; provided for backwards compatibility
+ * Status: testing
+ *
+ */
+
+#include "sieve-common.h"
+
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-actions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-result.h"
+
+#include "ext-vnd-report-common.h"
+
+/*
+ * Extension
+ */
+
+static bool ext_report_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def vnd_report_extension = {
+ .name = "vnd.dovecot.report",
+ .load = ext_report_load,
+ .validator_load = ext_report_validator_load,
+ SIEVE_EXT_DEFINE_OPERATION(report_operation)
+};
+
+/*
+ * Extension validation
+ */
+
+static bool ext_report_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Register new commands */
+ sieve_validator_register_command(valdtr, ext, &cmd_report);
+
+ return TRUE;
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-actions.c b/pigeonhole/src/lib-sieve/sieve-actions.c
new file mode 100644
index 0000000..86c9954
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-actions.c
@@ -0,0 +1,1096 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "strfuncs.h"
+#include "ioloop.h"
+#include "hostpid.h"
+#include "str-sanitize.h"
+#include "unichar.h"
+#include "istream.h"
+#include "istream-header-filter.h"
+#include "ostream.h"
+#include "smtp-params.h"
+#include "mail-storage.h"
+#include "message-date.h"
+#include "message-size.h"
+
+#include "rfc2822.h"
+
+#include "sieve-code.h"
+#include "sieve-settings.h"
+#include "sieve-extensions.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-result.h"
+#include "sieve-actions.h"
+#include "sieve-message.h"
+#include "sieve-smtp.h"
+
+/*
+ * Action execution environment
+ */
+
+struct event_passthrough *
+sieve_action_create_finish_event(const struct sieve_action_exec_env *aenv)
+{
+ struct event_passthrough *e =
+ event_create_passthrough(aenv->event)->
+ set_name("sieve_action_finished");
+
+ return e;
+}
+
+/*
+ * Action instance
+ */
+
+bool sieve_action_is_executed(const struct sieve_action *act,
+ struct sieve_result *result)
+{
+ unsigned int cur_exec_seq = sieve_result_get_exec_seq(result);
+
+ i_assert(act->exec_seq <= cur_exec_seq);
+ return (act->exec_seq < cur_exec_seq);
+}
+
+/*
+ * Side-effect operand
+ */
+
+const struct sieve_operand_class
+sieve_side_effect_operand_class = { "SIDE-EFFECT" };
+
+bool sieve_opr_side_effect_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ struct sieve_side_effect seffect;
+ const struct sieve_side_effect_def *sdef;
+
+ if (!sieve_opr_object_dump(denv, &sieve_side_effect_operand_class,
+ address, &seffect.object))
+ return FALSE;
+
+ sdef = seffect.def =
+ (const struct sieve_side_effect_def *)seffect.object.def;
+
+ if (sdef->dump_context != NULL) {
+ sieve_code_descend(denv);
+ if (!sdef->dump_context(&seffect, denv, address))
+ return FALSE;
+ sieve_code_ascend(denv);
+ }
+ return TRUE;
+}
+
+int sieve_opr_side_effect_read(const struct sieve_runtime_env *renv,
+ sieve_size_t *address,
+ struct sieve_side_effect *seffect)
+{
+ const struct sieve_side_effect_def *sdef;
+ int ret;
+
+ seffect->context = NULL;
+
+ if (!sieve_opr_object_read(renv, &sieve_side_effect_operand_class,
+ address, &seffect->object))
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ sdef = seffect->def =
+ (const struct sieve_side_effect_def *)seffect->object.def;
+
+ if (sdef->read_context != NULL &&
+ (ret = sdef->read_context(seffect, renv, address,
+ &seffect->context)) <= 0)
+ return ret;
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Optional operands
+ */
+
+int sieve_action_opr_optional_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address, signed int *opt_code)
+{
+ signed int _opt_code = 0;
+ bool final = FALSE, opok = TRUE;
+
+ if (opt_code == NULL) {
+ opt_code = &_opt_code;
+ final = TRUE;
+ }
+
+ while (opok) {
+ int opt;
+
+ opt = sieve_opr_optional_dump(denv, address, opt_code);
+ if (opt <= 0)
+ return opt;
+
+ if (*opt_code == SIEVE_OPT_SIDE_EFFECT)
+ opok = sieve_opr_side_effect_dump(denv, address);
+ else
+ return (final ? -1 : 1);
+ }
+
+ return -1;
+}
+
+int sieve_action_opr_optional_read(const struct sieve_runtime_env *renv,
+ sieve_size_t *address,
+ signed int *opt_code, int *exec_status,
+ struct sieve_side_effects_list **list)
+{
+ signed int _opt_code = 0;
+ bool final = FALSE;
+ int ret;
+
+ if (opt_code == NULL) {
+ opt_code = &_opt_code;
+ final = TRUE;
+ }
+
+ if (exec_status != NULL)
+ *exec_status = SIEVE_EXEC_OK;
+
+ for (;;) {
+ int opt;
+
+ opt = sieve_opr_optional_read(renv, address, opt_code);
+ if (opt <= 0) {
+ if (opt < 0 && exec_status != NULL)
+ *exec_status = SIEVE_EXEC_BIN_CORRUPT;
+ return opt;
+ }
+
+ if (*opt_code == SIEVE_OPT_SIDE_EFFECT) {
+ struct sieve_side_effect seffect;
+
+ i_assert(list != NULL);
+
+ ret = sieve_opr_side_effect_read(renv, address,
+ &seffect);
+ if (ret <= 0) {
+ if (exec_status != NULL)
+ *exec_status = ret;
+ return -1;
+ }
+
+ if (*list == NULL) {
+ *list = sieve_side_effects_list_create(
+ renv->result);
+ }
+
+ sieve_side_effects_list_add(*list, &seffect);
+ } else {
+ if (final) {
+ sieve_runtime_trace_error(
+ renv, "invalid optional operand");
+ if (exec_status != NULL)
+ *exec_status = SIEVE_EXEC_BIN_CORRUPT;
+ return -1;
+ }
+ return 1;
+ }
+ }
+
+ i_unreached();
+ return -1;
+}
+
+/*
+ * Store action
+ */
+
+/* Forward declarations */
+
+static bool
+act_store_equals(const struct sieve_script_env *senv,
+ const struct sieve_action *act1,
+ const struct sieve_action *act2);
+
+static int
+act_store_check_duplicate(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other);
+static void
+act_store_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv, bool *keep);
+
+static int
+act_store_start(const struct sieve_action_exec_env *aenv, void **tr_context);
+static int
+act_store_execute(const struct sieve_action_exec_env *aenv, void *tr_context,
+ bool *keep);
+static int
+act_store_commit(const struct sieve_action_exec_env *aenv, void *tr_context);
+static void
+act_store_rollback(const struct sieve_action_exec_env *aenv, void *tr_context,
+ bool success);
+
+/* Action object */
+
+const struct sieve_action_def act_store = {
+ .name = "store",
+ .flags =
+ SIEVE_ACTFLAG_TRIES_DELIVER |
+ SIEVE_ACTFLAG_MAIL_STORAGE,
+ .equals = act_store_equals,
+ .check_duplicate = act_store_check_duplicate,
+ .print = act_store_print,
+ .start = act_store_start,
+ .execute = act_store_execute,
+ .commit = act_store_commit,
+ .rollback = act_store_rollback,
+};
+
+/* API */
+
+int sieve_act_store_add_to_result(const struct sieve_runtime_env *renv,
+ const char *name,
+ struct sieve_side_effects_list *seffects,
+ const char *mailbox)
+{
+ pool_t pool;
+ struct act_store_context *act;
+
+ /* Add redirect action to the result */
+ pool = sieve_result_pool(renv->result);
+ act = p_new(pool, struct act_store_context, 1);
+ act->mailbox = p_strdup(pool, mailbox);
+
+ return sieve_result_add_action(renv, NULL, name, &act_store, seffects,
+ (void *)act, 0, TRUE);
+}
+
+void sieve_act_store_add_flags(const struct sieve_action_exec_env *aenv,
+ void *tr_context, const char *const *keywords,
+ enum mail_flags flags)
+{
+ struct act_store_transaction *trans =
+ (struct act_store_transaction *)tr_context;
+
+ i_assert(trans != NULL);
+
+ /* Assign mail keywords for subsequent mailbox_copy() */
+ if (*keywords != NULL) {
+ const char *const *kw;
+
+ if (!array_is_created(&trans->keywords)) {
+ pool_t pool = sieve_result_pool(aenv->result);
+ p_array_init(&trans->keywords, pool, 2);
+ }
+
+ kw = keywords;
+ while (*kw != NULL) {
+ array_append(&trans->keywords, kw, 1);
+ kw++;
+ }
+ }
+
+ /* Assign mail flags for subsequent mailbox_copy() */
+ trans->flags |= flags;
+
+ trans->flags_altered = TRUE;
+}
+
+/* Equality */
+
+static bool
+act_store_equals(const struct sieve_script_env *senv,
+ const struct sieve_action *act1,
+ const struct sieve_action *act2)
+{
+ struct act_store_context *st_ctx1 =
+ (act1 == NULL ?
+ NULL : (struct act_store_context *)act1->context);
+ struct act_store_context *st_ctx2 =
+ (act2 == NULL ?
+ NULL : (struct act_store_context *)act2->context);
+ const char *mailbox1, *mailbox2;
+
+ /* FIXME: consider namespace aliases */
+
+ if (st_ctx1 == NULL && st_ctx2 == NULL)
+ return TRUE;
+
+ mailbox1 = (st_ctx1 == NULL ?
+ SIEVE_SCRIPT_DEFAULT_MAILBOX(senv) : st_ctx1->mailbox);
+ mailbox2 = (st_ctx2 == NULL ?
+ SIEVE_SCRIPT_DEFAULT_MAILBOX(senv) : st_ctx2->mailbox);
+
+ if (strcmp(mailbox1, mailbox2) == 0)
+ return TRUE;
+
+ return (strcasecmp(mailbox1, "INBOX") == 0 &&
+ strcasecmp(mailbox2, "INBOX") == 0);
+}
+
+/* Result verification */
+
+static int
+act_store_check_duplicate(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+
+ return (act_store_equals(eenv->scriptenv, act, act_other) ? 1 : 0);
+}
+
+/* Result printing */
+
+static void
+act_store_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv, bool *keep)
+{
+ struct act_store_context *ctx =
+ (struct act_store_context *)action->context;
+ const char *mailbox;
+
+ mailbox = (ctx == NULL ?
+ SIEVE_SCRIPT_DEFAULT_MAILBOX(rpenv->scriptenv) :
+ ctx->mailbox);
+
+ sieve_result_action_printf(rpenv, "store message in folder: %s",
+ str_sanitize(mailbox, 128));
+
+ *keep = FALSE;
+}
+
+/* Action implementation */
+
+void sieve_act_store_get_storage_error(const struct sieve_action_exec_env *aenv,
+ struct act_store_transaction *trans)
+{
+ pool_t pool = sieve_result_pool(aenv->result);
+
+ trans->error = p_strdup(pool,
+ mailbox_get_last_internal_error(trans->box,
+ &trans->error_code));
+}
+
+static bool
+act_store_mailbox_alloc(const struct sieve_action_exec_env *aenv,
+ const char *mailbox, struct mailbox **box_r,
+ enum mail_error *error_code_r, const char **error_r)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct mailbox *box;
+ struct mail_storage **storage = &(eenv->exec_status->last_storage);
+ enum mailbox_flags flags = MAILBOX_FLAG_POST_SESSION;
+
+ *box_r = NULL;
+ *error_code_r = MAIL_ERROR_NONE;
+ *error_r = NULL;
+
+ if (!uni_utf8_str_is_valid(mailbox)) {
+ /* Just a precaution; already (supposed to be) checked at
+ compiletime/runtime.
+ */
+ *error_r = t_strdup_printf("mailbox name not utf-8: %s",
+ mailbox);
+ *error_code_r = MAIL_ERROR_PARAMS;
+ return FALSE;
+ }
+
+ if (eenv->scriptenv->mailbox_autocreate)
+ flags |= MAILBOX_FLAG_AUTO_CREATE;
+ if (eenv->scriptenv->mailbox_autosubscribe)
+ flags |= MAILBOX_FLAG_AUTO_SUBSCRIBE;
+ *box_r = box = mailbox_alloc_for_user(eenv->scriptenv->user, mailbox,
+ flags);
+ *storage = mailbox_get_storage(box);
+
+ return TRUE;
+}
+
+static int
+act_store_start(const struct sieve_action_exec_env *aenv, void **tr_context)
+{
+ const struct sieve_action *action = aenv->action;
+ struct act_store_context *ctx =
+ (struct act_store_context *)action->context;
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ struct act_store_transaction *trans;
+ struct mailbox *box = NULL;
+ pool_t pool = sieve_result_pool(aenv->result);
+ const char *error = NULL;
+ enum mail_error error_code = MAIL_ERROR_NONE;
+ bool disabled = FALSE, alloc_failed = FALSE;
+
+ /* If context is NULL, the store action is the result of (implicit)
+ keep.
+ */
+ if (ctx == NULL) {
+ ctx = p_new(pool, struct act_store_context, 1);
+ ctx->mailbox =
+ p_strdup(pool, SIEVE_SCRIPT_DEFAULT_MAILBOX(senv));
+ }
+
+ e_debug(aenv->event, "Start storing into mailbox %s", ctx->mailbox);
+
+ /* Open the requested mailbox */
+
+ /* NOTE: The caller of the sieve library is allowed to leave user set
+ to NULL. This implementation will then skip actually storing the
+ message.
+ */
+ if (senv->user != NULL) {
+ if (!act_store_mailbox_alloc(aenv, ctx->mailbox, &box,
+ &error_code, &error))
+ alloc_failed = TRUE;
+ } else {
+ disabled = TRUE;
+ }
+
+ /* Create transaction context */
+ trans = p_new(pool, struct act_store_transaction, 1);
+
+ trans->context = ctx;
+ trans->box = box;
+ trans->flags = 0;
+
+ trans->mailbox_name = ctx->mailbox;
+ trans->mailbox_identifier =
+ p_strdup_printf(pool, "'%s'", str_sanitize(ctx->mailbox, 256));
+
+ trans->disabled = disabled;
+
+ if (alloc_failed) {
+ trans->error = p_strdup(pool, error);
+ trans->error_code = error_code;
+ e_debug(aenv->event, "Failed to open mailbox %s: %s",
+ trans->mailbox_identifier, trans->error);
+ } else {
+ trans->error_code = MAIL_ERROR_NONE;
+ }
+
+ *tr_context = (void *)trans;
+
+ switch (trans->error_code) {
+ case MAIL_ERROR_NONE:
+ case MAIL_ERROR_NOTFOUND:
+ return SIEVE_EXEC_OK;
+ case MAIL_ERROR_TEMP:
+ return SIEVE_EXEC_TEMP_FAILURE;
+ default:
+ break;
+ }
+ return SIEVE_EXEC_FAILURE;
+}
+
+static struct mail_keywords *
+act_store_keywords_create(const struct sieve_action_exec_env *aenv,
+ ARRAY_TYPE(const_string) *keywords,
+ struct mailbox *box, bool create_empty)
+{
+ struct mail_keywords *box_keywords = NULL;
+ const char *const *kwds = NULL;
+
+ if (!array_is_created(keywords) || array_count(keywords) == 0) {
+ if (!create_empty)
+ return NULL;
+ } else {
+ ARRAY_TYPE(const_string) valid_keywords;
+ const char *error;
+ unsigned int count, i;
+
+ kwds = array_get(keywords, &count);
+ t_array_init(&valid_keywords, count);
+
+ for (i = 0; i < count; i++) {
+ if (mailbox_keyword_is_valid(box, kwds[i], &error)) {
+ array_append(&valid_keywords, &kwds[i], 1);
+ continue;
+ }
+
+ sieve_result_warning(aenv,
+ "specified IMAP keyword '%s' is invalid "
+ "(ignored): %s", str_sanitize(kwds[i], 64),
+ sieve_error_from_external(error));
+ }
+
+ array_append_zero(keywords);
+ kwds = array_idx(keywords, 0);
+ }
+
+ if (mailbox_keywords_create(box, kwds, &box_keywords) < 0) {
+ sieve_result_error(
+ aenv, "invalid keywords set for stored message");
+ return NULL;
+ }
+
+ return box_keywords;
+}
+
+static bool have_equal_keywords(struct mail *mail, struct mail_keywords *new_kw)
+{
+ const ARRAY_TYPE(keyword_indexes) *old_kw_arr =
+ mail_get_keyword_indexes(mail);
+ const unsigned int *old_kw;
+ unsigned int i, j;
+
+ if (array_count(old_kw_arr) != new_kw->count)
+ return FALSE;
+ if (new_kw->count == 0)
+ return TRUE;
+
+ old_kw = array_front(old_kw_arr);
+ for (i = 0; i < new_kw->count; i++) {
+ /* new_kw->count equals old_kw's count and it's easier to use */
+ for (j = 0; j < new_kw->count; j++) {
+ if (old_kw[j] == new_kw->idx[i])
+ break;
+ }
+ if (j == new_kw->count)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static int
+act_store_execute(const struct sieve_action_exec_env *aenv, void *tr_context,
+ bool *keep)
+{
+ const struct sieve_action *action = aenv->action;
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct act_store_transaction *trans =
+ (struct act_store_transaction *)tr_context;
+ struct mail *mail = (action->mail != NULL ?
+ action->mail : eenv->msgdata->mail);
+ struct mail_save_context *save_ctx;
+ struct mail_keywords *keywords = NULL;
+ struct mailbox *box;
+ bool backends_equal = FALSE;
+ int status = SIEVE_EXEC_OK;
+
+ /* Verify transaction */
+ if (trans == NULL)
+ return SIEVE_EXEC_FAILURE;
+ box = trans->box;
+
+ /* Check whether we need to do anything */
+ if (trans->disabled) {
+ e_debug(aenv->event, "Skip storing into mailbox %s",
+ trans->mailbox_identifier);
+ *keep = FALSE;
+ return SIEVE_EXEC_OK;
+ }
+
+ /* Exit early if mailbox is not available */
+ if (box == NULL)
+ return SIEVE_EXEC_FAILURE;
+
+ e_debug(aenv->event, "Execute storing into mailbox %s",
+ trans->mailbox_identifier);
+
+ /* Mark attempt to use storage. Can only get here when all previous
+ actions succeeded.
+ */
+ eenv->exec_status->last_storage = mailbox_get_storage(box);
+
+ /* Open the mailbox (may already be open) */
+ if (trans->error_code == MAIL_ERROR_NONE) {
+ if (mailbox_open(box) < 0) {
+ sieve_act_store_get_storage_error(aenv, trans);
+ e_debug(aenv->event, "Failed to open mailbox %s: %s",
+ trans->mailbox_identifier, trans->error);
+ }
+ }
+
+ /* Exit early if transaction already failed */
+ switch (trans->error_code) {
+ case MAIL_ERROR_NONE:
+ break;
+ case MAIL_ERROR_TEMP:
+ return SIEVE_EXEC_TEMP_FAILURE;
+ default:
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ /* If the message originates from the target mailbox, only update the
+ flags and keywords (if not read-only)
+ */
+ if (mailbox_backends_equal(box, mail->box)) {
+ backends_equal = TRUE;
+ } else {
+ struct mail *real_mail;
+
+ if (mail_get_backend_mail(mail, &real_mail) < 0)
+ return SIEVE_EXEC_FAILURE;
+ if (real_mail != mail &&
+ mailbox_backends_equal(box, real_mail->box))
+ backends_equal = TRUE;
+ }
+ if (backends_equal) {
+ trans->redundant = TRUE;
+
+ if (trans->flags_altered && !mailbox_is_readonly(mail->box)) {
+ keywords = act_store_keywords_create(
+ aenv, &trans->keywords, mail->box, TRUE);
+
+ if (keywords != NULL) {
+ if (!have_equal_keywords(mail, keywords)) {
+ eenv->exec_status->significant_action_executed = TRUE;
+ mail_update_keywords(mail, MODIFY_REPLACE, keywords);
+ }
+ mailbox_keywords_unref(&keywords);
+ }
+
+ if ((mail_get_flags(mail) & MAIL_FLAGS_NONRECENT) != trans->flags) {
+ eenv->exec_status->significant_action_executed = TRUE;
+ mail_update_flags(mail, MODIFY_REPLACE, trans->flags);
+ }
+ }
+ e_debug(aenv->event, "Updated existing mail in mailbox %s",
+ trans->mailbox_identifier);
+ return SIEVE_EXEC_OK;
+
+ /* If the message is modified, only store it in the source mailbox when
+ it is not opened read-only. Mail structs of modified messages have
+ their own mailbox, unrelated to the orignal mail, so this case needs
+ to be handled separately.
+ */
+ } else if (mail != eenv->msgdata->mail &&
+ mailbox_is_readonly(eenv->msgdata->mail->box) &&
+ (mailbox_backends_equal(box, eenv->msgdata->mail->box))) {
+ e_debug(aenv->event,
+ "Not modifying exsiting mail in read-only mailbox %s",
+ trans->mailbox_identifier);
+ trans->redundant = TRUE;
+ return SIEVE_EXEC_OK;
+ }
+
+ /* Mark attempt to store in default mailbox */
+ if (strcmp(trans->context->mailbox,
+ SIEVE_SCRIPT_DEFAULT_MAILBOX(eenv->scriptenv)) == 0)
+ eenv->exec_status->tried_default_save = TRUE;
+
+ /* Start mail transaction */
+ trans->mail_trans = mailbox_transaction_begin(
+ box, MAILBOX_TRANSACTION_FLAG_EXTERNAL, __func__);
+
+ /* Store the message */
+ save_ctx = mailbox_save_alloc(trans->mail_trans);
+
+ /* Apply keywords and flags that side-effects may have added */
+ if (trans->flags_altered) {
+ keywords = act_store_keywords_create(aenv, &trans->keywords,
+ box, FALSE);
+
+ if (trans->flags != 0 || keywords != NULL) {
+ eenv->exec_status->significant_action_executed = TRUE;
+ mailbox_save_set_flags(save_ctx, trans->flags, keywords);
+ }
+ } else {
+ mailbox_save_copy_flags(save_ctx, mail);
+ }
+
+ if (mailbox_save_using_mail(&save_ctx, mail) < 0) {
+ sieve_act_store_get_storage_error(aenv, trans);
+ e_debug(aenv->event, "Failed to save to mailbox %s: %s",
+ trans->mailbox_identifier, trans->error);
+
+ status = (trans->error_code == MAIL_ERROR_TEMP ?
+ SIEVE_EXEC_TEMP_FAILURE : SIEVE_EXEC_FAILURE);
+ } else {
+ e_debug(aenv->event, "Saving to mailbox %s successful so far",
+ trans->mailbox_identifier);
+ eenv->exec_status->significant_action_executed = TRUE;
+ }
+
+ /* Deallocate keywords */
+ if (keywords != NULL)
+ mailbox_keywords_unref(&keywords);
+
+ /* Cancel implicit keep if all went well so far */
+ *keep = (status < SIEVE_EXEC_OK);
+
+ return status;
+}
+
+static void
+act_store_log_status(struct act_store_transaction *trans,
+ const struct sieve_action_exec_env *aenv,
+ bool rolled_back, bool status)
+{
+ const char *mailbox_name = trans->mailbox_name;
+ const char *mailbox_identifier = trans->mailbox_identifier;
+
+ if (trans->box != NULL) {
+ const char *mailbox_vname = str_sanitize(mailbox_get_vname(trans->box), 128);
+
+ if (strcmp(trans->mailbox_name, mailbox_vname) != 0) {
+ mailbox_identifier = t_strdup_printf(
+ "%s (%s)", mailbox_identifier,
+ str_sanitize(mailbox_vname, 256));
+ }
+ }
+
+ /* Store disabled? */
+ if (trans->disabled) {
+ sieve_result_global_log(aenv, "store into mailbox %s skipped",
+ mailbox_identifier);
+ /* Store redundant? */
+ } else if (trans->redundant) {
+ sieve_result_global_log(aenv, "left message in mailbox %s",
+ mailbox_identifier);
+ /* Store failed? */
+ } else if (!status) {
+ const char *errstr;
+ enum mail_error error_code;
+
+ if (trans->error == NULL)
+ sieve_act_store_get_storage_error(aenv, trans);
+
+ errstr = trans->error;
+ error_code = trans->error_code;
+
+ if (error_code == MAIL_ERROR_NOQUOTA) {
+ /* Never log quota problems as error in global log */
+ sieve_result_global_log_error(
+ aenv, "failed to store into mailbox %s: %s",
+ mailbox_identifier, errstr);
+ } else if (error_code == MAIL_ERROR_NOTFOUND ||
+ error_code == MAIL_ERROR_PARAMS ||
+ error_code == MAIL_ERROR_PERM) {
+ sieve_result_error(
+ aenv, "failed to store into mailbox %s: %s",
+ mailbox_identifier, errstr);
+ } else {
+ sieve_result_global_error(
+ aenv, "failed to store into mailbox %s: %s",
+ mailbox_identifier, errstr);
+ }
+ /* Store aborted? */
+ } else if (rolled_back) {
+ if (!aenv->action->keep) {
+ sieve_result_global_log(
+ aenv, "store into mailbox %s aborted",
+ mailbox_identifier);
+ } else {
+ e_debug(aenv->event, "Store into mailbox %s aborted",
+ mailbox_identifier);
+ }
+ /* Succeeded */
+ } else {
+ struct event_passthrough *e =
+ sieve_action_create_finish_event(aenv)->
+ add_str("fileinto_mailbox_name", mailbox_name)->
+ add_str("fileinto_mailbox", mailbox_identifier);
+ sieve_result_event_log(aenv, e->event(),
+ "stored mail into mailbox %s",
+ mailbox_identifier);
+ }
+}
+
+static void act_store_cleanup(struct act_store_transaction *trans)
+{
+ if (trans->mail_trans != NULL)
+ mailbox_transaction_rollback(&trans->mail_trans);
+ if (trans->box != NULL)
+ mailbox_free(&trans->box);
+}
+
+static int
+act_store_commit(const struct sieve_action_exec_env *aenv, void *tr_context)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct act_store_transaction *trans =
+ (struct act_store_transaction *)tr_context;
+ bool bail_out = FALSE, status = TRUE;
+ int ret = SIEVE_EXEC_OK;
+
+ /* Verify transaction */
+ if (trans == NULL)
+ return SIEVE_EXEC_FAILURE;
+
+ e_debug(aenv->event, "Commit storing into mailbox %s",
+ trans->mailbox_identifier);
+
+ /* Check whether we can commit this transaction */
+ if (trans->error_code != MAIL_ERROR_NONE) {
+ /* Transaction already failed */
+ bail_out = TRUE;
+ status = FALSE;
+ if (trans->error_code == MAIL_ERROR_TEMP)
+ ret = SIEVE_EXEC_TEMP_FAILURE;
+ else
+ ret = SIEVE_EXEC_FAILURE;
+ /* Check whether we need to do anything */
+ } else if (trans->disabled) {
+ /* Nothing to do */
+ bail_out = TRUE;
+ } else if (trans->redundant) {
+ /* This transaction is redundant */
+ bail_out = TRUE;
+ eenv->exec_status->keep_original = TRUE;
+ eenv->exec_status->message_saved = TRUE;
+ }
+ if (bail_out) {
+ act_store_log_status(trans, aenv, FALSE, status);
+ act_store_cleanup(trans);
+ return ret;
+ }
+
+ i_assert(trans->box != NULL);
+ i_assert(trans->mail_trans != NULL);
+
+ /* Mark attempt to use storage. Can only get here when all previous
+ actions succeeded.
+ */
+ eenv->exec_status->last_storage = mailbox_get_storage(trans->box);
+
+ /* Commit mailbox transaction */
+ status = (mailbox_transaction_commit(&trans->mail_trans) == 0);
+
+ /* Note the fact that the message was stored at least once */
+ if (status)
+ eenv->exec_status->message_saved = TRUE;
+ else
+ eenv->exec_status->store_failed = TRUE;
+
+ /* Log our status */
+ act_store_log_status(trans, aenv, FALSE, status);
+
+ /* Clean up */
+ act_store_cleanup(trans);
+
+ if (status)
+ return SIEVE_EXEC_OK;
+
+ return (trans->error_code == MAIL_ERROR_TEMP ?
+ SIEVE_EXEC_TEMP_FAILURE : SIEVE_EXEC_FAILURE);
+}
+
+static void
+act_store_rollback(const struct sieve_action_exec_env *aenv, void *tr_context,
+ bool success)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct act_store_transaction *trans =
+ (struct act_store_transaction *)tr_context;
+
+ if (trans == NULL)
+ return;
+
+ e_debug(aenv->event, "Roll back storing into mailbox %s",
+ trans->mailbox_identifier);
+
+ i_assert(trans->box != NULL);
+
+ if (!success) {
+ eenv->exec_status->last_storage =
+ mailbox_get_storage(trans->box);
+ eenv->exec_status->store_failed = TRUE;
+ }
+
+ /* Log status */
+ act_store_log_status(trans, aenv, TRUE, success);
+
+ /* Rollback mailbox transaction and clean up */
+ act_store_cleanup(trans);
+}
+
+/*
+ * Redirect action
+ */
+
+int sieve_act_redirect_add_to_result(const struct sieve_runtime_env *renv,
+ const char *name,
+ struct sieve_side_effects_list *seffects,
+ const struct smtp_address *to_address)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ struct sieve_instance *svinst = eenv->svinst;
+ struct act_redirect_context *act;
+ pool_t pool;
+
+ pool = sieve_result_pool(renv->result);
+ act = p_new(pool, struct act_redirect_context, 1);
+ act->to_address = smtp_address_clone(pool, to_address);
+
+ if (sieve_result_add_action(renv, NULL, name, &act_redirect, seffects,
+ (void *)act, svinst->max_redirects,
+ TRUE) < 0)
+ return SIEVE_EXEC_FAILURE;
+
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Action utility functions
+ */
+
+/* Rejecting the mail */
+
+static int
+sieve_action_do_reject_mail(const struct sieve_action_exec_env *aenv,
+ const struct smtp_address *recipient,
+ const char *reason)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_instance *svinst = eenv->svinst;
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ const struct sieve_message_data *msgdata = eenv->msgdata;
+ const struct smtp_address *sender, *orig_recipient;
+ struct istream *input;
+ struct ostream *output;
+ struct sieve_smtp_context *sctx;
+ const char *new_msgid, *boundary, *error;
+ string_t *hdr;
+ int ret;
+
+ sender = sieve_message_get_sender(aenv->msgctx);
+ orig_recipient = msgdata->envelope.rcpt_params->orcpt.addr;
+
+ sctx = sieve_smtp_start_single(senv, sender, NULL, &output);
+
+ /* Just to be sure */
+ if (sctx == NULL) {
+ sieve_result_global_warning(
+ aenv, "reject action has no means to send mail");
+ return SIEVE_EXEC_OK;
+ }
+
+ new_msgid = sieve_message_get_new_id(svinst);
+ boundary = t_strdup_printf("%s/%s", my_pid, svinst->hostname);
+
+ hdr = t_str_new(512);
+ rfc2822_header_write(hdr, "X-Sieve", SIEVE_IMPLEMENTATION);
+ rfc2822_header_write(hdr, "Message-ID", new_msgid);
+ rfc2822_header_write(hdr, "Date", message_date_create(ioloop_time));
+ rfc2822_header_write(hdr, "From", sieve_get_postmaster_address(senv));
+ rfc2822_header_printf(hdr, "To", "<%s>", smtp_address_encode(sender));
+ rfc2822_header_write(hdr, "Subject", "Automatically rejected mail");
+ rfc2822_header_write(hdr, "Auto-Submitted", "auto-replied (rejected)");
+ rfc2822_header_write(hdr, "Precedence", "bulk");
+
+ rfc2822_header_write(hdr, "MIME-Version", "1.0");
+ rfc2822_header_printf(hdr, "Content-Type",
+ "multipart/report; "
+ "report-type=disposition-notification;\r\n"
+ "boundary=\"%s\"", boundary);
+
+ str_append(hdr, "\r\nThis is a MIME-encapsulated message\r\n\r\n");
+
+ /* Human readable status report */
+ str_printfa(hdr, "--%s\r\n", boundary);
+ rfc2822_header_write(hdr, "Content-Type", "text/plain; charset=utf-8");
+ rfc2822_header_write(hdr, "Content-Disposition", "inline");
+ rfc2822_header_write(hdr, "Content-Transfer-Encoding", "8bit");
+
+ str_printfa(hdr, "\r\nYour message to <%s> was automatically rejected:\r\n"
+ "%s\r\n", smtp_address_encode(recipient), reason);
+
+ /* MDN status report */
+ str_printfa(hdr, "--%s\r\n", boundary);
+ rfc2822_header_write(hdr, "Content-Type",
+ "message/disposition-notification");
+ str_append(hdr, "\r\n");
+ rfc2822_header_write(hdr,
+ "Reporting-UA: %s; Dovecot Mail Delivery Agent",
+ svinst->hostname);
+ if (orig_recipient != NULL) {
+ rfc2822_header_printf(hdr, "Original-Recipient", "rfc822; %s",
+ smtp_address_encode(orig_recipient));
+ }
+ rfc2822_header_printf(hdr, "Final-Recipient", "rfc822; %s",
+ smtp_address_encode(recipient));
+
+ if (msgdata->id != NULL)
+ rfc2822_header_write(hdr, "Original-Message-ID", msgdata->id);
+ rfc2822_header_write(hdr, "Disposition",
+ "automatic-action/MDN-sent-automatically; deleted");
+ str_append(hdr, "\r\n");
+
+ /* original message's headers */
+ str_printfa(hdr, "--%s\r\n", boundary);
+ rfc2822_header_write(hdr, "Content-Type", "message/rfc822");
+ str_append(hdr, "\r\n");
+ o_stream_nsend(output, str_data(hdr), str_len(hdr));
+
+ if (mail_get_hdr_stream(msgdata->mail, NULL, &input) == 0) {
+ /* NOTE: If you add more headers, they need to be sorted. We'll
+ drop Content-Type because we're not including the message
+ body, and having a multipart Content-Type may confuse some
+ MIME parsers when they don't see the message boundaries.
+ */
+ static const char *const exclude_headers[] = {
+ "Content-Type"
+ };
+
+ input = i_stream_create_header_filter(
+ input, HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR |
+ HEADER_FILTER_HIDE_BODY,
+ exclude_headers, N_ELEMENTS(exclude_headers),
+ *null_header_filter_callback, (void *)NULL);
+ o_stream_nsend_istream(output, input);
+ i_stream_unref(&input);
+ }
+
+ str_truncate(hdr, 0);
+ str_printfa(hdr, "\r\n\r\n--%s--\r\n", boundary);
+ o_stream_nsend(output, str_data(hdr), str_len(hdr));
+
+ if ((ret = sieve_smtp_finish(sctx, &error)) <= 0) {
+ if (ret < 0) {
+ sieve_result_global_error(aenv,
+ "failed to send rejection message to <%s>: %s "
+ "(temporary failure)",
+ smtp_address_encode(sender),
+ str_sanitize(error, 512));
+ } else {
+ sieve_result_global_log_error(aenv,
+ "failed to send rejection message to <%s>: %s "
+ "(permanent failure)",
+ smtp_address_encode(sender),
+ str_sanitize(error, 512));
+ }
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+int sieve_action_reject_mail(const struct sieve_action_exec_env *aenv,
+ const struct smtp_address *recipient,
+ const char *reason)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ int result;
+
+ T_BEGIN {
+ if (senv->reject_mail != NULL) {
+ result = (senv->reject_mail(senv, recipient,
+ reason) >= 0 ?
+ SIEVE_EXEC_OK : SIEVE_EXEC_FAILURE);
+ } else {
+ result = sieve_action_do_reject_mail(aenv, recipient,
+ reason);
+ }
+ } T_END;
+
+ return result;
+}
+
+/*
+ * Mailbox
+ */
+
+bool sieve_mailbox_check_name(const char *mailbox, const char **error_r)
+{
+ if (!uni_utf8_str_is_valid(mailbox)) {
+ *error_r = "invalid utf-8";
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/sieve-actions.h b/pigeonhole/src/lib-sieve/sieve-actions.h
new file mode 100644
index 0000000..f1a447f
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-actions.h
@@ -0,0 +1,311 @@
+#ifndef SIEVE_ACTIONS_H
+#define SIEVE_ACTIONS_H
+
+#include "lib.h"
+#include "mail-types.h"
+#include "mail-error.h"
+
+#include "sieve-common.h"
+#include "sieve-objects.h"
+#include "sieve-extensions.h"
+#include "sieve-execute.h"
+
+/*
+ * Action execution environment
+ */
+
+struct sieve_action_exec_env {
+ const struct sieve_execute_env *exec_env;
+ struct sieve_result_execution *rexec;
+ const struct sieve_action *action;
+ struct event *event;
+
+ struct sieve_result *result;
+ struct sieve_error_handler *ehandler;
+
+ struct sieve_message_context *msgctx;
+};
+
+struct event_passthrough *
+sieve_action_create_finish_event(const struct sieve_action_exec_env *aenv);
+
+/*
+ * Action flags
+ */
+
+enum sieve_action_flags {
+ SIEVE_ACTFLAG_TRIES_DELIVER = (1 << 0),
+ SIEVE_ACTFLAG_SENDS_RESPONSE = (1 << 1),
+ SIEVE_ACTFLAG_MAIL_STORAGE = (1 << 2)
+};
+
+/*
+ * Action definition
+ */
+
+struct sieve_action_def {
+ const char *name;
+ unsigned int flags;
+
+ bool (*equals)(const struct sieve_script_env *senv,
+ const struct sieve_action *act1,
+ const struct sieve_action *act2);
+
+ /* Result verification */
+ int (*check_duplicate)(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other);
+ int (*check_conflict)(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other);
+
+ /* Result printing */
+ void (*print)(const struct sieve_action *action,
+ const struct sieve_result_print_env *penv, bool *keep);
+
+ /* Result execution */
+ int (*start)(const struct sieve_action_exec_env *aenv,
+ void **tr_context);
+ int (*execute)(const struct sieve_action_exec_env *aenv,
+ void *tr_context, bool *keep);
+ int (*commit)(const struct sieve_action_exec_env *aenv,
+ void *tr_context);
+ void (*rollback)(const struct sieve_action_exec_env *aenv,
+ void *tr_context, bool success);
+ void (*finish)(const struct sieve_action_exec_env *aenv,
+ void *tr_context, int status);
+};
+
+/*
+ * Action instance
+ */
+
+struct sieve_action {
+ const struct sieve_action_def *def;
+ const struct sieve_extension *ext;
+ struct event *event;
+
+ const char *name;
+ const char *location;
+ unsigned int exec_seq;
+ void *context;
+ struct mail *mail;
+
+ bool keep:1;
+};
+
+#define sieve_action_is(act, definition) ((act)->def == &(definition))
+#define sieve_action_name(act) ((act)->name)
+
+bool sieve_action_is_executed(const struct sieve_action *act,
+ struct sieve_result *result);
+
+/*
+ * Action side effects
+ */
+
+/* Side effect object */
+
+struct sieve_side_effect_def {
+ struct sieve_object_def obj_def;
+
+ /* Precedence (side effects with higher value are executed first) */
+
+ unsigned int precedence;
+
+ /* The action it is supposed to link to */
+ const struct sieve_action_def *to_action;
+
+ /* Context coding */
+ bool (*dump_context)(const struct sieve_side_effect *seffect,
+ const struct sieve_dumptime_env *renv,
+ sieve_size_t *address);
+ int (*read_context)(const struct sieve_side_effect *seffect,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address, void **se_context);
+
+ /* Result verification */
+ int (*merge)(const struct sieve_runtime_env *renv,
+ const struct sieve_action *action,
+ const struct sieve_side_effect *old_seffect,
+ const struct sieve_side_effect *new_seffect,
+ void **old_context);
+
+ /* Result printing */
+ void (*print)(const struct sieve_side_effect *seffect,
+ const struct sieve_action *action,
+ const struct sieve_result_print_env *penv, bool *keep);
+
+ /* Result execution */
+
+ int (*pre_execute)(const struct sieve_side_effect *seffect,
+ const struct sieve_action_exec_env *aenv,
+ void *tr_context, void **se_tr_context);
+ int (*post_execute)(const struct sieve_side_effect *seffect,
+ const struct sieve_action_exec_env *aenv,
+ void *tr_context, void *se_tr_context, bool *keep);
+ void (*post_commit)(const struct sieve_side_effect *seffect,
+ const struct sieve_action_exec_env *aenv,
+ void *tr_context, void *se_tr_context,
+ int commit_status);
+ void (*rollback)(const struct sieve_side_effect *seffect,
+ const struct sieve_action_exec_env *aenv,
+ void *tr_context, void *se_tr_context, bool success);
+};
+
+struct sieve_side_effect {
+ struct sieve_object object;
+
+ const struct sieve_side_effect_def *def;
+
+ void *context;
+};
+
+/*
+ * Side effect operand
+ */
+
+#define SIEVE_EXT_DEFINE_SIDE_EFFECT(SEF) SIEVE_EXT_DEFINE_OBJECT(SEF)
+#define SIEVE_EXT_DEFINE_SIDE_EFFECTS(SEFS) SIEVE_EXT_DEFINE_OBJECTS(SEFS)
+
+#define SIEVE_OPT_SIDE_EFFECT (-1)
+
+extern const struct sieve_operand_class sieve_side_effect_operand_class;
+
+static inline void
+sieve_opr_side_effect_emit(struct sieve_binary_block *sblock,
+ const struct sieve_extension *ext,
+ const struct sieve_side_effect_def *seff)
+{
+ sieve_opr_object_emit(sblock, ext, &seff->obj_def);
+}
+
+bool sieve_opr_side_effect_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+int sieve_opr_side_effect_read(const struct sieve_runtime_env *renv,
+ sieve_size_t *address,
+ struct sieve_side_effect *seffect);
+
+/*
+ * Optional operands
+ */
+
+int sieve_action_opr_optional_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address, signed int *opt_code);
+
+int sieve_action_opr_optional_read(const struct sieve_runtime_env *renv,
+ sieve_size_t *address, signed int *opt_code,
+ int *exec_status,
+ struct sieve_side_effects_list **list);
+
+/*
+ * Core actions
+ */
+
+extern const struct sieve_action_def act_redirect;
+extern const struct sieve_action_def act_store;
+extern const struct sieve_action_def act_discard;
+
+/*
+ * Store action
+ */
+
+struct act_store_context {
+ /* Folder name represented in utf-8 */
+ const char *mailbox;
+};
+
+struct act_store_transaction {
+ struct act_store_context *context;
+ struct mailbox *box;
+ struct mailbox_transaction_context *mail_trans;
+
+ const char *mailbox_name;
+ const char *mailbox_identifier;
+
+ const char *error;
+ enum mail_error error_code;
+
+ enum mail_flags flags;
+ ARRAY_TYPE(const_string) keywords;
+
+ bool flags_altered:1;
+ bool disabled:1;
+ bool redundant:1;
+};
+
+int sieve_act_store_add_to_result(const struct sieve_runtime_env *renv,
+ const char *name,
+ struct sieve_side_effects_list *seffects,
+ const char *folder);
+
+void sieve_act_store_add_flags(const struct sieve_action_exec_env *aenv,
+ void *tr_context, const char *const *keywords,
+ enum mail_flags flags);
+
+void sieve_act_store_get_storage_error(const struct sieve_action_exec_env *aenv,
+ struct act_store_transaction *trans);
+
+/*
+ * Redirect action
+ */
+
+struct act_redirect_context {
+ const struct smtp_address *to_address;
+};
+
+int sieve_act_redirect_add_to_result(const struct sieve_runtime_env *renv,
+ const char *name,
+ struct sieve_side_effects_list *seffects,
+ const struct smtp_address *to_address);
+
+/*
+ * Checking for duplicates
+ */
+
+static inline bool
+sieve_action_duplicate_check_available(const struct sieve_action_exec_env *aenv)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+
+ return sieve_execute_duplicate_check_available(eenv);
+}
+
+static inline int
+sieve_action_duplicate_check(const struct sieve_action_exec_env *aenv,
+ const void *id, size_t id_size,
+ bool *duplicate_r)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+
+ return sieve_execute_duplicate_check(eenv, id, id_size,
+ duplicate_r);
+}
+
+static inline void
+sieve_action_duplicate_mark(const struct sieve_action_exec_env *aenv,
+ const void *id, size_t id_size, time_t time)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+
+ return sieve_execute_duplicate_mark(eenv, id, id_size, time);
+}
+
+/*
+ * Action utility functions
+ */
+
+/* Rejecting mail */
+
+int sieve_action_reject_mail(const struct sieve_action_exec_env *aenv,
+ const struct smtp_address *recipient,
+ const char *reason);
+
+/*
+ * Mailbox
+ */
+
+// FIXME: move this to a more appropriate location
+bool sieve_mailbox_check_name(const char *mailbox, const char **error_r);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-address-parts.c b/pigeonhole/src/lib-sieve/sieve-address-parts.c
new file mode 100644
index 0000000..a856e20
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-address-parts.c
@@ -0,0 +1,495 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "compat.h"
+#include "mempool.h"
+#include "hash.h"
+#include "array.h"
+#include "str-sanitize.h"
+
+#include "sieve-extensions.h"
+#include "sieve-code.h"
+#include "sieve-address.h"
+#include "sieve-commands.h"
+#include "sieve-binary.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-match.h"
+
+#include "sieve-address-parts.h"
+
+#include <string.h>
+
+/*
+ * Default address parts
+ */
+
+const struct sieve_address_part_def *sieve_core_address_parts[] = {
+ &all_address_part, &local_address_part, &domain_address_part
+};
+
+const unsigned int sieve_core_address_parts_count =
+ N_ELEMENTS(sieve_core_address_parts);
+
+/*
+ * Address-part 'extension'
+ */
+
+static bool addrp_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def address_part_extension = {
+ .name = "@address-parts",
+ .validator_load = addrp_validator_load
+};
+
+/*
+ * Validator context:
+ * name-based address-part registry.
+ */
+
+static struct sieve_validator_object_registry *_get_object_registry
+(struct sieve_validator *valdtr)
+{
+ struct sieve_instance *svinst;
+ const struct sieve_extension *adrp_ext;
+
+ svinst = sieve_validator_svinst(valdtr);
+ adrp_ext = sieve_get_address_part_extension(svinst);
+ return sieve_validator_object_registry_get(valdtr, adrp_ext);
+}
+
+void sieve_address_part_register
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ const struct sieve_address_part_def *addrp_def)
+{
+ struct sieve_validator_object_registry *regs = _get_object_registry(valdtr);
+
+ sieve_validator_object_registry_add(regs, ext, &addrp_def->obj_def);
+}
+
+static bool sieve_address_part_exists
+(struct sieve_validator *valdtr, const char *identifier)
+{
+ struct sieve_validator_object_registry *regs = _get_object_registry(valdtr);
+
+ return sieve_validator_object_registry_find(regs, identifier, NULL);
+}
+
+static const struct sieve_address_part *sieve_address_part_create_instance
+(struct sieve_validator *valdtr, struct sieve_command *cmd,
+ const char *identifier)
+{
+ struct sieve_validator_object_registry *regs = _get_object_registry(valdtr);
+ struct sieve_object object;
+ struct sieve_address_part *addrp;
+
+ if ( !sieve_validator_object_registry_find(regs, identifier, &object) )
+ return NULL;
+
+ addrp = p_new(sieve_command_pool(cmd), struct sieve_address_part, 1);
+ addrp->object = object;
+ addrp->def = (const struct sieve_address_part_def *) object.def;
+
+ return addrp;
+}
+
+static bool addrp_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ struct sieve_validator_object_registry *regs =
+ sieve_validator_object_registry_init(valdtr, ext);
+ unsigned int i;
+
+ /* Register core address-parts */
+ for ( i = 0; i < sieve_core_address_parts_count; i++ ) {
+ sieve_validator_object_registry_add
+ (regs, NULL, &(sieve_core_address_parts[i]->obj_def));
+ }
+
+ return TRUE;
+}
+
+void sieve_address_parts_link_tags
+(struct sieve_validator *valdtr, struct sieve_command_registration *cmd_reg,
+ int id_code)
+{
+ struct sieve_instance *svinst;
+ const struct sieve_extension *adrp_ext;
+
+ svinst = sieve_validator_svinst(valdtr);
+ adrp_ext = sieve_get_address_part_extension(svinst);
+
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, adrp_ext, &address_part_tag, id_code);
+}
+
+/*
+ * Address-part tagged argument
+ */
+
+/* Forward declarations */
+
+static bool tag_address_part_is_instance_of
+ (struct sieve_validator *valdtr, struct sieve_command *cmd,
+ const struct sieve_extension *ext, const char *identifier, void **data);
+static bool tag_address_part_validate
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool tag_address_part_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd);
+
+/* Argument object */
+
+const struct sieve_argument_def address_part_tag = {
+ .identifier = "ADDRESS-PART",
+ .is_instance_of = tag_address_part_is_instance_of,
+ .validate = tag_address_part_validate,
+ .generate = tag_address_part_generate
+};
+
+/* Argument implementation */
+
+static bool tag_address_part_is_instance_of
+(struct sieve_validator *valdtr, struct sieve_command *cmd,
+ const struct sieve_extension *ext ATTR_UNUSED, const char *identifier,
+ void **data)
+{
+ const struct sieve_address_part *addrp;
+
+ if ( data == NULL )
+ return sieve_address_part_exists(valdtr, identifier);
+
+ if ( (addrp=sieve_address_part_create_instance
+ (valdtr, cmd, identifier)) == NULL )
+ return FALSE;
+
+ *data = (void *) addrp;
+ return TRUE;
+}
+
+static bool tag_address_part_validate
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ /* NOTE: Currenly trivial, but might need to allow for further validation for
+ * future extensions.
+ */
+
+ /* Syntax:
+ * ":localpart" / ":domain" / ":all" (subject to extension)
+ */
+
+ /* Skip tag */
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+static bool tag_address_part_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ struct sieve_address_part *addrp =
+ (struct sieve_address_part *) arg->argument->data;
+
+ sieve_opr_address_part_emit(cgenv->sblock, addrp);
+
+ return TRUE;
+}
+
+/*
+ * Address-part operand
+ */
+
+const struct sieve_operand_class sieve_address_part_operand_class =
+ { "address part" };
+
+static const struct sieve_extension_objects core_address_parts =
+ SIEVE_EXT_DEFINE_MATCH_TYPES(sieve_core_address_parts);
+
+const struct sieve_operand_def address_part_operand = {
+ .name = "address-part",
+ .code = SIEVE_OPERAND_ADDRESS_PART,
+ .class = &sieve_address_part_operand_class,
+ .interface = &core_address_parts
+};
+
+/*
+ * Address-part string list
+ */
+
+static int sieve_address_part_stringlist_next_item
+ (struct sieve_stringlist *_strlist, string_t **str_r);
+static void sieve_address_part_stringlist_reset
+ (struct sieve_stringlist *_strlist);
+static int sieve_address_part_stringlist_get_length
+ (struct sieve_stringlist *_strlist);
+static void sieve_address_part_stringlist_set_trace
+(struct sieve_stringlist *_strlist, bool trace);
+
+struct sieve_address_part_stringlist {
+ struct sieve_stringlist strlist;
+
+ const struct sieve_address_part *addrp;
+ struct sieve_address_list *addresses;
+};
+
+struct sieve_stringlist *sieve_address_part_stringlist_create
+(const struct sieve_runtime_env *renv, const struct sieve_address_part *addrp,
+ struct sieve_address_list *addresses)
+{
+ struct sieve_address_part_stringlist *strlist;
+
+ strlist = t_new(struct sieve_address_part_stringlist, 1);
+ strlist->strlist.runenv = renv;
+ strlist->strlist.next_item = sieve_address_part_stringlist_next_item;
+ strlist->strlist.reset = sieve_address_part_stringlist_reset;
+ strlist->strlist.get_length = sieve_address_part_stringlist_get_length;
+ strlist->strlist.set_trace = sieve_address_part_stringlist_set_trace;
+
+ strlist->addrp = addrp;
+ strlist->addresses = addresses;
+
+ return &strlist->strlist;
+}
+
+static int sieve_address_part_stringlist_next_item
+ (struct sieve_stringlist *_strlist, string_t **str_r)
+{
+ struct sieve_address_part_stringlist *strlist =
+ (struct sieve_address_part_stringlist *)_strlist;
+ struct smtp_address item;
+ string_t *item_unparsed;
+ int ret;
+
+ *str_r = NULL;
+
+ while ( *str_r == NULL ) {
+ if ( (ret=sieve_address_list_next_item
+ (strlist->addresses, &item, &item_unparsed)) <= 0 )
+ return ret;
+
+ if ( item.localpart == NULL ) {
+ if ( item_unparsed != NULL ) {
+ if ( _strlist->trace ) {
+ sieve_runtime_trace(_strlist->runenv, 0,
+ "extracting `%s' part from non-address value `%s'",
+ sieve_address_part_name(strlist->addrp),
+ str_sanitize(str_c(item_unparsed), 80));
+ }
+
+ if ( str_len(item_unparsed) == 0 ||
+ sieve_address_part_is(strlist->addrp, all_address_part) )
+ *str_r = item_unparsed;
+ }
+ } else {
+ const struct sieve_address_part *addrp = strlist->addrp;
+ const char *part = NULL;
+
+ if ( _strlist->trace ) {
+ sieve_runtime_trace(_strlist->runenv, 0,
+ "extracting `%s' part from address %s",
+ sieve_address_part_name(strlist->addrp),
+ smtp_address_encode_path(&item));
+ }
+
+ if ( addrp->def != NULL && addrp->def->extract_from != NULL )
+ part = addrp->def->extract_from(addrp, &item);
+
+ if ( part != NULL )
+ *str_r = t_str_new_const(part, strlen(part));
+ }
+ }
+
+ return 1;
+}
+
+static void sieve_address_part_stringlist_reset
+ (struct sieve_stringlist *_strlist)
+{
+ struct sieve_address_part_stringlist *strlist =
+ (struct sieve_address_part_stringlist *)_strlist;
+
+ sieve_address_list_reset(strlist->addresses);
+}
+
+static int sieve_address_part_stringlist_get_length
+ (struct sieve_stringlist *_strlist)
+{
+ struct sieve_address_part_stringlist *strlist =
+ (struct sieve_address_part_stringlist *)_strlist;
+
+ return sieve_address_list_get_length(strlist->addresses);
+}
+
+static void sieve_address_part_stringlist_set_trace
+(struct sieve_stringlist *_strlist, bool trace)
+{
+ struct sieve_address_part_stringlist *strlist =
+ (struct sieve_address_part_stringlist *)_strlist;
+
+ sieve_address_list_set_trace(strlist->addresses, trace);
+}
+
+/*
+ * Default ADDRESS-PART, MATCH-TYPE, COMPARATOR access
+ */
+
+int sieve_addrmatch_opr_optional_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address,
+ signed int *opt_code)
+{
+ signed int _opt_code = 0;
+ bool final = FALSE, opok = TRUE;
+
+ if ( opt_code == NULL ) {
+ opt_code = &_opt_code;
+ final = TRUE;
+ }
+
+ while ( opok ) {
+ int opt;
+
+ if ( (opt=sieve_opr_optional_dump(denv, address, opt_code)) <= 0 )
+ return opt;
+
+ switch ( *opt_code ) {
+ case SIEVE_MATCH_OPT_COMPARATOR:
+ opok = sieve_opr_comparator_dump(denv, address);
+ break;
+ case SIEVE_MATCH_OPT_MATCH_TYPE:
+ opok = sieve_opr_match_type_dump(denv, address);
+ break;
+ case SIEVE_AM_OPT_ADDRESS_PART:
+ opok = sieve_opr_address_part_dump(denv, address);
+ break;
+ default:
+ return ( final ? -1 : 1 );
+ }
+ }
+
+ return -1;
+}
+
+int sieve_addrmatch_opr_optional_read
+(const struct sieve_runtime_env *renv, sieve_size_t *address,
+ signed int *opt_code, int *exec_status, struct sieve_address_part *addrp,
+ struct sieve_match_type *mtch, struct sieve_comparator *cmp)
+{
+ signed int _opt_code = 0;
+ bool final = FALSE;
+ int status = SIEVE_EXEC_OK;
+
+ if ( opt_code == NULL ) {
+ opt_code = &_opt_code;
+ final = TRUE;
+ }
+
+ if ( exec_status != NULL )
+ *exec_status = SIEVE_EXEC_OK;
+
+ while ( status == SIEVE_EXEC_OK ) {
+ int opt;
+
+ if ( (opt=sieve_opr_optional_read(renv, address, opt_code)) <= 0 ){
+ if ( opt < 0 && exec_status != NULL )
+ *exec_status = SIEVE_EXEC_BIN_CORRUPT;
+ return opt;
+ }
+
+ switch ( *opt_code ) {
+ case SIEVE_MATCH_OPT_COMPARATOR:
+ if (cmp == NULL) {
+ sieve_runtime_trace_error(renv, "unexpected comparator operand");
+ if ( exec_status != NULL )
+ *exec_status = SIEVE_EXEC_BIN_CORRUPT;
+ return -1;
+ }
+ status = sieve_opr_comparator_read(renv, address, cmp);
+ break;
+ case SIEVE_MATCH_OPT_MATCH_TYPE:
+ if (mtch == NULL) {
+ sieve_runtime_trace_error(renv, "unexpected match-type operand");
+ if ( exec_status != NULL )
+ *exec_status = SIEVE_EXEC_BIN_CORRUPT;
+ return -1;
+ }
+ status = sieve_opr_match_type_read(renv, address, mtch);
+ break;
+ case SIEVE_AM_OPT_ADDRESS_PART:
+ if (addrp == NULL) {
+ sieve_runtime_trace_error(renv, "unexpected address-part operand");
+ if ( exec_status != NULL )
+ *exec_status = SIEVE_EXEC_BIN_CORRUPT;
+ return -1;
+ }
+ status = sieve_opr_address_part_read(renv, address, addrp);
+ break;
+ default:
+ if ( final ) {
+ sieve_runtime_trace_error(renv, "invalid optional operand");
+ if ( exec_status != NULL )
+ *exec_status = SIEVE_EXEC_BIN_CORRUPT;
+ return -1;
+ }
+ return 1;
+ }
+ }
+
+ if ( exec_status != NULL )
+ *exec_status = status;
+ return -1;
+}
+
+/*
+ * Core address-part modifiers
+ */
+
+static const char *addrp_all_extract_from
+(const struct sieve_address_part *addrp ATTR_UNUSED,
+ const struct smtp_address *address)
+{
+ if ( address->localpart == NULL )
+ return NULL;
+ return smtp_address_encode(address);
+}
+
+static const char *addrp_domain_extract_from
+(const struct sieve_address_part *addrp ATTR_UNUSED,
+ const struct smtp_address *address)
+{
+ return address->domain;
+}
+
+static const char *addrp_localpart_extract_from
+(const struct sieve_address_part *addrp ATTR_UNUSED,
+ const struct smtp_address *address)
+{
+ return address->localpart;
+}
+
+const struct sieve_address_part_def all_address_part = {
+ SIEVE_OBJECT("all",
+ &address_part_operand, SIEVE_ADDRESS_PART_ALL),
+ .extract_from = addrp_all_extract_from
+};
+
+const struct sieve_address_part_def local_address_part = {
+ SIEVE_OBJECT("localpart",
+ &address_part_operand, SIEVE_ADDRESS_PART_LOCAL),
+ .extract_from = addrp_localpart_extract_from
+};
+
+const struct sieve_address_part_def domain_address_part = {
+ SIEVE_OBJECT("domain",
+ &address_part_operand, SIEVE_ADDRESS_PART_DOMAIN),
+ .extract_from = addrp_domain_extract_from
+};
+
diff --git a/pigeonhole/src/lib-sieve/sieve-address-parts.h b/pigeonhole/src/lib-sieve/sieve-address-parts.h
new file mode 100644
index 0000000..c774dc3
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-address-parts.h
@@ -0,0 +1,135 @@
+#ifndef SIEVE_ADDRESS_PARTS_H
+#define SIEVE_ADDRESS_PARTS_H
+
+#include "message-address.h"
+
+#include "sieve-common.h"
+#include "sieve-match.h"
+#include "sieve-extensions.h"
+#include "sieve-objects.h"
+
+/*
+ * Address part definition
+ */
+
+struct sieve_address_part_def {
+ struct sieve_object_def obj_def;
+
+ const char *(*extract_from)
+ (const struct sieve_address_part *addrp,
+ const struct smtp_address *address);
+};
+
+/*
+ * Address part instance
+ */
+
+struct sieve_address_part {
+ struct sieve_object object;
+
+ const struct sieve_address_part_def *def;
+};
+
+#define SIEVE_ADDRESS_PART_DEFAULT(definition) \
+ { SIEVE_OBJECT_DEFAULT(definition), &(definition) };
+
+#define sieve_address_part_name(addrp) \
+ ( (addrp)->object.def->identifier )
+#define sieve_address_part_is(addrp, definition) \
+ ( (addrp)->def == &(definition) )
+
+/*
+ * Core address parts
+ */
+
+enum sieve_address_part_code {
+ SIEVE_ADDRESS_PART_ALL,
+ SIEVE_ADDRESS_PART_LOCAL,
+ SIEVE_ADDRESS_PART_DOMAIN,
+ SIEVE_ADDRESS_PART_CUSTOM
+};
+
+extern const struct sieve_address_part_def all_address_part;
+extern const struct sieve_address_part_def local_address_part;
+extern const struct sieve_address_part_def domain_address_part;
+
+/*
+ * Address part tagged argument
+ */
+
+extern const struct sieve_argument_def address_part_tag;
+
+void sieve_address_parts_link_tags
+ (struct sieve_validator *valdtr, struct sieve_command_registration *cmd_reg,
+ int id_code);
+
+/*
+ * Address part registry
+ */
+
+void sieve_address_part_register
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ const struct sieve_address_part_def *addrp);
+
+/*
+ * Address part operand
+ */
+
+extern const struct sieve_operand_def address_part_operand;
+extern const struct sieve_operand_class sieve_address_part_operand_class;
+
+#define SIEVE_EXT_DEFINE_ADDRESS_PART(OP) SIEVE_EXT_DEFINE_OBJECT(OP)
+#define SIEVE_EXT_DEFINE_ADDRESS_PARTS(OPS) SIEVE_EXT_DEFINE_OBJECTS(OPS)
+
+static inline void sieve_opr_address_part_emit
+(struct sieve_binary_block *sblock, const struct sieve_address_part *addrp)
+{
+ sieve_opr_object_emit(sblock, addrp->object.ext, addrp->object.def);
+}
+
+static inline bool sieve_opr_address_part_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ return sieve_opr_object_dump
+ (denv, &sieve_address_part_operand_class, address, NULL);
+}
+
+static inline int sieve_opr_address_part_read
+(const struct sieve_runtime_env *renv, sieve_size_t *address,
+ struct sieve_address_part *addrp)
+{
+ if ( !sieve_opr_object_read
+ (renv, &sieve_address_part_operand_class, address, &addrp->object) )
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ addrp->def = (const struct sieve_address_part_def *) addrp->object.def;
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Address-part string list
+ */
+
+struct sieve_stringlist *sieve_address_part_stringlist_create
+ (const struct sieve_runtime_env *renv, const struct sieve_address_part *addrp,
+ struct sieve_address_list *addresses);
+
+/*
+ * Match utility
+ */
+
+enum sieve_addrmatch_opt_operand {
+ SIEVE_AM_OPT_ADDRESS_PART = SIEVE_MATCH_OPT_LAST,
+ SIEVE_AM_OPT_LAST
+};
+
+int sieve_addrmatch_opr_optional_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address,
+ signed int *opt_code);
+
+int sieve_addrmatch_opr_optional_read
+ (const struct sieve_runtime_env *renv, sieve_size_t *address,
+ signed int *opt_code, int *exec_status, struct sieve_address_part *addrp,
+ struct sieve_match_type *mtch, struct sieve_comparator *cmp);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-address-source.c b/pigeonhole/src/lib-sieve/sieve-address-source.c
new file mode 100644
index 0000000..a5ec6f6
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-address-source.c
@@ -0,0 +1,119 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-settings.h"
+#include "sieve-address.h"
+#include "sieve-message.h"
+
+#include "sieve-address-source.h"
+
+bool sieve_address_source_parse
+(pool_t pool, const char *value,
+ struct sieve_address_source *asrc)
+{
+ struct smtp_address *address;
+ const char *error;
+ size_t val_len;
+
+ i_zero(asrc);
+
+ value = t_str_trim(value, "\t ");
+ value = t_str_lcase(value);
+ val_len = strlen(value);
+ if ( val_len > 0 ) {
+ if ( strcmp(value, "default") == 0 ) {
+ asrc->type = SIEVE_ADDRESS_SOURCE_DEFAULT;
+ } else if ( strcmp(value, "sender") == 0 ) {
+ asrc->type = SIEVE_ADDRESS_SOURCE_SENDER;
+ } else if ( strcmp(value, "recipient") == 0 ) {
+ asrc->type = SIEVE_ADDRESS_SOURCE_RECIPIENT;
+ } else if ( strcmp(value, "orig_recipient") == 0 ) {
+ asrc->type = SIEVE_ADDRESS_SOURCE_ORIG_RECIPIENT;
+ } else if ( strcmp(value, "user_email") == 0 ) {
+ asrc->type = SIEVE_ADDRESS_SOURCE_USER_EMAIL;
+ } else if ( strcmp(value, "postmaster") == 0 ) {
+ asrc->type = SIEVE_ADDRESS_SOURCE_POSTMASTER;
+ } else if ( smtp_address_parse_path(pool_datastack_create(), value,
+ SMTP_ADDRESS_PARSE_FLAG_ALLOW_EMPTY, &address, &error) >= 0 ) {
+ asrc->type = SIEVE_ADDRESS_SOURCE_EXPLICIT;
+ asrc->address = smtp_address_clone(pool, address);
+ } else {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+bool sieve_address_source_parse_from_setting
+(struct sieve_instance *svinst, pool_t pool,
+ const char *setting, struct sieve_address_source *asrc)
+{
+ const char *value;
+
+ value = sieve_setting_get(svinst, setting);
+ if ( value == NULL )
+ return FALSE;
+
+ if ( !sieve_address_source_parse(pool, value, asrc) ) {
+ e_warning(svinst->event, "Invalid value for setting '%s': '%s'",
+ setting, value);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+int sieve_address_source_get_address
+(struct sieve_address_source *asrc,
+ struct sieve_instance *svinst,
+ const struct sieve_script_env *senv,
+ struct sieve_message_context *msgctx,
+ enum sieve_execute_flags flags,
+ const struct smtp_address **addr_r)
+{
+ enum sieve_address_source_type type = asrc->type;
+
+ if ( type == SIEVE_ADDRESS_SOURCE_USER_EMAIL &&
+ svinst->user_email == NULL )
+ type = SIEVE_ADDRESS_SOURCE_RECIPIENT;
+
+ if ( (flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) != 0 ) {
+ switch ( type ) {
+ case SIEVE_ADDRESS_SOURCE_SENDER:
+ case SIEVE_ADDRESS_SOURCE_RECIPIENT:
+ case SIEVE_ADDRESS_SOURCE_ORIG_RECIPIENT:
+ /* We have no envelope */
+ type = SIEVE_ADDRESS_SOURCE_DEFAULT;
+ break;
+ default:
+ break;
+ }
+ }
+
+ switch ( type ) {
+ case SIEVE_ADDRESS_SOURCE_SENDER:
+ *addr_r = sieve_message_get_sender(msgctx);
+ return 1;
+ case SIEVE_ADDRESS_SOURCE_RECIPIENT:
+ *addr_r = sieve_message_get_final_recipient(msgctx);
+ return 1;
+ case SIEVE_ADDRESS_SOURCE_ORIG_RECIPIENT:
+ *addr_r = sieve_message_get_orig_recipient(msgctx);
+ return 1;
+ case SIEVE_ADDRESS_SOURCE_USER_EMAIL:
+ *addr_r = svinst->user_email;
+ return 1;
+ case SIEVE_ADDRESS_SOURCE_POSTMASTER:
+ *addr_r = sieve_get_postmaster_smtp(senv);
+ return 1;
+ case SIEVE_ADDRESS_SOURCE_EXPLICIT:
+ *addr_r = asrc->address;
+ return 1;
+ case SIEVE_ADDRESS_SOURCE_DEFAULT:
+ break;
+ }
+ return 0;
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-address-source.h b/pigeonhole/src/lib-sieve/sieve-address-source.h
new file mode 100644
index 0000000..fac4b49
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-address-source.h
@@ -0,0 +1,36 @@
+#ifndef SIEVE_ADDRESS_SOURCE_H
+#define SIEVE_ADDRESS_SOURCE_H
+
+#include "sieve-common.h"
+
+enum sieve_address_source_type {
+ SIEVE_ADDRESS_SOURCE_DEFAULT = 0,
+ SIEVE_ADDRESS_SOURCE_SENDER,
+ SIEVE_ADDRESS_SOURCE_RECIPIENT,
+ SIEVE_ADDRESS_SOURCE_ORIG_RECIPIENT,
+ SIEVE_ADDRESS_SOURCE_USER_EMAIL,
+ SIEVE_ADDRESS_SOURCE_POSTMASTER,
+ SIEVE_ADDRESS_SOURCE_EXPLICIT
+};
+
+struct sieve_address_source {
+ enum sieve_address_source_type type;
+ const struct smtp_address *address;
+};
+
+bool sieve_address_source_parse
+ (pool_t pool, const char *value,
+ struct sieve_address_source *asrc);
+bool sieve_address_source_parse_from_setting
+ (struct sieve_instance *svinst, pool_t pool,
+ const char *setting, struct sieve_address_source *asrc);
+
+int sieve_address_source_get_address
+ (struct sieve_address_source *asrc,
+ struct sieve_instance *svinst,
+ const struct sieve_script_env *senv,
+ struct sieve_message_context *msgctx,
+ enum sieve_execute_flags flags,
+ const struct smtp_address **addr_r);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-address.c b/pigeonhole/src/lib-sieve/sieve-address.c
new file mode 100644
index 0000000..f9456f8
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-address.c
@@ -0,0 +1,558 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "rfc822-parser.h"
+#include "message-address.h"
+
+#include "sieve-common.h"
+#include "sieve-runtime-trace.h"
+
+#include "sieve-address.h"
+
+#include <ctype.h>
+
+/*
+ * Header address list
+ */
+
+/* Forward declarations */
+
+static int
+sieve_header_address_list_next_string_item(struct sieve_stringlist *_strlist,
+ string_t **str_r);
+static int
+sieve_header_address_list_next_item(struct sieve_address_list *_addrlist,
+ struct smtp_address *addr_r,
+ string_t **unparsed_r);
+static void
+sieve_header_address_list_reset(struct sieve_stringlist *_strlist);
+static void
+sieve_header_address_list_set_trace(struct sieve_stringlist *_strlist,
+ bool trace);
+
+/* Stringlist object */
+
+struct sieve_header_address_list {
+ struct sieve_address_list addrlist;
+
+ struct sieve_stringlist *field_values;
+ const struct message_address *cur_address;
+};
+
+struct sieve_address_list *
+sieve_header_address_list_create(const struct sieve_runtime_env *renv,
+ struct sieve_stringlist *field_values)
+{
+ struct sieve_header_address_list *addrlist;
+
+ addrlist = t_new(struct sieve_header_address_list, 1);
+ addrlist->addrlist.strlist.runenv = renv;
+ addrlist->addrlist.strlist.exec_status = SIEVE_EXEC_OK;
+ addrlist->addrlist.strlist.next_item =
+ sieve_header_address_list_next_string_item;
+ addrlist->addrlist.strlist.reset = sieve_header_address_list_reset;
+ addrlist->addrlist.strlist.set_trace =
+ sieve_header_address_list_set_trace;
+ addrlist->addrlist.next_item = sieve_header_address_list_next_item;
+ addrlist->field_values = field_values;
+
+ return &addrlist->addrlist;
+}
+
+static int
+sieve_header_address_list_next_address(
+ struct sieve_header_address_list *addrlist, struct smtp_address *addr_r)
+{
+ struct smtp_address adummy;
+ int ret = 0;
+
+ if (addr_r == NULL)
+ addr_r = &adummy;
+
+ while (addrlist->cur_address != NULL) {
+ const struct message_address *aitem = addrlist->cur_address;
+
+ addrlist->cur_address = addrlist->cur_address->next;
+
+ if (!aitem->invalid_syntax && aitem->domain != NULL &&
+ smtp_address_init_from_msg(addr_r, aitem) >= 0)
+ return 1;
+ ret = -1;
+ }
+ return ret;
+}
+
+static int
+sieve_header_address_list_next_item(struct sieve_address_list *_addrlist,
+ struct smtp_address *addr_r,
+ string_t **unparsed_r)
+{
+ struct sieve_header_address_list *addrlist =
+ (struct sieve_header_address_list *)_addrlist;
+ const struct sieve_runtime_env *runenv = _addrlist->strlist.runenv;
+ string_t *value_item = NULL;
+ bool trace = _addrlist->strlist.trace;
+
+ if (addr_r != NULL)
+ smtp_address_init(addr_r, NULL, NULL);
+ if (unparsed_r != NULL)
+ *unparsed_r = NULL;
+
+ for (;;) {
+ int ret;
+
+ if ((ret = sieve_header_address_list_next_address(
+ addrlist, addr_r)) < 0 &&
+ value_item != NULL) {
+ /* completely invalid address list is returned as-is */
+ if (trace) {
+ sieve_runtime_trace(
+ runenv, 0,
+ "invalid address value `%s'",
+ str_sanitize(str_c(value_item), 80));
+ }
+ if (unparsed_r != NULL)
+ *unparsed_r = value_item;
+ return 1;
+ }
+ if (ret > 0) {
+ if (trace) {
+ sieve_runtime_trace(
+ runenv, 0,
+ "address value `%s'",
+ str_sanitize(smtp_address_encode(addr_r),
+ 80));
+ }
+ return 1;
+ }
+
+ /* Read next header value from source list */
+ if ((ret = sieve_stringlist_next_item(addrlist->field_values,
+ &value_item)) <= 0)
+ return ret;
+ if (str_len(value_item) == 0) {
+ /* empty header value is returned as-is */
+ if (trace) {
+ sieve_runtime_trace(runenv, 0,
+ "empty address value");
+ }
+ addrlist->cur_address = NULL;
+ if (unparsed_r != NULL)
+ *unparsed_r = value_item;
+ return 1;
+ }
+
+ if (trace) {
+ sieve_runtime_trace(
+ runenv, 0,
+ "parsing address header value `%s'",
+ str_sanitize(str_c(value_item), 80));
+ }
+
+ addrlist->cur_address = message_address_parse(
+ pool_datastack_create(),
+ (const unsigned char *)str_data(value_item),
+ str_len(value_item), 256, 0);
+ }
+ i_unreached();
+}
+
+static int
+sieve_header_address_list_next_string_item(struct sieve_stringlist *_strlist,
+ string_t **str_r)
+{
+ struct sieve_address_list *addrlist =
+ (struct sieve_address_list *)_strlist;
+ struct smtp_address addr;
+ int ret;
+
+ if ((ret = sieve_header_address_list_next_item(
+ addrlist, &addr, str_r)) <= 0)
+ return ret;
+
+ if (addr.localpart != NULL) {
+ const char *addr_str = smtp_address_encode(&addr);
+
+ if (str_r != NULL)
+ *str_r = t_str_new_const(addr_str, strlen(addr_str));
+ }
+ return 1;
+}
+
+static void sieve_header_address_list_reset(struct sieve_stringlist *_strlist)
+{
+ struct sieve_header_address_list *addrlist =
+ (struct sieve_header_address_list *)_strlist;
+
+ sieve_stringlist_reset(addrlist->field_values);
+ addrlist->cur_address = NULL;
+}
+
+static void
+sieve_header_address_list_set_trace(struct sieve_stringlist *_strlist,
+ bool trace)
+{
+ struct sieve_header_address_list *addrlist =
+ (struct sieve_header_address_list *)_strlist;
+
+ sieve_stringlist_set_trace(addrlist->field_values, trace);
+}
+
+/*
+ * RFC 2822 addresses
+ */
+
+/* Mail message address according to RFC 2822 and implemented in the Dovecot
+ message address parser:
+
+ address = mailbox / group
+ mailbox = name-addr / addr-spec
+ name-addr = [display-name] angle-addr
+ angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
+ group = display-name ":" [mailbox-list / CFWS] ";" [CFWS]
+ display-name = phrase
+
+ addr-spec = local-part "@" domain
+ local-part = dot-atom / quoted-string / obs-local-part
+ domain = dot-atom / domain-literal / obs-domain
+ domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
+ dcontent = dtext / quoted-pair
+ dtext = NO-WS-CTL / ; Non white space controls
+ %d33-90 / ; The rest of the US-ASCII
+ %d94-126 ; characters not including "[",
+ ; "]", or "\"
+
+ atext = ALPHA / DIGIT / ; Any character except controls,
+ "!" / "#" / ; SP, and specials.
+ "$" / "%" / ; Used for atoms
+ "&" / "'" /
+ "*" / "+" /
+ "-" / "/" /
+ "=" / "?" /
+ "^" / "_" /
+ "`" / "{" /
+ "|" / "}" /
+ "~"
+ atom = [CFWS] 1*atext [CFWS]
+ dot-atom = [CFWS] dot-atom-text [CFWS]
+ dot-atom-text = 1*atext *("." 1*atext)
+ word = atom / quoted-string
+ phrase = 1*word / obs-phrase
+
+ Message address specification as allowed bij the RFC 5228 SIEVE
+ specification:
+ sieve-address = addr-spec ; simple address
+ / phrase "<" addr-spec ">" ; name & addr-spec\
+
+ Which concisely is about equal to:
+ sieve-address = mailbox
+ */
+
+/*
+ * Address parse context
+ */
+
+struct sieve_message_address_parser {
+ struct rfc822_parser_context parser;
+
+ string_t *str;
+ string_t *local_part;
+ string_t *domain;
+
+ string_t *error;
+};
+
+/*
+ * Error handling
+ */
+
+static inline void ATTR_FORMAT(2, 3)
+sieve_address_error(struct sieve_message_address_parser *ctx,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ if (str_len(ctx->error) == 0) {
+ va_start(args, fmt);
+ str_vprintfa(ctx->error, fmt, args);
+ va_end(args);
+ }
+}
+
+/*
+ Partial RFC 2822 address parser
+
+ FIXME: lots of overlap with dovecot/src/lib-mail/message-parser.c
+ --> this implementation adds textual error reporting
+ MERGE!
+ */
+
+static int check_local_part(struct sieve_message_address_parser *ctx)
+{
+ const unsigned char *p, *pend;
+
+ p = str_data(ctx->local_part);
+ pend = p + str_len(ctx->local_part);
+ while (p < pend) {
+ if (*p < 0x20 || *p > 0x7e)
+ return -1;
+ p++;
+ }
+ return 0;
+}
+
+static int parse_local_part(struct sieve_message_address_parser *ctx)
+{
+ int ret;
+
+ /*
+ local-part = dot-atom / quoted-string / obs-local-part
+ obs-local-part = word *("." word)
+ */
+ if (ctx->parser.data == ctx->parser.end) {
+ sieve_address_error(ctx, "empty local part");
+ return -1;
+ }
+
+ str_truncate(ctx->local_part, 0);
+ if (*ctx->parser.data == '"') {
+ ret = rfc822_parse_quoted_string(&ctx->parser, ctx->local_part);
+ } else {
+ ret = -1;
+ /* NOTE: this deviates from dot-atom syntax to allow some
+ Japanese mail addresses with dots at non-standard places to
+ be accepted. */
+ do {
+ while (*ctx->parser.data == '.') {
+ str_append_c(ctx->local_part, '.');
+ ctx->parser.data++;
+ if (ctx->parser.data == ctx->parser.end) {
+ /* @domain is missing, but local-part
+ parsing was successful */
+ return 0;
+ }
+ ret = 1;
+ }
+ if (*ctx->parser.data == '@')
+ break;
+ ret = rfc822_parse_atom(&ctx->parser, ctx->local_part);
+ } while (ret > 0 && *ctx->parser.data == '.');
+ }
+
+ if (ret < 0 || check_local_part(ctx) < 0) {
+ sieve_address_error(ctx, "invalid local part");
+ return -1;
+ }
+ return ret;
+}
+
+static int parse_domain(struct sieve_message_address_parser *ctx)
+{
+ int ret;
+
+ str_truncate(ctx->domain, 0);
+ if ((ret = rfc822_parse_domain(&ctx->parser, ctx->domain)) < 0) {
+ sieve_address_error(ctx, "invalid or missing domain");
+ return -1;
+ }
+
+ return ret;
+}
+
+static int parse_addr_spec(struct sieve_message_address_parser *ctx)
+{
+ /* addr-spec = local-part "@" domain */
+ int ret;
+
+ if ((ret = parse_local_part(ctx)) < 0)
+ return ret;
+
+ if (ret > 0 && *ctx->parser.data == '@') {
+ return parse_domain(ctx);
+ }
+
+ sieve_address_error(
+ ctx, "invalid or lonely local part '%s' (expecting '@')",
+ str_sanitize(str_c(ctx->local_part), 80));
+ return -1;
+}
+
+static int parse_mailbox(struct sieve_message_address_parser *ctx)
+{
+ int ret;
+ const unsigned char *start;
+
+ /* sieve-address = addr-spec ; simple address
+ / phrase "<" addr-spec ">" ; name & addr-spec
+ */
+
+ /* Record parser state in case we fail at our first attempt */
+ start = ctx->parser.data;
+
+ /* First try: phrase "<" addr-spec ">" ; name & addr-spec */
+ str_truncate(ctx->str, 0);
+ if (rfc822_parse_phrase(&ctx->parser, ctx->str) <= 0 ||
+ *ctx->parser.data != '<') {
+ /* Failed; try just bare addr-spec */
+ ctx->parser.data = start;
+ return parse_addr_spec(ctx);
+ }
+
+ /* "<" addr-spec ">" */
+ ctx->parser.data++;
+
+ if ((ret = rfc822_skip_lwsp(&ctx->parser)) <= 0) {
+ if (ret < 0)
+ sieve_address_error(ctx, "invalid characters after <");
+ return ret;
+ }
+
+ if (parse_addr_spec(ctx) < 0)
+ return -1;
+
+ if (*ctx->parser.data != '>') {
+ sieve_address_error(ctx, "missing '>'");
+ return -1;
+ }
+ ctx->parser.data++;
+
+ if ((ret = rfc822_skip_lwsp(&ctx->parser)) < 0) {
+ sieve_address_error(
+ ctx, "address ends with invalid characters");
+ }
+ return ret;
+}
+
+static bool
+parse_mailbox_address(struct sieve_message_address_parser *ctx,
+ const unsigned char *address, unsigned int addr_size)
+{
+ /* Initialize parser */
+
+ rfc822_parser_init(&ctx->parser, address, addr_size, NULL);
+
+ /* Parse */
+
+ rfc822_skip_lwsp(&ctx->parser);
+
+ if (ctx->parser.data == ctx->parser.end) {
+ sieve_address_error(ctx, "empty address");
+ return FALSE;
+ }
+
+ if (parse_mailbox(ctx) < 0)
+ return FALSE;
+
+ if (ctx->parser.data != ctx->parser.end) {
+ if (*ctx->parser.data == ',') {
+ sieve_address_error(
+ ctx, "not a single addres (found ',')");
+ } else {
+ sieve_address_error(
+ ctx, "address ends in invalid characters");
+ }
+ return FALSE;
+ }
+
+ if (str_len(ctx->domain) == 0) {
+ /* Not gonna happen */
+ sieve_address_error(ctx, "missing domain");
+ return FALSE;
+ }
+
+ if (str_len(ctx->local_part) == 0) {
+ sieve_address_error(ctx, "missing local part");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static bool
+sieve_address_do_validate(const unsigned char *address, size_t size,
+ const char **error_r)
+{
+ struct sieve_message_address_parser ctx;
+
+ *error_r = NULL;
+
+ if (address == NULL) {
+ *error_r = "null address";
+ return FALSE;
+ }
+
+ i_zero(&ctx);
+
+ ctx.local_part = t_str_new(128);
+ ctx.domain = t_str_new(128);
+ ctx.str = t_str_new(128);
+ ctx.error = t_str_new(128);
+
+ if (!parse_mailbox_address(&ctx, address, size)) {
+ *error_r = str_c(ctx.error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static const struct smtp_address *
+sieve_address_do_parse(const unsigned char *address, size_t size,
+ const char **error_r)
+{
+ struct sieve_message_address_parser ctx;
+
+ *error_r = NULL;
+
+ if (address == NULL)
+ return NULL;
+
+ i_zero(&ctx);
+
+ ctx.local_part = t_str_new(128);
+ ctx.domain = t_str_new(128);
+ ctx.str = t_str_new(128);
+ ctx.error = t_str_new(128);
+
+ if (!parse_mailbox_address(&ctx, address, size)) {
+ *error_r = str_c(ctx.error);
+ return NULL;
+ }
+
+ (void)str_lcase(str_c_modifiable(ctx.domain));
+
+ return smtp_address_create_temp(str_c(ctx.local_part),
+ str_c(ctx.domain));
+}
+
+/*
+ * Sieve address
+ */
+
+const struct smtp_address *
+sieve_address_parse(const char *address, const char **error_r)
+{
+ return sieve_address_do_parse((const unsigned char *)address,
+ strlen(address), error_r);
+}
+
+const struct smtp_address *
+sieve_address_parse_str(string_t *address, const char **error_r)
+{
+ return sieve_address_do_parse(str_data(address), str_len(address),
+ error_r);
+}
+
+bool sieve_address_validate(const char *address, const char **error_r)
+{
+ return sieve_address_do_validate((const unsigned char *)address,
+ strlen(address), error_r);
+}
+
+bool sieve_address_validate_str(string_t *address, const char **error_r)
+{
+ return sieve_address_do_validate(str_data(address), str_len(address),
+ error_r);
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-address.h b/pigeonhole/src/lib-sieve/sieve-address.h
new file mode 100644
index 0000000..3779a07
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-address.h
@@ -0,0 +1,67 @@
+#ifndef SIEVE_ADDRESS_H
+#define SIEVE_ADDRESS_H
+
+#include "lib.h"
+#include "strfuncs.h"
+#include "smtp-address.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+
+/*
+ * Address list API
+ */
+
+struct sieve_address_list {
+ struct sieve_stringlist strlist;
+
+ int (*next_item)(struct sieve_address_list *_addrlist,
+ struct smtp_address *addr_r, string_t **unparsed_r);
+};
+
+static inline int
+sieve_address_list_next_item(struct sieve_address_list *addrlist,
+ struct smtp_address *addr_r, string_t **unparsed_r)
+{
+ return addrlist->next_item(addrlist, addr_r, unparsed_r);
+}
+
+static inline void
+sieve_address_list_reset(struct sieve_address_list *addrlist)
+{
+ sieve_stringlist_reset(&addrlist->strlist);
+}
+
+static inline int
+sieve_address_list_get_length(struct sieve_address_list *addrlist)
+{
+ return sieve_stringlist_get_length(&addrlist->strlist);
+}
+
+static inline void
+sieve_address_list_set_trace(struct sieve_address_list *addrlist, bool trace)
+{
+ sieve_stringlist_set_trace(&addrlist->strlist, trace);
+}
+
+/*
+ * Header address list
+ */
+
+struct sieve_address_list *
+sieve_header_address_list_create(const struct sieve_runtime_env *renv,
+ struct sieve_stringlist *field_values);
+
+/*
+ * Sieve address parsing/validatin
+ */
+
+const struct smtp_address *
+sieve_address_parse(const char *address, const char **error_r);
+const struct smtp_address *
+sieve_address_parse_str(string_t *address, const char **error_r);
+
+bool sieve_address_validate(const char *address, const char **error_r);
+bool sieve_address_validate_str(string_t *address, const char **error_r);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-ast.c b/pigeonhole/src/lib-sieve/sieve-ast.c
new file mode 100644
index 0000000..197dbad
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-ast.c
@@ -0,0 +1,1111 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "mempool.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-script.h"
+#include "sieve-extensions.h"
+
+#include "sieve-ast.h"
+
+#include <stdio.h>
+
+/*
+ * Forward declarations
+ */
+
+static struct sieve_ast_node *
+sieve_ast_node_create(struct sieve_ast *ast, struct sieve_ast_node *parent,
+ enum sieve_ast_type type, unsigned int source_line);
+
+/*
+ * Types
+ */
+
+/* Extensions to the AST */
+
+struct sieve_ast_extension_reg {
+ const struct sieve_extension *ext;
+ const struct sieve_ast_extension *ast_ext;
+ void *context;
+
+ bool required:1;
+};
+
+/*
+ * AST object
+ */
+
+struct sieve_ast {
+ pool_t pool;
+ int refcount;
+
+ struct sieve_instance *svinst;
+
+ struct sieve_script *script;
+
+ struct sieve_ast_node *root;
+
+ ARRAY(const struct sieve_extension *) linked_extensions;
+ ARRAY(struct sieve_ast_extension_reg) extensions;
+};
+
+struct sieve_ast *sieve_ast_create(struct sieve_script *script)
+{
+ pool_t pool;
+ struct sieve_ast *ast;
+ unsigned int ext_count;
+
+ pool = pool_alloconly_create("sieve_ast", 32768);
+ ast = p_new(pool, struct sieve_ast, 1);
+ ast->pool = pool;
+ ast->refcount = 1;
+
+ ast->script = script;
+ sieve_script_ref(script);
+ ast->svinst = sieve_script_svinst(script);
+
+ ast->root = sieve_ast_node_create(ast, NULL, SAT_ROOT, 0);
+ ast->root->identifier = "ROOT";
+
+ ext_count = sieve_extensions_get_count(ast->svinst);
+ p_array_init(&ast->linked_extensions, pool, ext_count);
+ p_array_init(&ast->extensions, pool, ext_count);
+
+ return ast;
+}
+
+void sieve_ast_ref(struct sieve_ast *ast)
+{
+ ast->refcount++;
+}
+
+void sieve_ast_unref(struct sieve_ast **ast)
+{
+ unsigned int i, ext_count;
+ const struct sieve_ast_extension_reg *extrs;
+
+ i_assert((*ast)->refcount > 0);
+
+ if (--(*ast)->refcount != 0)
+ return;
+
+ /* Release script reference */
+ sieve_script_unref(&(*ast)->script);
+
+ /* Signal registered extensions that the AST is being destroyed */
+ extrs = array_get(&(*ast)->extensions, &ext_count);
+ for (i = 0; i < ext_count; i++) {
+ if (extrs[i].ast_ext != NULL && extrs[i].ast_ext->free != NULL)
+ extrs[i].ast_ext->free(extrs[i].ext, *ast,
+ extrs[i].context);
+ }
+
+ /* Destroy AST */
+ pool_unref(&(*ast)->pool);
+
+ *ast = NULL;
+}
+
+struct sieve_ast_node *sieve_ast_root(struct sieve_ast *ast)
+{
+ return ast->root;
+}
+
+pool_t sieve_ast_pool(struct sieve_ast *ast)
+{
+ return ast->pool;
+}
+
+struct sieve_script *sieve_ast_script(struct sieve_ast *ast)
+{
+ return ast->script;
+}
+
+/*
+ * Extension support
+ */
+
+void sieve_ast_extension_link(struct sieve_ast *ast,
+ const struct sieve_extension *ext, bool required)
+{
+ unsigned int i, ext_count;
+ const struct sieve_extension *const *extensions;
+ struct sieve_ast_extension_reg *reg;
+
+ if (ext->id < 0)
+ return;
+
+ /* Initialize registration */
+ reg = array_idx_get_space(&ast->extensions, (unsigned int)ext->id);
+ i_assert(reg->ext == NULL || reg->ext == ext);
+ reg->ext = ext;
+ reg->required = reg->required || required;
+
+ /* Prevent duplicates */
+ extensions = array_get(&ast->linked_extensions, &ext_count);
+ for (i = 0; i < ext_count; i++) {
+ if (extensions[i] == ext)
+ return;
+ }
+
+ /* Add extension */
+ array_append(&ast->linked_extensions, &ext, 1);
+}
+
+const struct sieve_extension * const *
+sieve_ast_extensions_get(struct sieve_ast *ast, unsigned int *count_r)
+{
+ return array_get(&ast->linked_extensions, count_r);
+}
+
+void sieve_ast_extension_register(struct sieve_ast *ast,
+ const struct sieve_extension *ext,
+ const struct sieve_ast_extension *ast_ext,
+ void *context)
+{
+ struct sieve_ast_extension_reg *reg;
+
+ if (ext->id < 0)
+ return;
+
+ /* Initialize registration */
+ reg = array_idx_get_space(&ast->extensions, (unsigned int)ext->id);
+ i_assert(reg->ext == NULL || reg->ext == ext);
+ reg->ext = ext;
+ reg->ast_ext = ast_ext;
+ reg->context = context;
+}
+
+void sieve_ast_extension_set_context(struct sieve_ast *ast,
+ const struct sieve_extension *ext,
+ void *context)
+{
+ struct sieve_ast_extension_reg *reg;
+
+ if (ext->id < 0)
+ return;
+
+ reg = array_idx_get_space(&ast->extensions, (unsigned int)ext->id);
+ reg->context = context;
+}
+
+void *sieve_ast_extension_get_context(struct sieve_ast *ast,
+ const struct sieve_extension *ext)
+{
+ const struct sieve_ast_extension_reg *reg;
+
+ if (ext->id < 0 || ext->id >= (int)array_count(&ast->extensions))
+ return NULL;
+
+ reg = array_idx(&ast->extensions, (unsigned int)ext->id);
+
+ return reg->context;
+}
+
+bool sieve_ast_extension_is_required
+(struct sieve_ast *ast, const struct sieve_extension *ext)
+{
+ const struct sieve_ast_extension_reg *reg;
+
+ i_assert(ext->id >= 0 &&
+ ext->id < (int)array_count(&ast->extensions));
+
+ reg = array_idx(&ast->extensions, (unsigned int)ext->id);
+ return reg->required;
+}
+
+/*
+ * AST list implementations
+ */
+
+/* Very simplistic linked list implementation
+ FIXME: Merge with core
+ */
+#define __LIST_CREATE(pool, type) { \
+ type *list = p_new(pool, type, 1); \
+ list->head = NULL; \
+ list->tail = NULL; \
+ list->len = 0; \
+ return list; \
+ }
+
+#define __LIST_ADD(list, node) { \
+ if (list->len + 1 < list->len) \
+ return FALSE; \
+ \
+ node->next = NULL; \
+ if (list->head == NULL) { \
+ node->prev = NULL; \
+ list->head = node; \
+ list->tail = node; \
+ } else { \
+ list->tail->next = node; \
+ node->prev = list->tail; \
+ list->tail = node; \
+ } \
+ list->len++; \
+ node->list = list; \
+ return TRUE; \
+ }
+
+#define __LIST_INSERT(list, before, node) { \
+ if (list->len + 1 < list->len) \
+ return FALSE; \
+ \
+ node->next = before; \
+ if (list->head == before) { \
+ node->prev = NULL; \
+ list->head = node; \
+ } else { \
+ before->prev->next = node; \
+ } \
+ node->prev = before->prev; \
+ before->prev = node; \
+ list->len++; \
+ node->list = list; \
+ \
+ return TRUE; \
+ }
+
+#define __LIST_JOIN(list, node_type, items) { \
+ node_type *node; \
+ \
+ if (list->len + items->len < list->len) \
+ return FALSE; \
+ \
+ if (items->len == 0) \
+ return TRUE; \
+ \
+ if (list->head == NULL) { \
+ list->head = items->head; \
+ list->tail = items->tail; \
+ } else { \
+ list->tail->next = items->head; \
+ items->head->prev = list->tail; \
+ list->tail = items->tail; \
+ } \
+ list->len += items->len; \
+ \
+ node = items->head; \
+ while (node != NULL) { \
+ node->list = list; \
+ node = node->next; \
+ } \
+ return TRUE; \
+ }
+
+#define __LIST_DETACH(first, node_type, count) { \
+ node_type *last, *result; \
+ unsigned int left; \
+ \
+ i_assert(first->list != NULL); \
+ \
+ left = count - 1; \
+ last = first; \
+ while (left > 0 && last->next != NULL) { \
+ left--; \
+ last = last->next; \
+ } \
+ \
+ if (first->list->head == first) \
+ first->list->head = last->next; \
+ if (first->list->tail == last) \
+ first->list->tail = first->prev; \
+ \
+ if (first->prev != NULL) \
+ first->prev->next = last->next; \
+ if (last->next != NULL) \
+ last->next->prev = first->prev; \
+ \
+ first->list->len -= count - left; \
+ \
+ result = last->next; \
+ first->prev = NULL; \
+ last->next = NULL; \
+ \
+ return result; \
+ }
+
+/* List of AST nodes */
+
+static struct sieve_ast_list *
+sieve_ast_list_create(pool_t pool)
+ __LIST_CREATE(pool, struct sieve_ast_list)
+
+static bool
+sieve_ast_list_add(struct sieve_ast_list *list, struct sieve_ast_node *node)
+ __LIST_ADD(list, node)
+
+static struct sieve_ast_node *
+sieve_ast_list_detach(struct sieve_ast_node *first, unsigned int count)
+ __LIST_DETACH(first, struct sieve_ast_node, count)
+
+/* List of argument AST nodes */
+
+struct sieve_ast_arg_list *sieve_ast_arg_list_create(pool_t pool)
+ __LIST_CREATE(pool, struct sieve_ast_arg_list)
+
+bool sieve_ast_arg_list_add(struct sieve_ast_arg_list *list,
+ struct sieve_ast_argument *argument)
+ __LIST_ADD(list, argument)
+
+bool sieve_ast_arg_list_insert(struct sieve_ast_arg_list *list,
+ struct sieve_ast_argument *before,
+ struct sieve_ast_argument *argument)
+ __LIST_INSERT(list, before, argument)
+
+static bool
+sieve_ast_arg_list_join(struct sieve_ast_arg_list *list,
+ struct sieve_ast_arg_list *items)
+ __LIST_JOIN(list, struct sieve_ast_argument, items)
+
+static struct sieve_ast_argument *
+sieve_ast_arg_list_detach(struct sieve_ast_argument *first,
+ const unsigned int count)
+ __LIST_DETACH(first, struct sieve_ast_argument, count)
+
+void sieve_ast_arg_list_substitute(struct sieve_ast_arg_list *list,
+ struct sieve_ast_argument *argument,
+ struct sieve_ast_argument *replacement)
+{
+ if (list->head == argument)
+ list->head = replacement;
+ if (list->tail == argument)
+ list->tail = replacement;
+
+ if (argument->prev != NULL)
+ argument->prev->next = replacement;
+ if (argument->next != NULL)
+ argument->next->prev = replacement;
+
+ replacement->prev = argument->prev;
+ replacement->next = argument->next;
+ replacement->list = argument->list;
+
+ argument->next = NULL;
+ argument->prev = NULL;
+}
+
+/*
+ * AST node
+ */
+
+static struct sieve_ast_node *
+sieve_ast_node_create(struct sieve_ast *ast, struct sieve_ast_node *parent,
+ enum sieve_ast_type type, unsigned int source_line)
+{
+ struct sieve_ast_node *node =
+ p_new(ast->pool, struct sieve_ast_node, 1);
+
+ node->ast = ast;
+ node->parent = parent;
+ node->type = type;
+
+ node->prev = NULL;
+ node->next = NULL;
+
+ node->arguments = NULL;
+ node->tests = NULL;
+ node->commands = NULL;
+
+ node->test_list = FALSE;
+ node->block = FALSE;
+
+ node->source_line = source_line;
+
+ return node;
+}
+
+static bool
+sieve_ast_node_add_command(struct sieve_ast_node *node,
+ struct sieve_ast_node *command)
+{
+ i_assert(command->type == SAT_COMMAND &&
+ (node->type == SAT_ROOT || node->type == SAT_COMMAND));
+
+ if (node->commands == NULL)
+ node->commands = sieve_ast_list_create(node->ast->pool);
+
+ return sieve_ast_list_add(node->commands, command);
+}
+
+static bool
+sieve_ast_node_add_test(struct sieve_ast_node *node,
+ struct sieve_ast_node *test)
+{
+ i_assert(test->type == SAT_TEST &&
+ (node->type == SAT_TEST || node->type == SAT_COMMAND));
+
+ if (node->tests == NULL)
+ node->tests = sieve_ast_list_create(node->ast->pool);
+
+ return sieve_ast_list_add(node->tests, test);
+}
+
+static bool
+sieve_ast_node_add_argument(struct sieve_ast_node *node,
+ struct sieve_ast_argument *argument)
+{
+ i_assert(node->type == SAT_TEST || node->type == SAT_COMMAND);
+
+ if (node->arguments == NULL)
+ node->arguments = sieve_ast_arg_list_create(node->ast->pool);
+
+ return sieve_ast_arg_list_add(node->arguments, argument);
+}
+
+struct sieve_ast_node *sieve_ast_node_detach(struct sieve_ast_node *first)
+{
+ return sieve_ast_list_detach(first, 1);
+}
+
+const char *sieve_ast_type_name(enum sieve_ast_type ast_type)
+{
+ switch (ast_type) {
+ case SAT_NONE:
+ return "none";
+ case SAT_ROOT:
+ return "ast root node";
+ case SAT_COMMAND:
+ return "command";
+ case SAT_TEST:
+ return "test";
+ default:
+ return "??AST NODE??";
+ }
+}
+
+/*
+ * Argument AST node
+ */
+
+struct sieve_ast_argument *
+sieve_ast_argument_create(struct sieve_ast *ast, unsigned int source_line)
+{
+ struct sieve_ast_argument *arg =
+ p_new(ast->pool, struct sieve_ast_argument, 1);
+
+ arg->ast = ast;
+
+ arg->prev = NULL;
+ arg->next = NULL;
+
+ arg->source_line = source_line;
+
+ arg->argument = NULL;
+
+ return arg;
+}
+
+static void
+sieve_ast_argument_substitute(struct sieve_ast_argument *argument,
+ struct sieve_ast_argument *replacement)
+{
+ sieve_ast_arg_list_substitute(argument->list, argument, replacement);
+}
+
+struct sieve_ast_argument *
+sieve_ast_argument_string_create_raw(struct sieve_ast *ast, string_t *str,
+ unsigned int source_line)
+{
+ struct sieve_ast_argument *argument =
+ sieve_ast_argument_create(ast, source_line);
+
+ argument->type = SAAT_STRING;
+ argument->_value.str = str;
+
+ return argument;
+}
+
+struct sieve_ast_argument *
+sieve_ast_argument_string_create(struct sieve_ast_node *node,
+ const string_t *str, unsigned int source_line)
+{
+ struct sieve_ast_argument *argument;
+ string_t *newstr;
+
+ /* Allocate new internal string buffer */
+ newstr = str_new(node->ast->pool, str_len(str));
+
+ /* Clone string */
+ str_append_str(newstr, str);
+
+ /* Create string argument */
+ argument = sieve_ast_argument_string_create_raw(
+ node->ast, newstr, source_line);
+
+ /* Add argument to command/test node */
+ sieve_ast_node_add_argument(node, argument);
+
+ return argument;
+}
+
+struct sieve_ast_argument *
+sieve_ast_argument_cstring_create(struct sieve_ast_node *node, const char *str,
+ unsigned int source_line)
+{
+ struct sieve_ast_argument *argument;
+ string_t *newstr;
+
+ /* Allocate new internal string buffer */
+ newstr = str_new(node->ast->pool, strlen(str));
+
+ /* Clone string */
+ str_append(newstr, str);
+
+ /* Create string argument */
+ argument = sieve_ast_argument_string_create_raw(
+ node->ast, newstr, source_line);
+
+ /* Add argument to command/test node */
+ sieve_ast_node_add_argument(node, argument);
+
+ return argument;
+}
+
+void sieve_ast_argument_string_set(struct sieve_ast_argument *argument,
+ string_t *newstr)
+{
+ i_assert(argument->type == SAAT_STRING);
+ argument->_value.str = newstr;
+}
+
+void sieve_ast_argument_string_setc(struct sieve_ast_argument *argument,
+ const char *newstr)
+{
+ i_assert(argument->type == SAAT_STRING);
+
+ str_truncate(argument->_value.str, 0);
+ str_append(argument->_value.str, newstr);
+}
+
+void sieve_ast_argument_number_substitute(struct sieve_ast_argument *argument,
+ sieve_number_t number)
+{
+ argument->type = SAAT_NUMBER;
+ argument->_value.number = number;
+}
+
+struct sieve_ast_argument *
+sieve_ast_argument_stringlist_create(struct sieve_ast_node *node,
+ unsigned int source_line)
+{
+ struct sieve_ast_argument *argument =
+ sieve_ast_argument_create(node->ast, source_line);
+
+ argument->type = SAAT_STRING_LIST;
+ argument->_value.strlist = NULL;
+
+ sieve_ast_node_add_argument(node, argument);
+
+ return argument;
+}
+
+struct sieve_ast_argument *
+sieve_ast_argument_stringlist_substitute(struct sieve_ast_node *node,
+ struct sieve_ast_argument *arg)
+{
+ struct sieve_ast_argument *argument =
+ sieve_ast_argument_create(node->ast, arg->source_line);
+
+ argument->type = SAAT_STRING_LIST;
+ argument->_value.strlist = NULL;
+
+ sieve_ast_argument_substitute(arg, argument);
+
+ return argument;
+}
+
+static inline bool
+_sieve_ast_stringlist_add_item(struct sieve_ast_argument *list,
+ struct sieve_ast_argument *item)
+{
+ i_assert(list->type == SAAT_STRING_LIST);
+
+ if (list->_value.strlist == NULL) {
+ list->_value.strlist =
+ sieve_ast_arg_list_create(list->ast->pool);
+ }
+
+ return sieve_ast_arg_list_add(list->_value.strlist, item);
+}
+
+static bool
+sieve_ast_stringlist_add_stringlist(struct sieve_ast_argument *list,
+ struct sieve_ast_argument *items)
+{
+ i_assert(list->type == SAAT_STRING_LIST);
+ i_assert(items->type == SAAT_STRING_LIST);
+
+ if (list->_value.strlist == NULL) {
+ list->_value.strlist =
+ sieve_ast_arg_list_create(list->ast->pool);
+ }
+
+ return sieve_ast_arg_list_join(list->_value.strlist,
+ items->_value.strlist);
+}
+
+static bool
+_sieve_ast_stringlist_add_str(struct sieve_ast_argument *list, string_t *str,
+ unsigned int source_line)
+{
+ struct sieve_ast_argument *stritem;
+
+ stritem = sieve_ast_argument_create(list->ast, source_line);
+ stritem->type = SAAT_STRING;
+ stritem->_value.str = str;
+
+ return _sieve_ast_stringlist_add_item(list, stritem);
+}
+
+bool sieve_ast_stringlist_add(struct sieve_ast_argument *list,
+ const string_t *str, unsigned int source_line)
+{
+ string_t *copied_str = str_new(list->ast->pool, str_len(str));
+ str_append_str(copied_str, str);
+
+ return _sieve_ast_stringlist_add_str(list, copied_str, source_line);
+}
+
+bool sieve_ast_stringlist_add_strc(struct sieve_ast_argument *list,
+ const char *str, unsigned int source_line)
+{
+ string_t *copied_str = str_new(list->ast->pool, strlen(str));
+ str_append(copied_str, str);
+
+ return _sieve_ast_stringlist_add_str(list, copied_str, source_line);
+}
+
+struct sieve_ast_argument *
+sieve_ast_argument_tag_create(struct sieve_ast_node *node, const char *tag,
+ unsigned int source_line)
+{
+ struct sieve_ast_argument *argument =
+ sieve_ast_argument_create(node->ast, source_line);
+
+ argument->type = SAAT_TAG;
+ argument->_value.tag = p_strdup(node->ast->pool, tag);
+
+ if (!sieve_ast_node_add_argument(node, argument))
+ return NULL;
+ return argument;
+}
+
+struct sieve_ast_argument *
+sieve_ast_argument_tag_insert(struct sieve_ast_argument *before,
+ const char *tag, unsigned int source_line)
+{
+ struct sieve_ast_argument *argument =
+ sieve_ast_argument_create(before->ast, source_line);
+
+ argument->type = SAAT_TAG;
+ argument->_value.tag = p_strdup(before->ast->pool, tag);
+
+ if (!sieve_ast_arg_list_insert(before->list, before, argument))
+ return NULL;
+ return argument;
+}
+
+struct sieve_ast_argument *
+sieve_ast_argument_number_create(struct sieve_ast_node *node,
+ sieve_number_t number,
+ unsigned int source_line)
+{
+ struct sieve_ast_argument *argument =
+ sieve_ast_argument_create(node->ast, source_line);
+
+ argument->type = SAAT_NUMBER;
+ argument->_value.number = number;
+
+ if (!sieve_ast_node_add_argument(node, argument))
+ return NULL;
+ return argument;
+}
+
+void sieve_ast_argument_number_set(struct sieve_ast_argument *argument,
+ sieve_number_t newnum)
+{
+ i_assert(argument->type == SAAT_NUMBER);
+ argument->_value.number = newnum;
+}
+
+struct sieve_ast_argument *
+sieve_ast_arguments_detach(struct sieve_ast_argument *first,
+ unsigned int count)
+{
+ return sieve_ast_arg_list_detach(first, count);
+}
+
+bool sieve_ast_argument_attach(struct sieve_ast_node *node,
+ struct sieve_ast_argument *argument)
+{
+ return sieve_ast_node_add_argument(node, argument);
+}
+
+const char *sieve_ast_argument_type_name(enum sieve_ast_argument_type arg_type)
+{
+ switch (arg_type) {
+ case SAAT_NONE:
+ return "none";
+ case SAAT_STRING_LIST:
+ return "a string list";
+ case SAAT_STRING:
+ return "a string";
+ case SAAT_NUMBER:
+ return "a number";
+ case SAAT_TAG:
+ return "a tag";
+ default:
+ return "??ARGUMENT??";
+ }
+}
+
+/* Test AST node */
+
+struct sieve_ast_node *
+sieve_ast_test_create(struct sieve_ast_node *parent, const char *identifier,
+ unsigned int source_line)
+{
+ struct sieve_ast_node *test = sieve_ast_node_create(
+ parent->ast, parent, SAT_TEST, source_line);
+
+ test->identifier = p_strdup(parent->ast->pool, identifier);
+
+ if (!sieve_ast_node_add_test(parent, test))
+ return NULL;
+ return test;
+}
+
+/* Command AST node */
+
+struct sieve_ast_node *
+sieve_ast_command_create(struct sieve_ast_node *parent, const char *identifier,
+ unsigned int source_line)
+{
+ struct sieve_ast_node *command = sieve_ast_node_create(
+ parent->ast, parent, SAT_COMMAND, source_line);
+
+ command->identifier = p_strdup(parent->ast->pool, identifier);
+
+ if (!sieve_ast_node_add_command(parent, command))
+ return NULL;
+ return command;
+}
+
+/*
+ * Utility
+ */
+
+int sieve_ast_stringlist_map(
+ struct sieve_ast_argument **listitem, void *context,
+ int (*map_function)(void *context, struct sieve_ast_argument *arg))
+{
+ if (sieve_ast_argument_type(*listitem) == SAAT_STRING) {
+ /* Single string */
+ return map_function(context, *listitem);
+ } else if (sieve_ast_argument_type(*listitem) == SAAT_STRING_LIST) {
+ int ret = 0;
+
+ /* String list */
+ *listitem = sieve_ast_strlist_first(*listitem);
+
+ while (*listitem != NULL) {
+ if ((ret = map_function(context, *listitem)) <= 0)
+ return ret;
+
+ *listitem = sieve_ast_strlist_next(*listitem);
+ }
+
+ return ret;
+ }
+
+ i_unreached();
+ return -1;
+}
+
+struct sieve_ast_argument *
+sieve_ast_stringlist_join(struct sieve_ast_argument *list,
+ struct sieve_ast_argument *items)
+{
+ enum sieve_ast_argument_type list_type, items_type;
+ struct sieve_ast_argument *newlist;
+
+ list_type = sieve_ast_argument_type(list);
+ items_type = sieve_ast_argument_type(items);
+
+ switch (list_type) {
+ case SAAT_STRING:
+ switch (items_type) {
+ case SAAT_STRING:
+ newlist = sieve_ast_argument_create(
+ list->ast, list->source_line);
+ newlist->type = SAAT_STRING_LIST;
+ newlist->_value.strlist = NULL;
+
+ sieve_ast_argument_substitute(list, newlist);
+ sieve_ast_arguments_detach(items, 1);
+
+ if (!_sieve_ast_stringlist_add_item(newlist, list) ||
+ !_sieve_ast_stringlist_add_item(newlist, items))
+ return NULL;
+ return newlist;
+ case SAAT_STRING_LIST:
+ /* Adding stringlist to string; make them swith places
+ and add one to the other.
+ */
+ sieve_ast_arguments_detach(items, 1);
+ sieve_ast_argument_substitute(list, items);
+ if (!_sieve_ast_stringlist_add_item(items, list))
+ return NULL;
+ return list;
+ default:
+ i_unreached();
+ }
+ break;
+ case SAAT_STRING_LIST:
+ switch (items_type) {
+ case SAAT_STRING:
+ /* Adding string to stringlist; straightforward add */
+ sieve_ast_arguments_detach(items, 1);
+ if (!_sieve_ast_stringlist_add_item(list, items))
+ return NULL;
+ return list;
+ case SAAT_STRING_LIST:
+ /* Adding stringlist to stringlist; perform actual join
+ */
+ sieve_ast_arguments_detach(items, 1);
+ if (!sieve_ast_stringlist_add_stringlist(list, items))
+ return NULL;
+ return list;
+ default:
+ i_unreached();
+ }
+ break;
+ default:
+ i_unreached();
+ }
+ return NULL;
+}
+
+/* Debug */
+
+/* Unparsing, currently implemented using plain printf()s */
+
+static void sieve_ast_unparse_string(const string_t *strval)
+{
+ char *str = t_strdup_noconst(str_c((string_t *)strval));
+
+ if (strchr(str, '\n') != NULL && str[strlen(str)-1] == '\n') {
+ /* Print it as a multi-line string and do required dotstuffing
+ */
+ char *spos = str;
+ char *epos = strchr(str, '\n');
+ printf("text:\n");
+
+ while (epos != NULL) {
+ *epos = '\0';
+ if (*spos == '.')
+ printf(".");
+
+ printf("%s\n", spos);
+
+ spos = epos+1;
+ epos = strchr(spos, '\n');
+ }
+ if (*spos == '.')
+ printf(".");
+
+ printf("%s\n.\n", spos);
+ } else {
+ /* Print it as a quoted string and escape " */
+ char *spos = str;
+ char *epos = strchr(str, '"');
+ printf("\"");
+
+ while (epos != NULL) {
+ *epos = '\0';
+ printf("%s\\\"", spos);
+
+ spos = epos+1;
+ epos = strchr(spos, '"');
+ }
+
+ printf("%s\"", spos);
+ }
+}
+
+static void
+sieve_ast_unparse_argument(struct sieve_ast_argument *argument, int level);
+
+static void
+sieve_ast_unparse_stringlist(struct sieve_ast_argument *strlist, int level)
+{
+ struct sieve_ast_argument *stritem;
+
+ if (sieve_ast_strlist_count(strlist) > 1) {
+ int i;
+
+ printf("[\n");
+
+ /* Create indent */
+ for (i = 0; i < level+2; i++)
+ printf(" ");
+
+ stritem = sieve_ast_strlist_first(strlist);
+ if (stritem != NULL) {
+ sieve_ast_unparse_string(
+ sieve_ast_strlist_str(stritem));
+
+ stritem = sieve_ast_strlist_next(stritem);
+ while (stritem != NULL) {
+ printf(",\n");
+ for (i = 0; i < level+2; i++)
+ printf(" ");
+ sieve_ast_unparse_string(
+ sieve_ast_strlist_str(stritem));
+ stritem = sieve_ast_strlist_next(stritem);
+ }
+ }
+
+ printf(" ]");
+ } else {
+ stritem = sieve_ast_strlist_first(strlist);
+ if (stritem != NULL) {
+ sieve_ast_unparse_string(
+ sieve_ast_strlist_str(stritem));
+ }
+ }
+}
+
+static void
+sieve_ast_unparse_argument(struct sieve_ast_argument *argument, int level)
+{
+ switch (argument->type) {
+ case SAAT_STRING:
+ sieve_ast_unparse_string(sieve_ast_argument_str(argument));
+ break;
+ case SAAT_STRING_LIST:
+ sieve_ast_unparse_stringlist(argument, level+1);
+ break;
+ case SAAT_NUMBER:
+ printf("%"SIEVE_PRI_NUMBER,
+ sieve_ast_argument_number(argument));
+ break;
+ case SAAT_TAG:
+ printf(":%s", sieve_ast_argument_tag(argument));
+ break;
+ default:
+ printf("??ARGUMENT??");
+ break;
+ }
+}
+
+static void sieve_ast_unparse_test(struct sieve_ast_node *node, int level);
+
+static void sieve_ast_unparse_tests(struct sieve_ast_node *node, int level)
+{
+ struct sieve_ast_node *test;
+
+ if (sieve_ast_test_count(node) > 1) {
+ int i;
+
+ printf(" (\n");
+
+ /* Create indent */
+ for (i = 0; i < level+2; i++)
+ printf(" ");
+
+ test = sieve_ast_test_first(node);
+ sieve_ast_unparse_test(test, level+1);
+
+ test = sieve_ast_test_next(test);
+ while (test != NULL) {
+ printf(", \n");
+ for (i = 0; i < level+2; i++)
+ printf(" ");
+ sieve_ast_unparse_test(test, level+1);
+ test = sieve_ast_test_next(test);
+ }
+
+ printf(" )");
+ } else {
+ test = sieve_ast_test_first(node);
+ if (test != NULL)
+ sieve_ast_unparse_test(test, level);
+ }
+}
+
+static void sieve_ast_unparse_test(struct sieve_ast_node *node, int level)
+{
+ struct sieve_ast_argument *argument;
+
+ printf(" %s", node->identifier);
+
+ argument = sieve_ast_argument_first(node);
+ while (argument != NULL) {
+ printf(" ");
+ sieve_ast_unparse_argument(argument, level);
+ argument = sieve_ast_argument_next(argument);
+ }
+
+ sieve_ast_unparse_tests(node, level);
+}
+
+static void sieve_ast_unparse_command(struct sieve_ast_node *node, int level)
+{
+ struct sieve_ast_node *command;
+ struct sieve_ast_argument *argument;
+
+ int i;
+
+ /* Create indent */
+ for (i = 0; i < level; i++)
+ printf(" ");
+
+ printf("%s", node->identifier);
+
+ argument = sieve_ast_argument_first(node);
+ while (argument != NULL) {
+ printf(" ");
+ sieve_ast_unparse_argument(argument, level);
+ argument = sieve_ast_argument_next(argument);
+ }
+
+ sieve_ast_unparse_tests(node, level);
+
+ command = sieve_ast_command_first(node);
+ if (command != NULL) {
+ printf(" {\n");
+
+ while (command != NULL) {
+ sieve_ast_unparse_command(command, level+1);
+ command = sieve_ast_command_next(command);
+ }
+
+ for (i = 0; i < level; i++)
+ printf(" ");
+ printf("}\n");
+ } else
+ printf(";\n");
+}
+
+void sieve_ast_unparse(struct sieve_ast *ast)
+{
+ struct sieve_ast_node *command;
+
+ printf("Unparsing Abstract Syntax Tree:\n");
+
+ T_BEGIN {
+ command = sieve_ast_command_first(sieve_ast_root(ast));
+ while (command != NULL) {
+ sieve_ast_unparse_command(command, 0);
+ command = sieve_ast_command_next(command);
+ }
+ } T_END;
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-ast.h b/pigeonhole/src/lib-sieve/sieve-ast.h
new file mode 100644
index 0000000..00f8a6b
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-ast.h
@@ -0,0 +1,382 @@
+#ifndef SIEVE_AST_H
+#define SIEVE_AST_H
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+
+/*
+ Abstract Syntax Tree (AST) structure:
+
+ sieve_ast (root)
+ [*command]
+ |
+ +-- command:
+ | ....
+ +-- command:
+ | [identifier *argument *test *command]
+ | +-- argument: | \--> as from root
+ | | .... |
+ | +-- argument: V (continued below)
+ | | [number | tag | *string]
+ | .
+ .
+
+ *test
+ +-- test:
+ | ....
+ +-- test:
+ | [identifier *argument *test]
+ | +-- argument: \--> as from the top
+ . | .... of this tree
+ +-- argument:
+ | [number | tag | *string]
+ .
+
+ Tests and commands are defined using the same structure: sieve_ast_node.
+ However, arguments and string-lists are described using sieve_ast_argument.
+*/
+
+/* IMPORTANT NOTICE: Do not decorate the AST with objects other than those
+ allocated on the ast's pool or static const objects. Otherwise it is possible
+ that pointers in the tree become dangling which is highly undesirable.
+ */
+
+/*
+ * Forward declarations
+ */
+
+struct sieve_ast_list;
+struct sieve_ast_arg_list;
+
+/*
+ * Types
+ */
+
+enum sieve_ast_argument_type {
+ SAAT_NONE,
+ SAAT_NUMBER,
+ SAAT_STRING,
+ SAAT_STRING_LIST,
+ SAAT_TAG,
+};
+
+enum sieve_ast_type {
+ SAT_NONE,
+ SAT_ROOT,
+ SAT_COMMAND,
+ SAT_TEST,
+};
+
+/*
+ * AST Nodes
+ */
+
+/* Argument node */
+
+struct sieve_ast_argument {
+ enum sieve_ast_argument_type type;
+
+ /* Back reference to the AST object */
+ struct sieve_ast *ast;
+
+ /* List related */
+ struct sieve_ast_arg_list *list;
+ struct sieve_ast_argument *next;
+ struct sieve_ast_argument *prev;
+
+ /* Parser-assigned data */
+
+ union {
+ string_t *str;
+ struct sieve_ast_arg_list *strlist;
+ const char *tag;
+ sieve_number_t number;
+ } _value;
+
+ unsigned int source_line;
+
+ /* Assigned during validation */
+
+ /* Argument associated with this ast element */
+ struct sieve_argument *argument;
+
+ /* Parameters to this (tag) argument */
+ struct sieve_ast_argument *parameters;
+};
+
+struct sieve_ast_node {
+ enum sieve_ast_type type;
+
+ /* Back reference to the AST object */
+ struct sieve_ast *ast;
+
+ /* Back reference to this node's parent */
+ struct sieve_ast_node *parent;
+
+ /* Linked list references */
+ struct sieve_ast_list *list;
+ struct sieve_ast_node *next;
+ struct sieve_ast_node *prev;
+
+ /* Commands (NULL if not allocated) */
+ bool block;
+ struct sieve_ast_list *commands;
+
+ /* Tests (NULL if not allocated)*/
+ bool test_list;
+ struct sieve_ast_list *tests;
+
+ /* Arguments (NULL if not allocated) */
+ struct sieve_ast_arg_list *arguments;
+
+ /* Identifier of command or test */
+ const char *identifier;
+
+ /* The location in the file where this command was started */
+ unsigned int source_line;
+
+ /* Assigned during validation */
+
+ /* Context */
+ struct sieve_command *command;
+};
+
+/*
+ * AST node lists
+ */
+
+struct sieve_ast_list {
+ struct sieve_ast_node *head;
+ struct sieve_ast_node *tail;
+ unsigned int len;
+};
+
+struct sieve_ast_arg_list {
+ struct sieve_ast_argument *head;
+ struct sieve_ast_argument *tail;
+ unsigned int len;
+};
+
+/*
+ * AST object
+ */
+
+struct sieve_ast;
+
+struct sieve_ast *sieve_ast_create(struct sieve_script *script);
+void sieve_ast_ref(struct sieve_ast *ast);
+void sieve_ast_unref(struct sieve_ast **ast);
+
+struct sieve_ast_node *sieve_ast_root(struct sieve_ast *ast);
+pool_t sieve_ast_pool(struct sieve_ast *ast);
+struct sieve_script *sieve_ast_script(struct sieve_ast *ast);
+
+/* Extension support */
+
+struct sieve_ast_extension {
+ const struct sieve_extension_def *ext;
+
+ void (*free)(const struct sieve_extension *ext, struct sieve_ast *ast,
+ void *context);
+};
+
+void sieve_ast_extension_link(struct sieve_ast *ast,
+ const struct sieve_extension *ext,
+ bool required);
+const struct sieve_extension * const *
+sieve_ast_extensions_get(struct sieve_ast *ast, unsigned int *count_r);
+
+void sieve_ast_extension_register(struct sieve_ast *ast,
+ const struct sieve_extension *ext,
+ const struct sieve_ast_extension *ast_ext,
+ void *context);
+void sieve_ast_extension_set_context(struct sieve_ast *ast,
+ const struct sieve_extension *ext,
+ void *context);
+void *sieve_ast_extension_get_context(struct sieve_ast *ast,
+ const struct sieve_extension *ext);
+
+bool sieve_ast_extension_is_required(struct sieve_ast *ast,
+ const struct sieve_extension *ext);
+
+/*
+ * AST node manipulation
+ */
+
+/* Command nodes */
+
+struct sieve_ast_node *
+sieve_ast_test_create(struct sieve_ast_node *parent, const char *identifier,
+ unsigned int source_line);
+struct sieve_ast_node *
+sieve_ast_command_create(struct sieve_ast_node *parent, const char *identifier,
+ unsigned int source_line);
+
+struct sieve_ast_node *
+sieve_ast_node_detach(struct sieve_ast_node *first);
+
+const char *sieve_ast_type_name(enum sieve_ast_type ast_type);
+
+/* Argument nodes */
+
+struct sieve_ast_argument *
+sieve_ast_argument_create(struct sieve_ast *ast, unsigned int source_line);
+
+struct sieve_ast_arg_list *sieve_ast_arg_list_create(pool_t pool);
+bool sieve_ast_arg_list_add(struct sieve_ast_arg_list *list,
+ struct sieve_ast_argument *argument);
+bool sieve_ast_arg_list_insert(struct sieve_ast_arg_list *list,
+ struct sieve_ast_argument *before,
+ struct sieve_ast_argument *argument);
+void sieve_ast_arg_list_substitute(struct sieve_ast_arg_list *list,
+ struct sieve_ast_argument *argument,
+ struct sieve_ast_argument *replacement);
+
+struct sieve_ast_argument *
+sieve_ast_argument_string_create_raw(struct sieve_ast *ast, string_t *str,
+ unsigned int source_line);
+struct sieve_ast_argument *
+sieve_ast_argument_string_create(struct sieve_ast_node *node,
+ const string_t *str, unsigned int source_line);
+struct sieve_ast_argument *
+sieve_ast_argument_cstring_create(struct sieve_ast_node *node, const char *str,
+ unsigned int source_line);
+
+struct sieve_ast_argument *
+sieve_ast_argument_tag_create(struct sieve_ast_node *node, const char *tag,
+ unsigned int source_line);
+
+struct sieve_ast_argument *
+sieve_ast_argument_number_create(struct sieve_ast_node *node,
+ sieve_number_t number,
+ unsigned int source_line);
+
+void sieve_ast_argument_string_set(struct sieve_ast_argument *argument,
+ string_t *newstr);
+void sieve_ast_argument_string_setc(struct sieve_ast_argument *argument,
+ const char *newstr);
+
+void sieve_ast_argument_number_set(struct sieve_ast_argument *argument,
+ sieve_number_t newnum);
+void sieve_ast_argument_number_substitute(struct sieve_ast_argument *argument,
+ sieve_number_t number);
+
+struct sieve_ast_argument *
+sieve_ast_argument_tag_insert(struct sieve_ast_argument *before,
+ const char *tag, unsigned int source_line);
+
+struct sieve_ast_argument *
+sieve_ast_argument_stringlist_create(struct sieve_ast_node *node,
+ unsigned int source_line);
+struct sieve_ast_argument *
+sieve_ast_argument_stringlist_substitute(struct sieve_ast_node *node,
+ struct sieve_ast_argument *arg);
+
+struct sieve_ast_argument *
+sieve_ast_arguments_detach(struct sieve_ast_argument *first,
+ unsigned int count);
+bool sieve_ast_argument_attach(struct sieve_ast_node *node,
+ struct sieve_ast_argument *argument);
+
+const char *sieve_ast_argument_type_name(enum sieve_ast_argument_type arg_type);
+#define sieve_ast_argument_name(argument) \
+ sieve_ast_argument_type_name((argument)->type)
+
+bool sieve_ast_stringlist_add(struct sieve_ast_argument *list,
+ const string_t *str, unsigned int source_line);
+bool sieve_ast_stringlist_add_strc(struct sieve_ast_argument *list,
+ const char *str, unsigned int source_line);
+
+/*
+ * Utility
+ */
+
+int sieve_ast_stringlist_map(
+ struct sieve_ast_argument **listitem, void *context,
+ int (*map_function)(void *context, struct sieve_ast_argument *arg));
+struct sieve_ast_argument *
+sieve_ast_stringlist_join(struct sieve_ast_argument *list,
+ struct sieve_ast_argument *items);
+
+/*
+ * AST access macros
+ */
+
+/* Generic list access macros */
+#define __AST_LIST_FIRST(list) \
+ ((list) == NULL ? NULL : (list)->head)
+#define __AST_LIST_LAST(list) \
+ ((list) == NULL ? NULL : (list)->tail)
+#define __AST_LIST_COUNT(list) \
+ ((list) == NULL || (list)->head == NULL ? 0 : (list)->len)
+#define __AST_LIST_NEXT(item) ((item)->next)
+#define __AST_LIST_PREV(item) ((item)->prev)
+
+#define __AST_NODE_LIST_FIRST(node, list) __AST_LIST_FIRST((node)->list)
+#define __AST_NODE_LIST_LAST(node, list) __AST_LIST_LAST((node)->list)
+#define __AST_NODE_LIST_COUNT(node, list) __AST_LIST_COUNT((node)->list)
+
+/* AST macros */
+
+/* AST node macros */
+#define sieve_ast_node_pool(node) (sieve_ast_pool((node)->ast))
+#define sieve_ast_node_parent(node) ((node)->parent)
+#define sieve_ast_node_prev(node) __AST_LIST_PREV(node)
+#define sieve_ast_node_next(node) __AST_LIST_NEXT(node)
+#define sieve_ast_node_type(node) ((node) == NULL ? SAT_NONE : (node)->type)
+#define sieve_ast_node_line(node) ((node) == NULL ? 0 : (node)->source_line)
+
+/* AST command node macros */
+#define sieve_ast_command_first(node) __AST_NODE_LIST_FIRST(node, commands)
+#define sieve_ast_command_count(node) __AST_NODE_LIST_COUNT(node, commands)
+#define sieve_ast_command_prev(command) __AST_LIST_PREV(command)
+#define sieve_ast_command_next(command) __AST_LIST_NEXT(command)
+
+/* Compare the identifier of the previous command */
+#define sieve_ast_prev_cmd_is(cmd, id) \
+ ((cmd)->prev == NULL ? FALSE : \
+ strncasecmp((cmd)->prev->identifier, id, sizeof(id)-1) == 0)
+
+/* AST test macros */
+#define sieve_ast_test_count(node) __AST_NODE_LIST_COUNT(node, tests)
+#define sieve_ast_test_first(node) __AST_NODE_LIST_FIRST(node, tests)
+#define sieve_ast_test_next(test) __AST_LIST_NEXT(test)
+
+/* AST argument macros */
+#define sieve_ast_argument_pool(node) (sieve_ast_pool((node)->ast))
+#define sieve_ast_argument_first(node) __AST_NODE_LIST_FIRST(node, arguments)
+#define sieve_ast_argument_last(node) __AST_NODE_LIST_LAST(node, arguments)
+#define sieve_ast_argument_count(node) __AST_NODE_LIST_COUNT(node, arguments)
+#define sieve_ast_argument_prev(argument) __AST_LIST_PREV(argument)
+#define sieve_ast_argument_next(argument) __AST_LIST_NEXT(argument)
+#define sieve_ast_argument_type(argument) (argument)->type
+#define sieve_ast_argument_line(argument) (argument)->source_line
+
+#define sieve_ast_argument_str(argument) ((argument)->_value.str)
+#define sieve_ast_argument_strc(argument) (str_c((argument)->_value.str))
+#define sieve_ast_argument_tag(argument) ((argument)->_value.tag)
+#define sieve_ast_argument_number(argument) ((argument)->_value.number)
+
+/* AST string list macros */
+// @UNSAFE: should check whether we are actually accessing a string list
+#define sieve_ast_strlist_first(list) \
+ __AST_NODE_LIST_FIRST(list, _value.strlist)
+#define sieve_ast_strlist_last(list) \
+ __AST_NODE_LIST_LAST(list, _value.strlist)
+#define sieve_ast_strlist_count(list) \
+ __AST_NODE_LIST_COUNT(list, _value.strlist)
+#define sieve_ast_strlist_next(str) __AST_LIST_NEXT(str)
+#define sieve_ast_strlist_prev(str) __AST_LIST_PREV(str)
+#define sieve_ast_strlist_str(str) sieve_ast_argument_str(str)
+#define sieve_ast_strlist_strc(str) sieve_ast_argument_strc(str)
+
+/*
+ * Debug
+ */
+
+void sieve_ast_unparse(struct sieve_ast *ast);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-binary-code.c b/pigeonhole/src/lib-sieve/sieve-binary-code.c
new file mode 100644
index 0000000..0d76ee0
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-binary-code.c
@@ -0,0 +1,405 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "mempool.h"
+#include "buffer.h"
+#include "hash.h"
+#include "array.h"
+#include "ostream.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-extensions.h"
+#include "sieve-code.h"
+#include "sieve-script.h"
+
+#include "sieve-binary-private.h"
+
+/*
+ * Forward declarations
+ */
+
+static inline sieve_size_t
+sieve_binary_emit_dynamic_data(struct sieve_binary_block *sblock,
+ const void *data, size_t size);
+
+/*
+ * Emission functions
+ */
+
+/* Low-level emission functions */
+
+static inline void
+_sieve_binary_emit_data(struct sieve_binary_block *sblock,
+ const void *data, sieve_size_t size)
+{
+ buffer_append(sblock->data, data, size);
+}
+
+static inline void
+_sieve_binary_emit_byte(struct sieve_binary_block *sblock, uint8_t byte)
+{
+ _sieve_binary_emit_data(sblock, &byte, 1);
+}
+
+static inline void
+_sieve_binary_update_data(struct sieve_binary_block *sblock,
+ sieve_size_t address, const void *data,
+ sieve_size_t size)
+{
+ buffer_write(sblock->data, address, data, size);
+}
+
+sieve_size_t sieve_binary_emit_data(struct sieve_binary_block *sblock,
+ const void *data, sieve_size_t size)
+{
+ sieve_size_t address = _sieve_binary_block_get_size(sblock);
+
+ _sieve_binary_emit_data(sblock, data, size);
+
+ return address;
+}
+
+sieve_size_t sieve_binary_emit_byte(struct sieve_binary_block *sblock,
+ uint8_t byte)
+{
+ sieve_size_t address = _sieve_binary_block_get_size(sblock);
+
+ _sieve_binary_emit_data(sblock, &byte, 1);
+
+ return address;
+}
+
+void sieve_binary_update_data(struct sieve_binary_block *sblock,
+ sieve_size_t address, const void *data,
+ sieve_size_t size)
+{
+ _sieve_binary_update_data(sblock, address, data, size);
+}
+
+/* Offset emission functions */
+
+sieve_size_t sieve_binary_emit_offset(struct sieve_binary_block *sblock,
+ sieve_offset_t offset)
+{
+ sieve_size_t address = _sieve_binary_block_get_size(sblock);
+ uint8_t encoded[sizeof(offset)];
+ int i;
+
+ for (i = sizeof(offset)-1; i >= 0; i--) {
+ encoded[i] = (uint8_t)offset;
+ offset >>= 8;
+ }
+
+ _sieve_binary_emit_data(sblock, encoded, sizeof(offset));
+
+ return address;
+}
+
+void sieve_binary_resolve_offset(struct sieve_binary_block *sblock,
+ sieve_size_t address)
+{
+ sieve_size_t cur_address = _sieve_binary_block_get_size(sblock);
+ sieve_offset_t offset;
+ uint8_t encoded[sizeof(offset)];
+ int i;
+
+ i_assert(cur_address > address);
+ i_assert((cur_address - address) <= (sieve_offset_t)-1);
+ offset = cur_address - address;
+ for (i = sizeof(offset)-1; i >= 0; i--) {
+ encoded[i] = (uint8_t)offset;
+ offset >>= 8;
+ }
+
+ _sieve_binary_update_data(sblock, address, encoded, sizeof(offset));
+}
+
+/* Literal emission */
+
+sieve_size_t sieve_binary_emit_integer(struct sieve_binary_block *sblock,
+ sieve_number_t integer)
+{
+ sieve_size_t address = _sieve_binary_block_get_size(sblock);
+ uint8_t buffer[sizeof(sieve_number_t) + 1];
+ int bufpos = sizeof(buffer) - 1;
+
+ /* Encode last byte [0xxxxxxx]; msb == 0 marks the last byte */
+ buffer[bufpos] = integer & 0x7F;
+ bufpos--;
+
+ /* Encode first bytes [1xxxxxxx] */
+ integer >>= 7;
+ while (integer > 0) {
+ buffer[bufpos] = (integer & 0x7F) | 0x80;
+ bufpos--;
+ integer >>= 7;
+ }
+
+ /* Emit encoded integer */
+ bufpos++;
+ _sieve_binary_emit_data(sblock, buffer + bufpos, sizeof(buffer) - bufpos);
+
+ return address;
+}
+
+static inline sieve_size_t
+sieve_binary_emit_dynamic_data(struct sieve_binary_block *sblock,
+ const void *data, sieve_size_t size)
+{
+ sieve_size_t address =
+ sieve_binary_emit_integer(sblock, (sieve_number_t)size);
+
+ _sieve_binary_emit_data(sblock, data, size);
+
+ return address;
+}
+
+sieve_size_t sieve_binary_emit_cstring(struct sieve_binary_block *sblock,
+ const char *str)
+{
+ sieve_size_t address =
+ sieve_binary_emit_dynamic_data(sblock, (void *)str,
+ (sieve_size_t)strlen(str));
+
+ _sieve_binary_emit_byte(sblock, 0);
+ return address;
+}
+
+sieve_size_t sieve_binary_emit_string(struct sieve_binary_block *sblock,
+ const string_t *str)
+{
+ sieve_size_t address =
+ sieve_binary_emit_dynamic_data(sblock, (void *)str_data(str),
+ (sieve_size_t)str_len(str));
+
+ _sieve_binary_emit_byte(sblock, 0);
+ return address;
+}
+
+/*
+ * Extension emission
+ */
+
+sieve_size_t sieve_binary_emit_extension(struct sieve_binary_block *sblock,
+ const struct sieve_extension *ext,
+ unsigned int offset)
+{
+ sieve_size_t address = _sieve_binary_block_get_size(sblock);
+ struct sieve_binary_extension_reg *ereg = NULL;
+
+ (void)sieve_binary_extension_register(sblock->sbin, ext, &ereg);
+
+ i_assert(ereg != NULL);
+
+ _sieve_binary_emit_byte(sblock, offset + ereg->index);
+ return address;
+}
+
+void sieve_binary_emit_extension_object(
+ struct sieve_binary_block *sblock,
+ const struct sieve_extension_objects *objs, unsigned int code)
+{
+ if (objs->count > 1)
+ _sieve_binary_emit_byte(sblock, code);
+}
+
+/*
+ * Code retrieval
+ */
+
+#define ADDR_CODE_READ(block) \
+ size_t _code_size; \
+ const int8_t *_code = buffer_get_data((block)->data, &_code_size)
+
+#define ADDR_CODE_AT(address) \
+ ((int8_t)(_code[*address]))
+#define ADDR_DATA_AT(address) \
+ ((uint8_t)(_code[*address]))
+#define ADDR_POINTER(address) \
+ ((const int8_t *)(&_code[*address]))
+
+#define ADDR_BYTES_LEFT(address) \
+ ((*address) > _code_size ? 0 : ((_code_size) - (*address)))
+#define ADDR_JUMP(address, offset) \
+ (*address) += offset
+
+/* Literals */
+
+bool sieve_binary_read_byte(struct sieve_binary_block *sblock,
+ sieve_size_t *address, unsigned int *byte_r)
+{
+ ADDR_CODE_READ(sblock);
+
+ if (ADDR_BYTES_LEFT(address) >= 1) {
+ if (byte_r != NULL)
+ *byte_r = ADDR_DATA_AT(address);
+ ADDR_JUMP(address, 1);
+
+ return TRUE;
+ }
+
+ if (byte_r != NULL)
+ *byte_r = 0;
+ return FALSE;
+}
+
+bool sieve_binary_read_code(struct sieve_binary_block *sblock,
+ sieve_size_t *address, signed int *code_r)
+{
+ ADDR_CODE_READ(sblock);
+
+ if (ADDR_BYTES_LEFT(address) >= 1) {
+ if (code_r != NULL)
+ *code_r = ADDR_CODE_AT(address);
+ ADDR_JUMP(address, 1);
+
+ return TRUE;
+ }
+
+ if (code_r != NULL)
+ *code_r = 0;
+ return FALSE;
+}
+
+
+bool sieve_binary_read_offset(struct sieve_binary_block *sblock,
+ sieve_size_t *address, sieve_offset_t *offset_r)
+{
+ sieve_offset_t offs = 0;
+ ADDR_CODE_READ(sblock);
+
+ if (ADDR_BYTES_LEFT(address) >= 4) {
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ offs = (offs << 8) + ADDR_DATA_AT(address);
+ ADDR_JUMP(address, 1);
+ }
+
+ if (offset_r != NULL)
+ *offset_r = offs;
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* FIXME: might need negative numbers in the future */
+bool sieve_binary_read_integer(struct sieve_binary_block *sblock,
+ sieve_size_t *address, sieve_number_t *int_r)
+{
+ int bits = sizeof(sieve_number_t) * 8;
+ sieve_number_t integer = 0;
+
+ ADDR_CODE_READ(sblock);
+
+ if (ADDR_BYTES_LEFT(address) == 0)
+ return FALSE;
+
+ /* Read first integer bytes [1xxxxxxx] */
+ while ((ADDR_DATA_AT(address) & 0x80) > 0) {
+ if (ADDR_BYTES_LEFT(address) > 0 && bits > 0) {
+ integer |= ADDR_DATA_AT(address) & 0x7F;
+ ADDR_JUMP(address, 1);
+
+ /* Each byte encodes 7 bits of the integer */
+ integer <<= 7;
+ bits -= 7;
+ } else {
+ /* This is an error */
+ return FALSE;
+ }
+ }
+
+ /* Read last byte [0xxxxxxx] */
+ integer |= ADDR_DATA_AT(address) & 0x7F;
+ ADDR_JUMP(address, 1);
+
+ if (int_r != NULL)
+ *int_r = integer;
+ return TRUE;
+}
+
+bool sieve_binary_read_string(struct sieve_binary_block *sblock,
+ sieve_size_t *address, string_t **str_r)
+{
+ unsigned int strlen = 0;
+ const char *strdata;
+
+ ADDR_CODE_READ(sblock);
+
+ if (!sieve_binary_read_unsigned(sblock, address, &strlen))
+ return FALSE;
+
+ if (strlen > ADDR_BYTES_LEFT(address))
+ return FALSE;
+
+ strdata = (const char *)ADDR_POINTER(address);
+ ADDR_JUMP(address, strlen);
+
+ if (ADDR_CODE_AT(address) != 0)
+ return FALSE;
+
+ if (str_r != NULL)
+ *str_r = t_str_new_const(strdata, strlen);
+
+ ADDR_JUMP(address, 1);
+
+ return TRUE;
+}
+
+bool sieve_binary_read_extension(struct sieve_binary_block *sblock,
+ sieve_size_t *address, unsigned int *offset_r,
+ const struct sieve_extension **ext_r)
+{
+ unsigned int code;
+ unsigned int offset = *offset_r;
+ const struct sieve_extension *ext = NULL;
+
+ ADDR_CODE_READ(sblock);
+
+ if (ADDR_BYTES_LEFT(address) == 0)
+ return FALSE;
+
+ *offset_r = code = ADDR_DATA_AT(address);
+ ADDR_JUMP(address, 1);
+
+ if (code >= offset) {
+ ext = sieve_binary_extension_get_by_index(sblock->sbin,
+ (code - offset));
+ if (ext == NULL)
+ return FALSE;
+ }
+
+ if (ext_r != NULL)
+ *ext_r = ext;
+ return TRUE;
+}
+
+const void *
+sieve_binary_read_extension_object(struct sieve_binary_block *sblock,
+ sieve_size_t *address,
+ const struct sieve_extension_objects *objs)
+{
+ unsigned int code;
+
+ ADDR_CODE_READ(sblock);
+
+ if (objs->count == 0)
+ return NULL;
+ if (objs->count == 1)
+ return objs->objects;
+ if (ADDR_BYTES_LEFT(address) == 0)
+ return NULL;
+
+ code = ADDR_DATA_AT(address);
+ ADDR_JUMP(address, 1);
+
+ if (code >= objs->count)
+ return NULL;
+ return ((const void *const *)objs->objects)[code];
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-binary-debug.c b/pigeonhole/src/lib-sieve/sieve-binary-debug.c
new file mode 100644
index 0000000..5e8b13a
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-binary-debug.c
@@ -0,0 +1,276 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-code.h"
+
+#include "sieve-binary-private.h"
+
+/* Quick 'n dirty debug */
+#if 0
+#define debug_printf(...) printf ("lineinfo: " __VA_ARGS__)
+#else
+#define debug_printf(...)
+#endif
+
+/*
+ * Opcodes
+ */
+
+enum {
+ LINPROG_OP_COPY,
+ LINPROG_OP_ADVANCE_PC,
+ LINPROG_OP_ADVANCE_LINE,
+ LINPROG_OP_SET_COLUMN,
+ LINPROG_OP_SPECIAL_BASE
+};
+
+#define LINPROG_LINE_BASE 0
+#define LINPROG_LINE_RANGE 4
+
+/*
+ * Lineinfo writer
+ */
+
+struct sieve_binary_debug_writer {
+ struct sieve_binary_block *sblock;
+
+ sieve_size_t address;
+ unsigned int line;
+ unsigned int column;
+};
+
+struct sieve_binary_debug_writer *
+sieve_binary_debug_writer_init(struct sieve_binary_block *sblock)
+{
+ struct sieve_binary_debug_writer *dwriter;
+
+ dwriter = i_new(struct sieve_binary_debug_writer, 1);
+ dwriter->sblock = sblock;
+
+ return dwriter;
+}
+
+void sieve_binary_debug_writer_deinit(
+ struct sieve_binary_debug_writer **dwriter)
+{
+ i_free(*dwriter);
+ *dwriter = NULL;
+}
+
+void sieve_binary_debug_emit(struct sieve_binary_debug_writer *dwriter,
+ sieve_size_t code_address, unsigned int code_line,
+ unsigned int code_column)
+{
+ i_assert(code_address >= dwriter->address);
+
+ struct sieve_binary_block *sblock = dwriter->sblock;
+ sieve_size_t address_inc = code_address - dwriter->address;
+ int line_inc = (code_line > dwriter->line ?
+ (int)(code_line - dwriter->line) :
+ -(int)(dwriter->line - code_line));
+ unsigned int sp_opcode = 0;
+
+ /* Check for applicability of special opcode */
+ if (line_inc > 0 &&
+ (LINPROG_LINE_BASE + LINPROG_LINE_RANGE - 1) >= line_inc) {
+ sp_opcode = LINPROG_OP_SPECIAL_BASE +
+ (line_inc - LINPROG_LINE_BASE) +
+ (LINPROG_LINE_RANGE * address_inc);
+
+ if (sp_opcode > 255)
+ sp_opcode = 0;
+ }
+
+ /* Update line and address */
+ if (sp_opcode == 0) {
+ if (line_inc != 0) {
+ (void)sieve_binary_emit_byte(sblock,
+ LINPROG_OP_ADVANCE_LINE);
+ (void)sieve_binary_emit_unsigned(
+ sblock, (unsigned int)line_inc);
+ }
+
+ if (address_inc > 0) {
+ (void)sieve_binary_emit_byte(sblock,
+ LINPROG_OP_ADVANCE_PC);
+ (void)sieve_binary_emit_unsigned(sblock, address_inc);
+ }
+ } else {
+ (void)sieve_binary_emit_byte(sblock, sp_opcode);
+ }
+
+ /* Set column */
+ if (dwriter->column != code_column) {
+ (void)sieve_binary_emit_byte(sblock, LINPROG_OP_SET_COLUMN);
+ (void)sieve_binary_emit_unsigned(sblock, code_column);
+ }
+
+ /* Generate matrix row */
+ (void)sieve_binary_emit_byte(sblock, LINPROG_OP_COPY);
+
+ dwriter->address = code_address;
+ dwriter->line = code_line;
+ dwriter->column = code_column;
+}
+
+/*
+ * Debug reader
+ */
+
+struct sieve_binary_debug_reader {
+ struct sieve_binary_block *sblock;
+
+ sieve_size_t address, last_address;
+ unsigned int line, last_line;
+
+ unsigned int column;
+
+ sieve_size_t state;
+};
+
+struct sieve_binary_debug_reader *
+sieve_binary_debug_reader_init(struct sieve_binary_block *sblock)
+{
+ struct sieve_binary_debug_reader *dreader;
+
+ dreader = i_new(struct sieve_binary_debug_reader, 1);
+ dreader->sblock = sblock;
+
+ return dreader;
+}
+
+void sieve_binary_debug_reader_deinit(
+ struct sieve_binary_debug_reader **dreader)
+{
+ i_free(*dreader);
+ *dreader = NULL;
+}
+
+void sieve_binary_debug_reader_reset(struct sieve_binary_debug_reader *dreader)
+{
+ dreader->address = 0;
+ dreader->line = 0;
+ dreader->column = 0;
+ dreader->state = 0;
+}
+
+unsigned int
+sieve_binary_debug_read_line(struct sieve_binary_debug_reader *dreader,
+ sieve_size_t code_address)
+{
+ size_t linprog_size;
+ sieve_size_t address;
+ unsigned int line;
+
+ if (code_address < dreader->last_address)
+ sieve_binary_debug_reader_reset(dreader);
+
+ if (code_address >= dreader->last_address &&
+ code_address < dreader->address) {
+ debug_printf("%08llx: NOOP [%08llx]\n",
+ (unsigned long long)dreader->state,
+ (unsigned long long)code_address);
+ return dreader->last_line;
+ }
+
+ address = dreader->address;
+ line = dreader->line;
+
+ debug_printf("%08llx: READ [%08llx]\n",
+ (unsigned long long)dreader->state,
+ (unsigned long long)code_address);
+
+ linprog_size = sieve_binary_block_get_size(dreader->sblock);
+ while (dreader->state < linprog_size) {
+ unsigned int opcode;
+ unsigned int value;
+ int line_inc;
+
+ if (sieve_binary_read_byte(dreader->sblock,
+ &dreader->state, &opcode)) {
+ switch (opcode) {
+ case LINPROG_OP_COPY:
+ debug_printf("%08llx: COPY ==> %08llx: %ld\n",
+ (unsigned long long)dreader->state,
+ (unsigned long long)address, line);
+
+ dreader->last_address = dreader->address;
+ dreader->last_line = dreader->line;
+
+ dreader->address = address;
+ dreader->line = line;
+
+ if (code_address < address)
+ return dreader->last_line;
+ else if (code_address == address)
+ return dreader->line;
+ break;
+ case LINPROG_OP_ADVANCE_PC:
+ debug_printf("%08llx: ADV_PC\n",
+ (unsigned long long)dreader->state);
+ if (!sieve_binary_read_unsigned(
+ dreader->sblock, &dreader->state,
+ &value)) {
+ sieve_binary_debug_reader_reset(dreader);
+ return 0;
+ }
+ debug_printf(" : + %d\n", value);
+ address += value;
+ break;
+ case LINPROG_OP_ADVANCE_LINE:
+ debug_printf("%08llx: ADV_LINE\n",
+ (unsigned long long)dreader->state);
+ if (!sieve_binary_read_unsigned(
+ dreader->sblock, &dreader->state,
+ &value)) {
+ sieve_binary_debug_reader_reset(dreader);
+ return 0;
+ }
+ line_inc = (int)value;
+ debug_printf(" : + %d\n", line_inc);
+ line = (line_inc > 0 ?
+ line + (unsigned int)line_inc :
+ line - (unsigned int)-line_inc);
+ break;
+ case LINPROG_OP_SET_COLUMN:
+ debug_printf("%08llx: SET_COL\n",
+ (unsigned long long)dreader->state);
+ if (!sieve_binary_read_unsigned(
+ dreader->sblock, &dreader->state,
+ &value)) {
+ sieve_binary_debug_reader_reset(dreader);
+ return 0;
+ }
+ debug_printf(" : = %d\n", value);
+ dreader->column = value;
+ break;
+ default:
+ opcode -= LINPROG_OP_SPECIAL_BASE;
+
+ address += (opcode / LINPROG_LINE_RANGE);
+ line += LINPROG_LINE_BASE +
+ (opcode % LINPROG_LINE_RANGE);
+
+ debug_printf("%08llx: SPECIAL\n",
+ (unsigned long long)dreader->state);
+ debug_printf(" : +A %d +L %d\n",
+ (opcode / LINPROG_LINE_RANGE),
+ LINPROG_LINE_BASE +
+ (opcode % LINPROG_LINE_RANGE));
+ break;
+ }
+ } else {
+ debug_printf("OPCODE READ FAILED\n");
+ sieve_binary_debug_reader_reset(dreader);
+ return 0;
+ }
+ }
+
+ return dreader->line;
+}
+
diff --git a/pigeonhole/src/lib-sieve/sieve-binary-dumper.c b/pigeonhole/src/lib-sieve/sieve-binary-dumper.c
new file mode 100644
index 0000000..3b3bb4b
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-binary-dumper.c
@@ -0,0 +1,326 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "ostream.h"
+#include "array.h"
+#include "buffer.h"
+#include "time-util.h"
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+#include "sieve-dump.h"
+#include "sieve-script.h"
+
+#include "sieve-binary-private.h"
+
+/*
+ * Binary dumper object
+ */
+
+struct sieve_binary_dumper {
+ pool_t pool;
+
+ /* Dumptime environment */
+ struct sieve_dumptime_env dumpenv;
+};
+
+struct sieve_binary_dumper *
+sieve_binary_dumper_create(struct sieve_binary *sbin)
+{
+ pool_t pool;
+ struct sieve_binary_dumper *dumper;
+
+ pool = pool_alloconly_create("sieve_binary_dumper", 4096);
+ dumper = p_new(pool, struct sieve_binary_dumper, 1);
+ dumper->pool = pool;
+ dumper->dumpenv.dumper = dumper;
+
+ dumper->dumpenv.sbin = sbin;
+ sieve_binary_ref(sbin);
+
+ dumper->dumpenv.svinst = sieve_binary_svinst(sbin);
+
+ return dumper;
+}
+
+void sieve_binary_dumper_free(struct sieve_binary_dumper **dumper)
+{
+ sieve_binary_unref(&(*dumper)->dumpenv.sbin);
+ pool_unref(&((*dumper)->pool));
+
+ *dumper = NULL;
+}
+
+pool_t sieve_binary_dumper_pool(struct sieve_binary_dumper *dumper)
+{
+ return dumper->pool;
+}
+
+/*
+ * Formatted output
+ */
+
+void sieve_binary_dumpf(const struct sieve_dumptime_env *denv,
+ const char *fmt, ...)
+{
+ string_t *outbuf = t_str_new(128);
+ va_list args;
+
+ va_start(args, fmt);
+ str_vprintfa(outbuf, fmt, args);
+ va_end(args);
+
+ o_stream_nsend(denv->stream, str_data(outbuf), str_len(outbuf));
+}
+
+void sieve_binary_dump_sectionf(const struct sieve_dumptime_env *denv,
+ const char *fmt, ...)
+{
+ string_t *outbuf = t_str_new(128);
+ va_list args;
+
+ va_start(args, fmt);
+ str_printfa(outbuf, "\n* ");
+ str_vprintfa(outbuf, fmt, args);
+ str_printfa(outbuf, ":\n\n");
+ va_end(args);
+
+ o_stream_nsend(denv->stream, str_data(outbuf), str_len(outbuf));
+}
+
+/*
+ * Dumping the binary
+ */
+
+bool sieve_binary_dumper_run(struct sieve_binary_dumper *dumper,
+ struct ostream *stream, bool verbose)
+{
+ struct sieve_binary *sbin = dumper->dumpenv.sbin;
+ struct sieve_script *script = sieve_binary_script(sbin);
+ struct sieve_dumptime_env *denv = &(dumper->dumpenv);
+ const struct sieve_binary_header *header = &sbin->header;
+ struct sieve_binary_block *sblock;
+ bool success = TRUE;
+ sieve_size_t offset;
+ int count, i;
+
+ dumper->dumpenv.stream = stream;
+
+ /* Dump header */
+
+ sieve_binary_dump_sectionf(denv, "Header");
+
+ sieve_binary_dumpf(denv,
+ "version = %"PRIu16".%"PRIu16"\n"
+ "flags = 0x%08"PRIx32"\n",
+ header->version_major, header->version_minor,
+ header->flags);
+ if (header->resource_usage.update_time != 0) {
+ time_t update_time =
+ (time_t)header->resource_usage.update_time;
+ sieve_binary_dumpf(denv,
+ "resource usage:\n"
+ " update time = %s\n"
+ " cpu time = %"PRIu32" ms\n",
+ t_strflocaltime("%Y-%m-%d %H:%M:%S",
+ update_time),
+ header->resource_usage.cpu_time_msecs);
+ }
+
+ /* Dump list of binary blocks */
+
+ if (verbose) {
+ count = sieve_binary_block_count(sbin);
+
+ sieve_binary_dump_sectionf(denv, "Binary blocks (count: %d)",
+ count);
+
+ for (i = 0; i < count; i++) {
+ struct sieve_binary_block *sblock =
+ sieve_binary_block_get(sbin, i);
+
+ sieve_binary_dumpf(
+ denv, "%3d: size: %zu bytes\n",
+ i, sieve_binary_block_get_size(sblock));
+ }
+ }
+
+ /* Dump script metadata */
+
+ sieve_binary_dump_sectionf(denv, "Script metadata (block: %d)",
+ SBIN_SYSBLOCK_SCRIPT_DATA);
+ sblock = sieve_binary_block_get(sbin, SBIN_SYSBLOCK_SCRIPT_DATA);
+
+ T_BEGIN {
+ offset = 0;
+ success = sieve_script_binary_dump_metadata(
+ script, denv, sblock, &offset);
+ } T_END;
+
+ if (!success)
+ return FALSE;
+
+ /* Dump list of used extensions */
+
+ count = sieve_binary_extensions_count(sbin);
+ if (count > 0) {
+ sieve_binary_dump_sectionf(
+ denv, "Required extensions (block: %d)",
+ SBIN_SYSBLOCK_EXTENSIONS);
+
+ for (i = 0; i < count; i++) {
+ const struct sieve_extension *ext =
+ sieve_binary_extension_get_by_index(sbin, i);
+
+ sblock = sieve_binary_extension_get_block(sbin, ext);
+
+ if (sblock == NULL) {
+ sieve_binary_dumpf(
+ denv, "%3d: %s (id: %d)\n",
+ i, sieve_extension_name(ext), ext->id);
+ } else {
+ sieve_binary_dumpf(
+ denv, "%3d: %s (id: %d; block: %d)\n",
+ i, sieve_extension_name(ext), ext->id,
+ sieve_binary_block_get_id(sblock));
+ }
+ }
+ }
+
+ /* Dump extension-specific elements of the binary */
+
+ count = sieve_binary_extensions_count(sbin);
+ if (count > 0) {
+ for (i = 0; i < count; i++) {
+ success = TRUE;
+
+ T_BEGIN {
+ const struct sieve_extension *ext =
+ sieve_binary_extension_get_by_index(
+ sbin, i);
+
+ if (ext->def != NULL &&
+ ext->def->binary_dump != NULL) {
+ success = ext->def->binary_dump(
+ ext, denv);
+ }
+ } T_END;
+
+ if (!success)
+ return FALSE;
+ }
+ }
+
+ /* Dump main program */
+
+ sieve_binary_dump_sectionf(denv, "Main program (block: %d)",
+ SBIN_SYSBLOCK_MAIN_PROGRAM);
+
+ dumper->dumpenv.sblock =
+ sieve_binary_block_get(sbin, SBIN_SYSBLOCK_MAIN_PROGRAM);
+ dumper->dumpenv.cdumper = sieve_code_dumper_create(&(dumper->dumpenv));
+
+ if (dumper->dumpenv.cdumper != NULL) {
+ sieve_code_dumper_run(dumper->dumpenv.cdumper);
+
+ sieve_code_dumper_free(&dumper->dumpenv.cdumper);
+ }
+
+ /* Finish with empty line */
+ sieve_binary_dumpf(denv, "\n");
+
+ return TRUE;
+}
+
+/*
+ * Hexdump production
+ */
+
+void sieve_binary_dumper_hexdump(struct sieve_binary_dumper *dumper,
+ struct ostream *stream)
+{
+ struct sieve_binary *sbin = dumper->dumpenv.sbin;
+ struct sieve_dumptime_env *denv = &(dumper->dumpenv);
+ int count, i;
+
+ dumper->dumpenv.stream = stream;
+
+ count = sieve_binary_block_count(sbin);
+
+ /* Block overview */
+
+ sieve_binary_dump_sectionf(denv, "Binary blocks (count: %d)", count);
+
+ for (i = 0; i < count; i++) {
+ struct sieve_binary_block *sblock =
+ sieve_binary_block_get(sbin, i);
+
+ sieve_binary_dumpf(denv, "%3d: size: %zu bytes\n",
+ i, sieve_binary_block_get_size(sblock));
+ }
+
+ /* Hexdump for each block */
+
+ for (i = 0; i < count; i++) {
+ struct sieve_binary_block *sblock =
+ sieve_binary_block_get(sbin, i);
+ buffer_t *blockbuf = sieve_binary_block_get_buffer(sblock);
+ string_t *line;
+ size_t data_size;
+ const unsigned char *data;
+ size_t offset;
+
+ data = buffer_get_data(blockbuf, &data_size);
+
+ // FIXME: calculate offset more nicely.
+ sieve_binary_dump_sectionf(
+ denv, "Block %d (%zu bytes, file offset %08llx)", i, data_size,
+ (unsigned long long int)sblock->offset + 8);
+
+ line = t_str_new(128);
+ offset = 0;
+ while (offset < data_size) {
+ size_t len = (data_size - offset >= 16 ?
+ 16 : data_size - offset);
+ size_t b;
+
+ str_printfa(line, "%08llx ",
+ (unsigned long long)offset);
+
+ for (b = 0; b < len; b++) {
+ str_printfa(line, "%02x ", data[offset+b]);
+ if (b == 7)
+ str_append_c(line, ' ');
+ }
+
+ if (len < 16) {
+ if (len <= 7)
+ str_append_c(line, ' ');
+
+ for (b = len; b < 16; b++)
+ str_append(line, " ");
+ }
+
+ str_append(line, " |");
+
+ for (b = 0; b < len; b++) {
+ const unsigned char c = data[offset+b];
+
+ if (c >= 32 && c <= 126)
+ str_append_c(line, (const char)c);
+ else
+ str_append_c(line, '.');
+ }
+
+ str_append(line, "|\n");
+ o_stream_nsend(stream, str_data(line), str_len(line));
+ str_truncate(line, 0);
+ offset += len;
+ }
+
+ str_printfa(line, "%08llx\n", (unsigned long long)offset);
+ o_stream_nsend(stream, str_data(line), str_len(line));
+ }
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-binary-dumper.h b/pigeonhole/src/lib-sieve/sieve-binary-dumper.h
new file mode 100644
index 0000000..4343190
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-binary-dumper.h
@@ -0,0 +1,41 @@
+#ifndef SIEVE_BINARY_DUMPER_H
+#define SIEVE_BINARY_DUMPER_H
+
+#include "sieve-common.h"
+
+/*
+ * Binary dumper object
+ */
+
+struct sieve_binary_dumper;
+
+struct sieve_binary_dumper *
+sieve_binary_dumper_create(struct sieve_binary *sbin);
+void sieve_binary_dumper_free(struct sieve_binary_dumper **dumper);
+
+pool_t sieve_binary_dumper_pool(struct sieve_binary_dumper *dumper);
+
+/*
+ * Formatted output
+ */
+
+void sieve_binary_dumpf(const struct sieve_dumptime_env *denv,
+ const char *fmt, ...) ATTR_FORMAT(2, 3);
+void sieve_binary_dump_sectionf(const struct sieve_dumptime_env *denv,
+ const char *fmt, ...) ATTR_FORMAT(2, 3);
+
+/*
+ * Dumping the binary
+ */
+
+bool sieve_binary_dumper_run(struct sieve_binary_dumper *dumper,
+ struct ostream *stream, bool verbose);
+
+/*
+ * Hexdump production
+ */
+
+void sieve_binary_dumper_hexdump(struct sieve_binary_dumper *dumper,
+ struct ostream *stream);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-binary-file.c b/pigeonhole/src/lib-sieve/sieve-binary-file.c
new file mode 100644
index 0000000..8eedbc2
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-binary-file.c
@@ -0,0 +1,1042 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "mempool.h"
+#include "buffer.h"
+#include "hash.h"
+#include "array.h"
+#include "ostream.h"
+#include "eacces-error.h"
+#include "safe-mkstemp.h"
+#include "file-lock.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-extensions.h"
+#include "sieve-code.h"
+#include "sieve-script.h"
+
+#include "sieve-binary-private.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/*
+ * Macros
+ */
+
+#define SIEVE_BINARY_MAGIC 0xcafebabe
+#define SIEVE_BINARY_MAGIC_OTHER_ENDIAN 0xbebafeca
+
+#define SIEVE_BINARY_ALIGN(offset) \
+ (((offset) + 3) & ~3U)
+#define SIEVE_BINARY_ALIGN_PTR(ptr) \
+ ((void *) SIEVE_BINARY_ALIGN(((size_t) ptr)))
+
+#define SIEVE_BINARY_PRE_HDR_SIZE_MAJOR 1
+#define SIEVE_BINARY_PRE_HDR_SIZE_MINOR 4
+#define SIEVE_BINARY_PRE_HDR_SIZE_HDR_SIZE 12
+
+/*
+ * Header and record structures of the binary on disk
+ */
+
+struct sieve_binary_block_index {
+ uint32_t id;
+ uint32_t size;
+ uint32_t offset;
+ uint32_t ext_id;
+};
+
+struct sieve_binary_block_header {
+ uint32_t id;
+ uint32_t size;
+};
+
+/*
+ * Header manipulation
+ */
+
+static int
+sieve_binary_file_read_header(struct sieve_binary *sbin, int fd,
+ struct sieve_binary_header *header_r,
+ enum sieve_error *error_r)
+{
+ struct sieve_binary_header header;
+ enum sieve_error error;
+ ssize_t rret;
+
+ if (error_r == NULL)
+ error_r = &error;
+ *error_r = SIEVE_ERROR_NONE;
+
+ rret = pread(fd, &header, sizeof(header), 0);
+ if (rret == 0) {
+ e_error(sbin->event, "read: "
+ "file is not large enough to contain the header");
+ *error_r = SIEVE_ERROR_NOT_VALID;
+ return -1;
+ } else if (rret < 0) {
+ e_error(sbin->event, "read: "
+ "failed to read from binary: %m");
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ } else if (rret != sizeof(header)) {
+ e_error(sbin->event, "read: "
+ "header read only partially %zd/%zu",
+ rret, sizeof(header));
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+
+ /* Check header validity */
+ if (header.magic != SIEVE_BINARY_MAGIC) {
+ if (header.magic != SIEVE_BINARY_MAGIC_OTHER_ENDIAN) {
+ e_error(sbin->event, "read: "
+ "binary has corrupted header "
+ "(0x%08x) or it is not a Sieve binary",
+ header.magic);
+ } else {
+ e_error(sbin->event, "read: "
+ "binary stored with in different endian format "
+ "(automatically fixed when re-compiled)");
+ }
+ *error_r = SIEVE_ERROR_NOT_VALID;
+ return -1;
+ }
+ /* Check binary version */
+ if (header.version_major == SIEVE_BINARY_PRE_HDR_SIZE_MAJOR &&
+ header.version_minor == SIEVE_BINARY_PRE_HDR_SIZE_MINOR) {
+ /* Old header without hdr_size; clear new fields */
+ static const size_t old_header_size =
+ SIEVE_BINARY_PRE_HDR_SIZE_HDR_SIZE;
+ memset(PTR_OFFSET(&header, old_header_size), 0,
+ (sizeof(header) - old_header_size));
+ header.hdr_size = old_header_size;
+ } else if (header.version_major != SIEVE_BINARY_VERSION_MAJOR) {
+ /* Binary is of different major version. Caller will have to
+ recompile */
+ e_error(sbin->event, "read: "
+ "binary stored with different major version %d.%d "
+ "(!= %d.%d; automatically fixed when re-compiled)",
+ (int)header.version_major, (int)header.version_minor,
+ SIEVE_BINARY_VERSION_MAJOR, SIEVE_BINARY_VERSION_MINOR);
+ *error_r = SIEVE_ERROR_NOT_VALID;
+ return -1;
+ } else if (header.hdr_size < SIEVE_BINARY_BASE_HEADER_SIZE) {
+ /* Header size is smaller than base size */
+ e_error(sbin->event, "read: "
+ "binary is corrupt: header size is too small");
+ *error_r = SIEVE_ERROR_NOT_VALID;
+ return -1;
+ }
+ /* Check block content */
+ if (header.blocks == 0) {
+ e_error(sbin->event, "read: "
+ "binary is corrupt: it contains no blocks");
+ *error_r = SIEVE_ERROR_NOT_VALID;
+ return -1;
+ }
+ /* Valid */
+ *header_r = header;
+ return 0;
+}
+
+static int
+sieve_binary_file_write_header(struct sieve_binary *sbin, int fd,
+ struct sieve_binary_header *header,
+ enum sieve_error *error_r) ATTR_NULL(4)
+{
+ ssize_t wret;
+
+ wret = pwrite(fd, header, sizeof(*header), 0);
+ if (wret < 0) {
+ e_error(sbin->event, "update: "
+ "failed to write to binary: %m");
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ } else if (wret != sizeof(*header)) {
+ e_error(sbin->event, "update: "
+ "header written partially %zd/%zu",
+ wret, sizeof(*header));
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+ return 0;
+}
+
+static void sieve_binary_file_update_header(struct sieve_binary *sbin)
+{
+ struct sieve_binary_header *header = &sbin->header;
+ struct sieve_resource_usage rusage;
+
+ sieve_binary_get_resource_usage(sbin, &rusage);
+
+ i_zero(&header->resource_usage);
+ if (HAS_ALL_BITS(header->flags, SIEVE_BINARY_FLAG_RESOURCE_LIMIT) ||
+ sieve_resource_usage_is_high(sbin->svinst, &rusage)) {
+ header->resource_usage.update_time = ioloop_time;
+ header->resource_usage.cpu_time_msecs = rusage.cpu_time_msecs;
+ }
+
+ sieve_resource_usage_init(&sbin->rusage);
+ sbin->rusage_updated = FALSE;
+
+ (void)sieve_binary_check_resource_usage(sbin);
+}
+
+/*
+ * Saving the binary to a file.
+ */
+
+static inline bool
+_save_skip(struct sieve_binary *sbin, struct ostream *stream, size_t size)
+{
+ if ((o_stream_seek(stream, stream->offset + size)) <= 0) {
+ e_error(sbin->event, "save: "
+ "failed to skip output stream to position "
+ "%"PRIuUOFF_T": %s", stream->offset + size,
+ strerror(stream->stream_errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static inline bool
+_save_skip_aligned(struct sieve_binary *sbin, struct ostream *stream,
+ size_t size, uoff_t *offset)
+{
+ uoff_t aligned_offset = SIEVE_BINARY_ALIGN(stream->offset);
+
+ if ((o_stream_seek(stream, aligned_offset + size)) <= 0) {
+ e_error(sbin->event, "save: "
+ "failed to skip output stream to position "
+ "%"PRIuUOFF_T": %s", aligned_offset + size,
+ strerror(stream->stream_errno));
+ return FALSE;
+ }
+
+ if (offset != NULL)
+ *offset = aligned_offset;
+ return TRUE;
+}
+
+/* FIXME: Is this even necessary for a file? */
+static bool
+_save_full(struct sieve_binary *sbin, struct ostream *stream,
+ const void *data, size_t size)
+{
+ size_t bytes_left = size;
+ const void *pdata = data;
+
+ while (bytes_left > 0) {
+ ssize_t ret;
+
+ ret = o_stream_send(stream, pdata, bytes_left);
+ if (ret <= 0) {
+ e_error(sbin->event, "save: "
+ "failed to write %zu bytes "
+ "to output stream: %s", bytes_left,
+ strerror(stream->stream_errno));
+ return FALSE;
+ }
+
+ pdata = PTR_OFFSET(pdata, ret);
+ bytes_left -= ret;
+ }
+
+ return TRUE;
+}
+
+static bool
+_save_aligned(struct sieve_binary *sbin, struct ostream *stream,
+ const void *data, size_t size, uoff_t *offset)
+{
+ uoff_t aligned_offset = SIEVE_BINARY_ALIGN(stream->offset);
+
+ o_stream_cork(stream);
+
+ /* Align the data by adding zeroes to the output stream */
+ if (stream->offset < aligned_offset) {
+ if (!_save_skip(sbin, stream,
+ (aligned_offset - stream->offset)))
+ return FALSE;
+ }
+
+ if (!_save_full(sbin, stream, data, size))
+ return FALSE;
+
+ o_stream_uncork(stream);
+
+ if (offset != NULL)
+ *offset = aligned_offset;
+ return TRUE;
+}
+
+static bool
+_save_block(struct sieve_binary *sbin, struct ostream *stream, unsigned int id)
+{
+ struct sieve_binary_block_header block_header;
+ struct sieve_binary_block *block;
+ const void *data;
+ size_t size;
+
+ block = sieve_binary_block_get(sbin, id);
+ if (block == NULL)
+ return FALSE;
+
+ data = buffer_get_data(block->data, &size);
+
+ block_header.id = id;
+ block_header.size = size;
+
+ if (!_save_aligned(sbin, stream, &block_header, sizeof(block_header),
+ &block->offset))
+ return FALSE;
+
+ return _save_aligned(sbin, stream, data, size, NULL);
+}
+
+static bool
+_save_block_index_record(struct sieve_binary *sbin, struct ostream *stream,
+ unsigned int id)
+{
+ struct sieve_binary_block *block;
+ struct sieve_binary_block_index header;
+
+ block = sieve_binary_block_get(sbin, id);
+ if (block == NULL)
+ return FALSE;
+
+ header.id = id;
+ header.size = buffer_get_used_size(block->data);
+ header.ext_id = block->ext_index;
+ header.offset = block->offset;
+
+ if (!_save_full(sbin, stream, &header, sizeof(header))) {
+ e_error(sbin->event, "save: "
+ "failed to save block index header %d", id);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool
+sieve_binary_save_to_stream(struct sieve_binary *sbin, struct ostream *stream)
+{
+ struct sieve_binary_header *header = &sbin->header;
+ struct sieve_binary_block *ext_block;
+ unsigned int ext_count, blk_count, i;
+ uoff_t block_index;
+
+ blk_count = sieve_binary_block_count(sbin);
+
+ /* Create header */
+
+ header->magic = SIEVE_BINARY_MAGIC;
+ header->version_major = SIEVE_BINARY_VERSION_MAJOR;
+ header->version_minor = SIEVE_BINARY_VERSION_MINOR;
+ header->blocks = blk_count;
+ header->hdr_size = sizeof(*header);
+
+ header->flags &= ENUM_NEGATE(SIEVE_BINARY_FLAG_RESOURCE_LIMIT);
+ sieve_binary_file_update_header(sbin);
+
+ if (!_save_aligned(sbin, stream, header, sizeof(*header), NULL)) {
+ e_error(sbin->event, "save: failed to save header");
+ return FALSE;
+ }
+
+ /* Skip block index for now */
+
+ if (!_save_skip_aligned(
+ sbin, stream,
+ (sizeof(struct sieve_binary_block_index) * blk_count),
+ &block_index))
+ return FALSE;
+
+ /* Create block containing all used extensions */
+
+ ext_block = sieve_binary_block_get(sbin, SBIN_SYSBLOCK_EXTENSIONS);
+ i_assert(ext_block != NULL);
+ sieve_binary_block_clear(ext_block);
+
+ ext_count = array_count(&sbin->linked_extensions);
+ sieve_binary_emit_unsigned(ext_block, ext_count);
+
+ for (i = 0; i < ext_count; i++) {
+ struct sieve_binary_extension_reg * const *ext =
+ array_idx(&sbin->linked_extensions, i);
+
+ sieve_binary_emit_cstring(
+ ext_block, sieve_extension_name((*ext)->extension));
+ sieve_binary_emit_unsigned(
+ ext_block, sieve_extension_version((*ext)->extension));
+ sieve_binary_emit_unsigned(ext_block, (*ext)->block_id);
+ }
+
+ /* Save all blocks into the binary */
+
+ for (i = 0; i < blk_count; i++) {
+ if (!_save_block(sbin, stream, i))
+ return FALSE;
+ }
+
+ /* Create the block index */
+ o_stream_seek(stream, block_index);
+ for (i = 0; i < blk_count; i++) {
+ if (!_save_block_index_record(sbin, stream, i))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int
+sieve_binary_do_save(struct sieve_binary *sbin, const char *path, bool update,
+ mode_t save_mode, enum sieve_error *error_r)
+{
+ int result, fd;
+ string_t *temp_path;
+ struct ostream *stream;
+ struct sieve_binary_extension_reg *const *regs;
+ unsigned int ext_count, i;
+
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NONE;
+
+ /* Check whether saving is necessary */
+ if (!update && sbin->path != NULL && strcmp(sbin->path, path) == 0) {
+ e_debug(sbin->event, "save: "
+ "not saving binary, because it is already stored");
+ return 0;
+ }
+
+ /* Open it as temp file first, as not to overwrite an existing just yet */
+ temp_path = t_str_new(256);
+ str_append(temp_path, path);
+ str_append_c(temp_path, '.');
+ fd = safe_mkstemp_hostpid(temp_path, save_mode, (uid_t)-1, (gid_t)-1);
+ if (fd < 0) {
+ if (errno == EACCES) {
+ e_error(sbin->event, "save: "
+ "failed to create temporary file: %s",
+ eacces_error_get_creating("open",
+ str_c(temp_path)));
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NO_PERMISSION;
+ } else {
+ e_error(sbin->event, "save: "
+ "failed to create temporary file: "
+ "open(%s) failed: %m", str_c(temp_path));
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ }
+ return -1;
+ }
+
+ /* Signal all extensions that we're about to save the binary */
+ regs = array_get(&sbin->extensions, &ext_count);
+ for (i = 0; i < ext_count; i++) {
+ const struct sieve_binary_extension *binext = regs[i]->binext;
+
+ if (binext != NULL && binext->binary_pre_save != NULL &&
+ !binext->binary_pre_save(regs[i]->extension, sbin,
+ regs[i]->context, error_r))
+ return -1;
+ }
+
+ /* Save binary */
+ result = 1;
+ stream = o_stream_create_fd(fd, 0);
+ if (!sieve_binary_save_to_stream(sbin, stream)) {
+ result = -1;
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ }
+ o_stream_destroy(&stream);
+
+ /* Close saved binary */
+ if (close(fd) < 0) {
+ e_error(sbin->event, "save: "
+ "failed to close temporary file: "
+ "close(fd=%s) failed: %m", str_c(temp_path));
+ }
+
+ /* Replace any original binary atomically */
+ if (result > 0 && (rename(str_c(temp_path), path) < 0)) {
+ if (errno == EACCES) {
+ e_error(sbin->event, "save: "
+ "failed to save binary: %s",
+ eacces_error_get_creating("rename", path));
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NO_PERMISSION;
+ } else {
+ e_error(sbin->event, "save: "
+ "failed to save binary: "
+ "rename(%s, %s) failed: %m",
+ str_c(temp_path), path);
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ }
+ result = -1;
+ }
+
+ if (result < 0) {
+ /* Get rid of temp output (if any) */
+ if (unlink(str_c(temp_path)) < 0 && errno != ENOENT) {
+ e_error(sbin->event, "save: "
+ "failed to clean up after error: "
+ "unlink(%s) failed: %m", str_c(temp_path));
+ }
+ } else {
+ if (sbin->path == NULL)
+ sbin->path = p_strdup(sbin->pool, path);
+
+ /* Signal all extensions that we successfully saved the binary.
+ */
+ regs = array_get(&sbin->extensions, &ext_count);
+ for (i = 0; i < ext_count; i++) {
+ const struct sieve_binary_extension *binext =
+ regs[i]->binext;
+
+ if (binext != NULL &&
+ binext->binary_post_save != NULL &&
+ !binext->binary_post_save(regs[i]->extension, sbin,
+ regs[i]->context,
+ error_r)) {
+ result = -1;
+ break;
+ }
+ }
+
+ if (result < 0 && unlink(path) < 0 && errno != ENOENT) {
+ e_error(sbin->event, "failed to clean up after error: "
+ "unlink(%s) failed: %m", path);
+ }
+ }
+
+ return result;
+}
+
+int sieve_binary_save(struct sieve_binary *sbin, const char *path, bool update,
+ mode_t save_mode, enum sieve_error *error_r)
+{
+ int ret;
+
+ sieve_binary_update_event(sbin, path);
+ ret = sieve_binary_do_save(sbin, path, update, save_mode, error_r);
+ sieve_binary_update_event(sbin, NULL);
+
+ return ret;
+}
+
+
+/*
+ * Binary file management
+ */
+
+static int
+sieve_binary_fd_open(struct sieve_binary *sbin, const char *path,
+ int open_flags, enum sieve_error *error_r)
+{
+ int fd;
+
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NONE;
+
+ fd = open(path, open_flags);
+ if (fd < 0) {
+ switch (errno) {
+ case ENOENT:
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NOT_FOUND;
+ break;
+ case EACCES:
+ e_error(sbin->event, "open: "
+ "failed to open: %s",
+ eacces_error_get("open", path));
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NO_PERMISSION;
+ break;
+ default:
+ e_error(sbin->event, "open: "
+ "failed to open: open(%s) failed: %m", path);
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ break;
+ }
+ return -1;
+ }
+ return fd;
+}
+
+static int
+sieve_binary_file_open(struct sieve_binary *sbin, const char *path,
+ struct sieve_binary_file **file_r,
+ enum sieve_error *error_r)
+{
+ int fd, ret = 0;
+ struct stat st;
+
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NONE;
+
+ fd = sieve_binary_fd_open(sbin, path, O_RDONLY, error_r);
+ if (fd < 0)
+ return -1;
+
+ if (fstat(fd, &st) < 0) {
+ if (errno != ENOENT)
+ e_error(sbin->event, "open: fstat() failed: %m");
+ ret = -1;
+ }
+
+ if (ret == 0 && !S_ISREG(st.st_mode)) {
+ e_error(sbin->event, "open: "
+ "binary is not a regular file");
+ ret = -1;
+ }
+
+ if (ret < 0) {
+ if (close(fd) < 0) {
+ e_error(sbin->event, "open: "
+ "close() failed after error: %m");
+ }
+ return -1;
+ }
+
+ pool_t pool;
+ struct sieve_binary_file *file;
+
+ pool = pool_alloconly_create("sieve_binary_file", 4096);
+ file = p_new(pool, struct sieve_binary_file, 1);
+ file->pool = pool;
+ file->path = p_strdup(pool, path);
+ file->fd = fd;
+ file->st = st;
+ file->sbin = sbin;
+
+ *file_r = file;
+ return 0;
+}
+
+void sieve_binary_file_close(struct sieve_binary_file **_file)
+{
+ struct sieve_binary_file *file = *_file;
+
+ *_file = NULL;
+ if (file == NULL)
+ return;
+
+ if (file->fd != -1) {
+ if (close(file->fd) < 0) {
+ e_error(file->sbin->event, "close: "
+ "failed to close: close() failed: %m");
+ }
+ }
+
+ pool_unref(&file->pool);
+}
+
+static int
+sieve_binary_file_read(struct sieve_binary_file *file, off_t *offset,
+ void *buffer, size_t size)
+{
+ struct sieve_binary *sbin = file->sbin;
+ int ret;
+ void *indata = buffer;
+ size_t insize = size;
+
+ *offset = SIEVE_BINARY_ALIGN(*offset);
+
+ /* Seek to the correct position */
+ if (*offset != file->offset &&
+ lseek(file->fd, *offset, SEEK_SET) == (off_t)-1) {
+ e_error(sbin->event, "read: "
+ "failed to seek(fd, %lld, SEEK_SET): %m",
+ (long long) *offset);
+ return -1;
+ }
+
+ /* Read record into memory */
+ while (insize > 0) {
+ ret = read(file->fd, indata, insize);
+ if (ret <= 0) {
+ if (ret == 0) {
+ e_error(sbin->event, "read: "
+ "binary is truncated "
+ "(more data expected)");
+ } else {
+ e_error(sbin->event, "read: "
+ "failed to read from binary: %m");
+ }
+ break;
+ }
+
+ indata = PTR_OFFSET(indata, ret);
+ insize -= ret;
+ }
+
+ if (insize != 0) {
+ /* Failed to read the whole requested record */
+ return 0;
+ }
+
+ *offset += size;
+ file->offset = *offset;
+ return 1;
+}
+
+static const void *
+sieve_binary_file_load_data(struct sieve_binary_file *file,
+ off_t *offset, size_t size)
+{
+ void *data = t_malloc_no0(size);
+
+ if (sieve_binary_file_read(file, offset, data, size) > 0)
+ return data;
+
+ return NULL;
+}
+
+static buffer_t *
+sieve_binary_file_load_buffer(struct sieve_binary_file *file,
+ off_t *offset, size_t size)
+{
+ buffer_t *buffer = buffer_create_dynamic(file->pool, size);
+
+ if (sieve_binary_file_read(file, offset,
+ buffer_get_space_unsafe(buffer, 0, size),
+ size) > 0)
+ return buffer;
+
+ return NULL;
+}
+
+/*
+ * Load binary from a file
+ */
+
+#define LOAD_HEADER(sbin, offset, header) \
+ (header *)sieve_binary_file_load_data(sbin->file, offset, \
+ sizeof(header))
+
+bool sieve_binary_load_block(struct sieve_binary_block *sblock)
+{
+ struct sieve_binary *sbin = sblock->sbin;
+ unsigned int id = sblock->id;
+ off_t offset = sblock->offset;
+ const struct sieve_binary_block_header *header =
+ LOAD_HEADER(sbin, &offset,
+ const struct sieve_binary_block_header);
+
+ if (header == NULL) {
+ e_error(sbin->event, "load: binary is corrupt: "
+ "failed to read header of block %d", id);
+ return FALSE;
+ }
+
+ if (header->id != id) {
+ e_error(sbin->event, "load: binary is corrupt: "
+ "header of block %d has non-matching id %d",
+ id, header->id);
+ return FALSE;
+ }
+
+ sblock->data = sieve_binary_file_load_buffer(sbin->file, &offset,
+ header->size);
+ if (sblock->data == NULL) {
+ e_error(sbin->event, "load: "
+ "failed to read block %d of binary (size=%d)",
+ id, header->size);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool
+_read_block_index_record(struct sieve_binary *sbin, off_t *offset,
+ unsigned int id)
+{
+ const struct sieve_binary_block_index *record =
+ LOAD_HEADER(sbin, offset,
+ const struct sieve_binary_block_index);
+ struct sieve_binary_block *block;
+
+ if (record == NULL) {
+ e_error(sbin->event, "open: binary is corrupt: "
+ "failed to load block index record %d", id);
+ return FALSE;
+ }
+
+ if (record->id != id) {
+ e_error(sbin->event, "open: binary is corrupt: "
+ "block index record %d has unexpected id %d",
+ id, record->id);
+ return FALSE;
+ }
+
+ block = sieve_binary_block_create_id(sbin, id);
+ block->ext_index = record->ext_id;
+ block->offset = record->offset;
+
+ return TRUE;
+}
+
+static int _read_extensions(struct sieve_binary_block *sblock)
+{
+ struct sieve_binary *sbin = sblock->sbin;
+ sieve_size_t offset = 0;
+ unsigned int i, count;
+ int result = 1;
+
+ if (!sieve_binary_read_unsigned(sblock, &offset, &count))
+ return -1;
+
+ for (i = 0; result > 0 && i < count; i++) {
+ T_BEGIN {
+ string_t *extension;
+ const struct sieve_extension *ext;
+ unsigned int version;
+
+ if (sieve_binary_read_string(sblock, &offset,
+ &extension)) {
+ ext = sieve_extension_get_by_name(
+ sbin->svinst, str_c(extension));
+
+ if (ext == NULL) {
+ e_error(sbin->event, "open: "
+ "binary requires unknown extension `%s'",
+ str_sanitize(str_c(extension), 128));
+ result = 0;
+ } else {
+ struct sieve_binary_extension_reg *ereg = NULL;
+
+ (void)sieve_binary_extension_register(sbin, ext, &ereg);
+ if (!sieve_binary_read_unsigned(sblock, &offset, &version) ||
+ !sieve_binary_read_unsigned(sblock, &offset, &ereg->block_id)) {
+ result = -1;
+ } else if (!sieve_extension_version_is(ext, version)) {
+ e_debug(sbin->event, "open: "
+ "binary was compiled with different version "
+ "of the `%s' extension (compiled v%d, expected v%d;"
+ "automatically fixed when re-compiled)",
+ sieve_extension_name(ext), version,
+ sieve_extension_version(ext));
+ result = 0;
+ }
+ }
+ } else {
+ result = -1;
+ }
+ } T_END;
+ }
+
+ return result;
+}
+
+static bool
+_sieve_binary_open(struct sieve_binary *sbin, enum sieve_error *error_r)
+{
+ bool result = TRUE;
+ off_t offset = 0;
+ struct sieve_binary_block *ext_block;
+ unsigned int i;
+ int ret;
+
+ /* Read header */
+
+ ret = sieve_binary_file_read_header(sbin, sbin->file->fd,
+ &sbin->header, error_r);
+ if (ret < 0)
+ return FALSE;
+ offset = sbin->header.hdr_size;
+
+ /* Load block index */
+
+ for (i = 0; i < sbin->header.blocks && result; i++) {
+ T_BEGIN {
+ if (!_read_block_index_record(sbin, &offset, i))
+ result = FALSE;
+ } T_END;
+ }
+
+ if (!result) {
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NOT_VALID;
+ return FALSE;
+ }
+
+ /* Load extensions used by this binary */
+
+ T_BEGIN {
+ ext_block = sieve_binary_block_get(
+ sbin, SBIN_SYSBLOCK_EXTENSIONS);
+ if (ext_block == NULL) {
+ result = FALSE;
+ } else if ((ret = _read_extensions(ext_block)) <= 0) {
+ if (ret < 0) {
+ e_error(sbin->event, "open: binary is corrupt: "
+ "failed to load extension block");
+ }
+ result = FALSE;
+ }
+ } T_END;
+
+ if (!result) {
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NOT_VALID;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+struct sieve_binary *
+sieve_binary_open(struct sieve_instance *svinst, const char *path,
+ struct sieve_script *script, enum sieve_error *error_r)
+{
+ struct sieve_binary_extension_reg *const *regs;
+ unsigned int ext_count, i;
+ struct sieve_binary *sbin;
+ struct sieve_binary_file *file;
+
+ i_assert(script == NULL || sieve_script_svinst(script) == svinst);
+
+ /* Create binary object */
+ sbin = sieve_binary_create(svinst, script);
+ sbin->path = p_strdup(sbin->pool, path);
+
+ if (sieve_binary_file_open(sbin, path, &file, error_r) < 0) {
+ sieve_binary_unref(&sbin);
+ return NULL;
+ }
+
+ sbin->file = file;
+
+ event_set_append_log_prefix(
+ sbin->event,
+ t_strdup_printf("binary %s: ", path));
+
+ if (!_sieve_binary_open(sbin, error_r)) {
+ sieve_binary_unref(&sbin);
+ return NULL;
+ }
+
+ sieve_binary_activate(sbin);
+
+ /* Signal open event to extensions */
+ regs = array_get(&sbin->extensions, &ext_count);
+ for (i = 0; i < ext_count; i++) {
+ const struct sieve_binary_extension *binext = regs[i]->binext;
+
+ if (binext != NULL && binext->binary_open != NULL &&
+ !binext->binary_open(regs[i]->extension, sbin,
+ regs[i]->context)) {
+ /* Extension thinks its corrupt */
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NOT_VALID;
+ sieve_binary_unref(&sbin);
+ return NULL;
+ }
+ }
+ return sbin;
+}
+
+int sieve_binary_check_executable(struct sieve_binary *sbin,
+ enum sieve_error *error_r,
+ const char **client_error_r)
+{
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NONE;
+ *client_error_r = NULL;
+
+ if (HAS_ALL_BITS(sbin->header.flags,
+ SIEVE_BINARY_FLAG_RESOURCE_LIMIT)) {
+ e_debug(sbin->event,
+ "Binary execution is blocked: "
+ "Cumulative resource usage limit exceeded "
+ "(resource limit flag is set)");
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_RESOURCE_LIMIT;
+ *client_error_r = "cumulative resource usage limit exceeded";
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Resource usage
+ */
+
+static int
+sieve_binary_file_do_update_resource_usage(
+ struct sieve_binary *sbin, int fd, enum sieve_error *error_r)
+{
+ struct sieve_binary_header *header = &sbin->header;
+ struct file_lock *lock;
+ const char *error;
+ int ret;
+
+ struct file_lock_settings lock_set = {
+ .lock_method = FILE_LOCK_METHOD_FCNTL,
+ };
+ ret = file_wait_lock(fd, sbin->path, F_WRLCK, &lock_set,
+ SIEVE_BINARY_FILE_LOCK_TIMEOUT, &lock, &error);
+ if (ret <= 0) {
+ e_error(sbin->event, "%s", error);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+
+ ret = sieve_binary_file_read_header(sbin, fd, header, error_r);
+ if (ret == 0) {
+ sieve_binary_file_update_header(sbin);
+ ret = sieve_binary_file_write_header(sbin, fd, header, error_r);
+ }
+
+ file_lock_free(&lock);
+
+ return ret;
+}
+
+int sieve_binary_file_update_resource_usage(struct sieve_binary *sbin,
+ enum sieve_error *error_r)
+{
+ enum sieve_error error;
+ int fd, ret = 0;
+
+ if (error_r == NULL)
+ error_r = &error;
+ *error_r = SIEVE_ERROR_NONE;
+
+ sieve_binary_file_close(&sbin->file);
+
+ if (sbin->path == NULL)
+ return 0;
+ if (sbin->header.version_major != SIEVE_BINARY_VERSION_MAJOR)
+ return sieve_binary_save(sbin, sbin->path, TRUE, 0600, error_r);
+
+ fd = sieve_binary_fd_open(sbin, sbin->path, O_RDWR, error_r);
+ if (fd < 0)
+ return -1;
+
+ ret = sieve_binary_file_do_update_resource_usage(sbin, fd, error_r);
+
+ if (close(fd) < 0) {
+ e_error(sbin->event, "update: "
+ "failed to close: close() failed: %m");
+ }
+
+ return ret;
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-binary-private.h b/pigeonhole/src/lib-sieve/sieve-binary-private.h
new file mode 100644
index 0000000..73d2d75
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-binary-private.h
@@ -0,0 +1,240 @@
+#ifndef SIEVE_BINARY_PRIVATE_H
+#define SIEVE_BINARY_PRIVATE_H
+
+#include "sieve-common.h"
+#include "sieve-binary.h"
+#include "sieve-extensions.h"
+
+#include <sys/stat.h>
+
+#define SIEVE_BINARY_FILE_LOCK_TIMEOUT 10
+
+/*
+ * Binary file
+ */
+
+enum SIEVE_BINARY_FLAGS {
+ SIEVE_BINARY_FLAG_RESOURCE_LIMIT = BIT(0),
+};
+
+struct sieve_binary_header {
+ uint32_t magic;
+ uint16_t version_major;
+ uint16_t version_minor;
+ uint32_t blocks;
+
+ uint32_t hdr_size;
+ uint32_t flags;
+
+ struct {
+ uint64_t update_time;
+ uint32_t cpu_time_msecs;
+ } resource_usage;
+};
+
+struct sieve_binary_file {
+ pool_t pool;
+ const char *path;
+ struct sieve_binary *sbin;
+
+ struct stat st;
+ int fd;
+ off_t offset;
+};
+
+void sieve_binary_file_close(struct sieve_binary_file **_file);
+
+/*
+ * Internal structures
+ */
+
+/* Extension registration */
+
+struct sieve_binary_extension_reg {
+ /* The identifier of the extension within this binary */
+ int index;
+
+ /* Global extension object */
+ const struct sieve_extension *extension;
+
+ /* Extension to the binary; typically used to manage extension-specific
+ blocks in the binary and as a means to get a binary_free notification
+ to release references held by extensions.
+ */
+ const struct sieve_binary_extension *binext;
+
+ /* Context data associated to the binary by this extension */
+ void *context;
+
+ /* Main block for this extension */
+ unsigned int block_id;
+};
+
+/* Block */
+
+struct sieve_binary_block {
+ struct sieve_binary *sbin;
+ unsigned int id;
+ int ext_index;
+
+ buffer_t *data;
+
+ uoff_t offset;
+};
+
+/*
+ * Binary object
+ */
+
+struct sieve_binary {
+ pool_t pool;
+ int refcount;
+ struct sieve_instance *svinst;
+ struct event *event;
+
+ struct sieve_script *script;
+
+ struct sieve_binary_file *file;
+ struct sieve_binary_header header;
+ struct sieve_resource_usage rusage;
+
+ /* When the binary is loaded into memory or when it is being constructed
+ by the generator, extensions can be associated to the binary. The
+ extensions array is a sequential list of all linked extensions. The
+ extension_index array is a mapping ext_id -> binary_extension. This
+ is used to obtain the index code associated with an extension for
+ this particular binary. The linked_extensions list all extensions
+ linked to this binary object other than the preloaded language
+ features implemented as 'extensions'.
+
+ All arrays refer to the same extension registration objects. Upon
+ loading a binary, the 'require'd extensions will sometimes need to
+ associate context data to the binary object in memory. This is stored
+ in these registration objects as well.
+ */
+ ARRAY(struct sieve_binary_extension_reg *) extensions;
+ ARRAY(struct sieve_binary_extension_reg *) extension_index;
+ ARRAY(struct sieve_binary_extension_reg *) linked_extensions;
+
+ /* Attributes of a loaded binary */
+ const char *path;
+
+ /* Blocks */
+ ARRAY(struct sieve_binary_block *) blocks;
+
+ bool rusage_updated:1;
+};
+
+void sieve_binary_update_event(struct sieve_binary *sbin, const char *new_path)
+ ATTR_NULL(2);
+
+struct sieve_binary *
+sieve_binary_create(struct sieve_instance *svinst, struct sieve_script *script);
+
+/* Blocks management */
+
+static inline struct sieve_binary_block *
+sieve_binary_block_index(struct sieve_binary *sbin, unsigned int id)
+{
+ struct sieve_binary_block * const *sblock;
+
+ if (id >= array_count(&sbin->blocks))
+ return NULL;
+
+ sblock = array_idx(&sbin->blocks, id);
+ if (*sblock == NULL)
+ return NULL;
+ return *sblock;
+}
+
+static inline size_t
+_sieve_binary_block_get_size(const struct sieve_binary_block *sblock)
+{
+ return buffer_get_used_size(sblock->data);
+}
+
+struct sieve_binary_block *
+sieve_binary_block_create_id(struct sieve_binary *sbin, unsigned int id);
+
+buffer_t *sieve_binary_block_get_buffer(struct sieve_binary_block *sblock);
+
+/* Extension registration */
+
+static inline struct sieve_binary_extension_reg *
+sieve_binary_extension_create_reg(struct sieve_binary *sbin,
+ const struct sieve_extension *ext)
+{
+ int index = array_count(&sbin->extensions);
+ struct sieve_binary_extension_reg *ereg;
+
+ if (ext->id < 0)
+ return NULL;
+
+ ereg = p_new(sbin->pool, struct sieve_binary_extension_reg, 1);
+ ereg->index = index;
+ ereg->extension = ext;
+
+ array_idx_set(&sbin->extensions, (unsigned int) index, &ereg);
+ array_idx_set(&sbin->extension_index, (unsigned int) ext->id, &ereg);
+
+ return ereg;
+}
+
+static inline struct sieve_binary_extension_reg *
+sieve_binary_extension_get_reg(struct sieve_binary *sbin,
+ const struct sieve_extension *ext,
+ bool create)
+{
+ struct sieve_binary_extension_reg *reg = NULL;
+
+ if (ext->id >= 0 &&
+ ext->id < (int)array_count(&sbin->extension_index)) {
+ struct sieve_binary_extension_reg * const *ereg =
+ array_idx(&sbin->extension_index,
+ (unsigned int)ext->id);
+
+ reg = *ereg;
+ }
+
+ /* Register if not known */
+ if (reg == NULL && create)
+ return sieve_binary_extension_create_reg(sbin, ext);
+ return reg;
+}
+
+static inline int
+sieve_binary_extension_register(struct sieve_binary *sbin,
+ const struct sieve_extension *ext,
+ struct sieve_binary_extension_reg **reg_r)
+{
+ struct sieve_binary_extension_reg *ereg;
+
+ if ((ereg = sieve_binary_extension_get_reg(sbin, ext, FALSE)) == NULL) {
+ ereg = sieve_binary_extension_create_reg(sbin, ext);
+
+ if (ereg == NULL)
+ return -1;
+
+ array_append(&sbin->linked_extensions, &ereg, 1);
+ }
+
+ if (reg_r != NULL)
+ *reg_r = ereg;
+ return ereg->index;
+}
+
+/* Load/Save */
+
+bool sieve_binary_load_block(struct sieve_binary_block *);
+
+/*
+ * Resource limits
+ */
+
+bool sieve_binary_check_resource_usage(struct sieve_binary *sbin);
+
+int sieve_binary_file_update_resource_usage(struct sieve_binary *sbin,
+ enum sieve_error *error_r)
+ ATTR_NULL(2);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-binary.c b/pigeonhole/src/lib-sieve/sieve-binary.c
new file mode 100644
index 0000000..06cf598
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-binary.c
@@ -0,0 +1,606 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "mempool.h"
+#include "buffer.h"
+#include "hash.h"
+#include "array.h"
+#include "ostream.h"
+#include "eacces-error.h"
+#include "safe-mkstemp.h"
+
+#include "sieve-error.h"
+#include "sieve-extensions.h"
+#include "sieve-code.h"
+#include "sieve-script.h"
+
+#include "sieve-binary-private.h"
+
+/*
+ * Forward declarations
+ */
+
+static inline struct sieve_binary_extension_reg *
+sieve_binary_extension_get_reg(struct sieve_binary *sbin,
+ const struct sieve_extension *ext, bool create);
+
+static inline int
+sieve_binary_extension_register(struct sieve_binary *sbin,
+ const struct sieve_extension *ext,
+ struct sieve_binary_extension_reg **reg);
+
+/*
+ * Binary object
+ */
+
+void sieve_binary_update_event(struct sieve_binary *sbin, const char *new_path)
+{
+ if (new_path != NULL) {
+ event_set_append_log_prefix(
+ sbin->event, t_strdup_printf("binary %s: ", new_path));
+ } else if (sbin->path != NULL) {
+ event_set_append_log_prefix(
+ sbin->event,
+ t_strdup_printf("binary %s: ", sbin->path));
+ } else if (sbin->script != NULL) {
+ event_set_append_log_prefix(
+ sbin->event,
+ t_strdup_printf("binary %s: ",
+ sieve_script_name(sbin->script)));
+ } else {
+ event_set_append_log_prefix(sbin->event, "binary: ");
+ }
+}
+
+struct sieve_binary *
+sieve_binary_create(struct sieve_instance *svinst, struct sieve_script *script)
+{
+ pool_t pool;
+ struct sieve_binary *sbin;
+ const struct sieve_extension *const *ext_preloaded;
+ unsigned int i, ext_count;
+
+ pool = pool_alloconly_create("sieve_binary", 16384);
+ sbin = p_new(pool, struct sieve_binary, 1);
+ sbin->pool = pool;
+ sbin->refcount = 1;
+ sbin->svinst = svinst;
+
+ sbin->header.version_major = SIEVE_BINARY_VERSION_MAJOR;
+ sbin->header.version_minor = SIEVE_BINARY_VERSION_MINOR;
+
+ sbin->script = script;
+ if (script != NULL)
+ sieve_script_ref(script);
+
+ sbin->event = event_create(svinst->event);
+
+ ext_count = sieve_extensions_get_count(svinst);
+
+ p_array_init(&sbin->linked_extensions, pool, ext_count);
+ p_array_init(&sbin->extensions, pool, ext_count);
+ p_array_init(&sbin->extension_index, pool, ext_count);
+
+ p_array_init(&sbin->blocks, pool, 16);
+
+ /* Pre-load core language features implemented as 'extensions' */
+ ext_preloaded = sieve_extensions_get_preloaded(svinst, &ext_count);
+ for (i = 0; i < ext_count; i++) {
+ const struct sieve_extension_def *ext_def = ext_preloaded[i]->def;
+
+ if (ext_def != NULL && ext_def->binary_load != NULL)
+ (void)ext_def->binary_load(ext_preloaded[i], sbin);
+ }
+
+ return sbin;
+}
+
+struct sieve_binary *sieve_binary_create_new(struct sieve_script *script)
+{
+ struct sieve_binary *sbin =
+ sieve_binary_create(sieve_script_svinst(script), script);
+ struct sieve_binary_block *sblock;
+ unsigned int i;
+
+ sieve_binary_update_event(sbin, NULL);
+
+ /* Create script metadata block */
+ sblock = sieve_binary_block_create(sbin);
+ sieve_script_binary_write_metadata(script, sblock);
+
+ /* Create other system blocks */
+ for (i = 1; i < SBIN_SYSBLOCK_LAST; i++)
+ (void)sieve_binary_block_create(sbin);
+
+ return sbin;
+}
+
+void sieve_binary_ref(struct sieve_binary *sbin)
+{
+ sbin->refcount++;
+}
+
+static inline void sieve_binary_extensions_free(struct sieve_binary *sbin)
+{
+ struct sieve_binary_extension_reg *const *regs;
+ unsigned int ext_count, i;
+
+ /* Cleanup binary extensions */
+ regs = array_get(&sbin->extensions, &ext_count);
+ for (i = 0; i < ext_count; i++) {
+ const struct sieve_binary_extension *binext = regs[i]->binext;
+
+ if (binext != NULL && binext->binary_free != NULL) {
+ binext->binary_free(regs[i]->extension, sbin,
+ regs[i]->context);
+ }
+ }
+}
+
+static void sieve_binary_update_resource_usage(struct sieve_binary *sbin)
+{
+ enum sieve_error error;
+
+ if (sbin->rusage_updated)
+ (void)sieve_binary_file_update_resource_usage(sbin, &error);
+ sbin->rusage_updated = FALSE;
+}
+
+void sieve_binary_unref(struct sieve_binary **_sbin)
+{
+ struct sieve_binary *sbin = *_sbin;
+
+ *_sbin = NULL;
+ if (sbin == NULL)
+ return;
+
+ i_assert(sbin->refcount > 0);
+ if (--sbin->refcount != 0)
+ return;
+
+ sieve_binary_file_close(&sbin->file);
+ sieve_binary_update_resource_usage(sbin);
+ sieve_binary_extensions_free(sbin);
+
+ if (sbin->script != NULL)
+ sieve_script_unref(&sbin->script);
+
+ event_unref(&sbin->event);
+ pool_unref(&sbin->pool);
+}
+
+void sieve_binary_close(struct sieve_binary **_sbin)
+{
+ struct sieve_binary *sbin = *_sbin;
+
+ *_sbin = NULL;
+ if (sbin == NULL)
+ return;
+
+ sieve_binary_file_close(&sbin->file);
+ sieve_binary_update_resource_usage(sbin);
+ sieve_binary_unref(&sbin);
+}
+
+/*
+ * Resource usage
+ */
+
+void sieve_binary_get_resource_usage(struct sieve_binary *sbin,
+ struct sieve_resource_usage *rusage_r)
+{
+ struct sieve_binary_header *header = &sbin->header;
+ time_t update_time = header->resource_usage.update_time;
+ unsigned int timeout = sbin->svinst->resource_usage_timeout_secs;
+
+ if (update_time != 0 && (ioloop_time - update_time) > timeout)
+ i_zero(&header->resource_usage);
+
+ sieve_resource_usage_init(rusage_r);
+ rusage_r->cpu_time_msecs = header->resource_usage.cpu_time_msecs;
+ sieve_resource_usage_add(rusage_r, &sbin->rusage);
+}
+
+bool sieve_binary_check_resource_usage(struct sieve_binary *sbin)
+{
+ struct sieve_binary_header *header = &sbin->header;
+ struct sieve_resource_usage rusage;
+
+ sieve_binary_get_resource_usage(sbin, &rusage);
+
+ if (sieve_resource_usage_is_excessive(sbin->svinst, &rusage)) {
+ header->flags |= SIEVE_BINARY_FLAG_RESOURCE_LIMIT;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool sieve_binary_record_resource_usage(
+ struct sieve_binary *sbin, const struct sieve_resource_usage *rusage)
+{
+ struct sieve_resource_usage rusage_total;
+
+ if (sbin == NULL)
+ return TRUE;
+ if (!sieve_resource_usage_is_high(sbin->svinst, rusage))
+ return TRUE;
+
+ sieve_resource_usage_add(&sbin->rusage, rusage);
+ sbin->rusage_updated = TRUE;
+
+ sieve_binary_get_resource_usage(sbin, &rusage_total);
+
+ e_debug(sbin->event, "Updated cumulative resource usage: %s",
+ sieve_resource_usage_get_summary(&rusage_total));
+
+ return sieve_binary_check_resource_usage(sbin);
+}
+
+void sieve_binary_set_resource_usage(struct sieve_binary *sbin,
+ const struct sieve_resource_usage *rusage)
+{
+ struct sieve_binary_header *header = &sbin->header;
+
+ i_zero(&header->resource_usage);
+ sbin->rusage = *rusage;
+ sbin->rusage_updated = TRUE;
+
+ (void)sieve_binary_check_resource_usage(sbin);
+}
+
+/*
+ * Accessors
+ */
+
+pool_t sieve_binary_pool(struct sieve_binary *sbin)
+{
+ return sbin->pool;
+}
+
+struct sieve_script *sieve_binary_script(struct sieve_binary *sbin)
+{
+ return sbin->script;
+}
+
+const char *sieve_binary_path(struct sieve_binary *sbin)
+{
+ return sbin->path;
+}
+
+bool sieve_binary_saved(struct sieve_binary *sbin)
+{
+ return (sbin->path != NULL);
+}
+
+bool sieve_binary_loaded(struct sieve_binary *sbin)
+{
+ return (sbin->file != NULL);
+}
+
+const char *sieve_binary_source(struct sieve_binary *sbin)
+{
+ if (sbin->script != NULL && (sbin->path == NULL || sbin->file == NULL))
+ return sieve_script_location(sbin->script);
+
+ return sbin->path;
+}
+
+struct sieve_instance *sieve_binary_svinst(struct sieve_binary *sbin)
+{
+ return sbin->svinst;
+}
+
+time_t sieve_binary_mtime(struct sieve_binary *sbin)
+{
+ i_assert(sbin->file != NULL);
+ return sbin->file->st.st_mtime;
+}
+
+const struct stat *sieve_binary_stat(struct sieve_binary *sbin)
+{
+ i_assert(sbin->file != NULL);
+ return &sbin->file->st;
+}
+
+const char *sieve_binary_script_name(struct sieve_binary *sbin)
+{
+ return (sbin->script == NULL ?
+ NULL : sieve_script_name(sbin->script));
+}
+
+const char *sieve_binary_script_location(struct sieve_binary *sbin)
+{
+ return (sbin->script == NULL ?
+ NULL : sieve_script_location(sbin->script));
+}
+
+/*
+ * Utility
+ */
+
+const char *sieve_binfile_from_name(const char *name)
+{
+ return t_strconcat(name, "."SIEVE_BINARY_FILEEXT, NULL);
+}
+
+/*
+ * Block management
+ */
+
+unsigned int sieve_binary_block_count(struct sieve_binary *sbin)
+{
+ return array_count(&sbin->blocks);
+}
+
+struct sieve_binary_block *sieve_binary_block_create(struct sieve_binary *sbin)
+{
+ unsigned int id = sieve_binary_block_count(sbin);
+ struct sieve_binary_block *sblock;
+
+ sblock = p_new(sbin->pool, struct sieve_binary_block, 1);
+ sblock->data = buffer_create_dynamic(sbin->pool, 64);
+ sblock->sbin = sbin;
+ sblock->id = id;
+
+ array_append(&sbin->blocks, &sblock, 1);
+
+ return sblock;
+}
+
+struct sieve_binary_block *
+sieve_binary_block_create_id(struct sieve_binary *sbin, unsigned int id)
+{
+ struct sieve_binary_block *sblock;
+
+ sblock = p_new(sbin->pool, struct sieve_binary_block, 1);
+
+ array_idx_set(&sbin->blocks, id, &sblock);
+ sblock->data = NULL;
+ sblock->sbin = sbin;
+ sblock->id = id;
+
+ return sblock;
+}
+
+static bool sieve_binary_block_fetch(struct sieve_binary_block *sblock)
+{
+ struct sieve_binary *sbin = sblock->sbin;
+
+ if (sbin->file != NULL) {
+ /* Try to acces the block in the binary on disk (apparently we
+ were lazy)
+ */
+ if (!sieve_binary_load_block(sblock) || sblock->data == NULL)
+ return FALSE;
+ } else {
+ sblock->data = buffer_create_dynamic(sbin->pool, 64);
+ return TRUE;
+ }
+
+ return TRUE;
+}
+
+struct sieve_binary_block *
+sieve_binary_block_get(struct sieve_binary *sbin, unsigned int id)
+{
+ struct sieve_binary_block *sblock = sieve_binary_block_index(sbin, id);
+
+ if (sblock == NULL)
+ return NULL;
+
+ if (sblock->data == NULL && !sieve_binary_block_fetch(sblock))
+ return NULL;
+
+ return sblock;
+}
+
+void sieve_binary_block_clear(struct sieve_binary_block *sblock)
+{
+ buffer_set_used_size(sblock->data, 0);
+}
+
+buffer_t *sieve_binary_block_get_buffer(struct sieve_binary_block *sblock)
+{
+ if (sblock->data == NULL && !sieve_binary_block_fetch(sblock))
+ return NULL;
+
+ return sblock->data;
+}
+
+struct sieve_binary *
+sieve_binary_block_get_binary(const struct sieve_binary_block *sblock)
+{
+ return sblock->sbin;
+}
+
+unsigned int sieve_binary_block_get_id(const struct sieve_binary_block *sblock)
+{
+ return sblock->id;
+}
+
+size_t sieve_binary_block_get_size(const struct sieve_binary_block *sblock)
+{
+ return _sieve_binary_block_get_size(sblock);
+}
+
+/*
+ * Up-to-date checking
+ */
+
+bool sieve_binary_up_to_date(struct sieve_binary *sbin,
+ enum sieve_compile_flags cpflags)
+{
+ struct sieve_binary_extension_reg *const *regs;
+ struct sieve_binary_block *sblock;
+ sieve_size_t offset = 0;
+ unsigned int ext_count, i;
+ int ret;
+
+ i_assert(sbin->file != NULL);
+
+ sblock = sieve_binary_block_get(sbin, SBIN_SYSBLOCK_SCRIPT_DATA);
+ if (sblock == NULL || sbin->script == NULL)
+ return FALSE;
+
+ if ((ret = sieve_script_binary_read_metadata(sbin->script, sblock,
+ &offset)) <= 0) {
+ if (ret < 0) {
+ e_debug(sbin->event, "up-to-date: "
+ "failed to read script metadata from binary");
+ } else {
+ e_debug(sbin->event, "up-to-date: "
+ "script metadata indicates that binary is not up-to-date");
+ }
+ return FALSE;
+ }
+
+ regs = array_get(&sbin->extensions, &ext_count);
+ for (i = 0; i < ext_count; i++) {
+ const struct sieve_binary_extension *binext = regs[i]->binext;
+
+ if (binext != NULL && binext->binary_up_to_date != NULL &&
+ !binext->binary_up_to_date(regs[i]->extension, sbin,
+ regs[i]->context, cpflags)) {
+ e_debug(sbin->event, "up-to-date: "
+ "the %s extension indicates binary is not up-to-date",
+ sieve_extension_name(regs[i]->extension));
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/*
+ * Activate the binary (after code generation)
+ */
+
+void sieve_binary_activate(struct sieve_binary *sbin)
+{
+ struct sieve_binary_extension_reg *const *regs;
+ unsigned int i, ext_count;
+
+ /* Load other extensions into binary */
+ regs = array_get(&sbin->linked_extensions, &ext_count);
+ for (i = 0; i < ext_count; i++) {
+ const struct sieve_extension *ext = regs[i]->extension;
+
+ if (ext != NULL && ext->def != NULL &&
+ ext->def->binary_load != NULL)
+ ext->def->binary_load(ext, sbin);
+ }
+}
+
+/*
+ * Extension handling
+ */
+
+void sieve_binary_extension_set_context(struct sieve_binary *sbin,
+ const struct sieve_extension *ext,
+ void *context)
+{
+ struct sieve_binary_extension_reg *ereg =
+ sieve_binary_extension_get_reg(sbin, ext, TRUE);
+
+ if (ereg != NULL)
+ ereg->context = context;
+}
+
+const void *
+sieve_binary_extension_get_context(struct sieve_binary *sbin,
+ const struct sieve_extension *ext)
+{
+ struct sieve_binary_extension_reg *ereg =
+ sieve_binary_extension_get_reg(sbin, ext, TRUE);
+
+ if (ereg != NULL)
+ return ereg->context;
+
+ return NULL;
+}
+
+void sieve_binary_extension_set(struct sieve_binary *sbin,
+ const struct sieve_extension *ext,
+ const struct sieve_binary_extension *bext,
+ void *context)
+{
+ struct sieve_binary_extension_reg *ereg =
+ sieve_binary_extension_get_reg(sbin, ext, TRUE);
+
+ if (ereg != NULL) {
+ ereg->binext = bext;
+
+ if (context != NULL)
+ ereg->context = context;
+ }
+}
+
+struct sieve_binary_block *
+sieve_binary_extension_create_block(struct sieve_binary *sbin,
+ const struct sieve_extension *ext)
+{
+ struct sieve_binary_block *sblock;
+ struct sieve_binary_extension_reg *ereg =
+ sieve_binary_extension_get_reg(sbin, ext, TRUE);
+
+ i_assert(ereg != NULL);
+
+ sblock = sieve_binary_block_create(sbin);
+
+ if (ereg->block_id < SBIN_SYSBLOCK_LAST)
+ ereg->block_id = sblock->id;
+ sblock->ext_index = ereg->index;
+
+ return sblock;
+}
+
+struct sieve_binary_block *
+sieve_binary_extension_get_block(struct sieve_binary *sbin,
+ const struct sieve_extension *ext)
+{
+ struct sieve_binary_extension_reg *ereg =
+ sieve_binary_extension_get_reg(sbin, ext, TRUE);
+
+ i_assert(ereg != NULL);
+
+ if (ereg->block_id < SBIN_SYSBLOCK_LAST)
+ return NULL;
+
+ return sieve_binary_block_get(sbin, ereg->block_id);
+}
+
+int sieve_binary_extension_link(struct sieve_binary *sbin,
+ const struct sieve_extension *ext)
+{
+ return sieve_binary_extension_register(sbin, ext, NULL);
+}
+
+const struct sieve_extension *
+sieve_binary_extension_get_by_index(struct sieve_binary *sbin, int index)
+{
+ struct sieve_binary_extension_reg * const *ereg;
+
+ if (index < (int)array_count(&sbin->extensions)) {
+ ereg = array_idx(&sbin->extensions, (unsigned int)index);
+
+ return (*ereg)->extension;
+ }
+
+ return NULL;
+}
+
+int sieve_binary_extension_get_index(struct sieve_binary *sbin,
+ const struct sieve_extension *ext)
+{
+ struct sieve_binary_extension_reg *ereg =
+ sieve_binary_extension_get_reg(sbin, ext, FALSE);
+
+ return (ereg == NULL ? -1 : ereg->index);
+}
+
+int sieve_binary_extensions_count(struct sieve_binary *sbin)
+{
+ return (int)array_count(&sbin->extensions);
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-binary.h b/pigeonhole/src/lib-sieve/sieve-binary.h
new file mode 100644
index 0000000..0b8b66e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-binary.h
@@ -0,0 +1,291 @@
+#ifndef SIEVE_BINARY_H
+#define SIEVE_BINARY_H
+
+#include "lib.h"
+
+#include "sieve-common.h"
+
+/*
+ * Config
+ */
+
+#define SIEVE_BINARY_VERSION_MAJOR 2
+#define SIEVE_BINARY_VERSION_MINOR 0
+
+#define SIEVE_BINARY_BASE_HEADER_SIZE 20
+
+/*
+ * Binary object
+ */
+
+struct sieve_binary;
+
+struct sieve_binary *sieve_binary_create_new(struct sieve_script *script);
+void sieve_binary_ref(struct sieve_binary *sbin);
+void sieve_binary_unref(struct sieve_binary **_sbin);
+
+void sieve_binary_close(struct sieve_binary **_sbin);
+
+/*
+ * Resource usage
+ */
+
+void sieve_binary_get_resource_usage(struct sieve_binary *sbin,
+ struct sieve_resource_usage *rusage_r);
+bool sieve_binary_record_resource_usage(
+ struct sieve_binary *sbin, const struct sieve_resource_usage *rusage)
+ ATTR_NULL(1);
+void sieve_binary_set_resource_usage(struct sieve_binary *sbin,
+ const struct sieve_resource_usage *rusage);
+/*
+ * Accessors
+ */
+
+pool_t sieve_binary_pool(struct sieve_binary *sbin);
+struct sieve_instance *sieve_binary_svinst(struct sieve_binary *sbin);
+const char *sieve_binary_path(struct sieve_binary *sbin);
+struct sieve_script *sieve_binary_script(struct sieve_binary *sbin);
+
+time_t sieve_binary_mtime(struct sieve_binary *sbin);
+const struct stat *sieve_binary_stat(struct sieve_binary *sbin);
+
+const char *sieve_binary_script_name(struct sieve_binary *sbin);
+const char *sieve_binary_script_location(struct sieve_binary *sbin);
+
+const char *sieve_binary_source(struct sieve_binary *sbin);
+bool sieve_binary_loaded(struct sieve_binary *sbin);
+bool sieve_binary_saved(struct sieve_binary *sbin);
+
+/*
+ * Utility
+ */
+
+const char *sieve_binfile_from_name(const char *name);
+
+/*
+ * Activation after code generation
+ */
+
+void sieve_binary_activate(struct sieve_binary *sbin);
+
+/*
+ * Saving the binary
+ */
+
+int sieve_binary_save(struct sieve_binary *sbin, const char *path, bool update,
+ mode_t save_mode, enum sieve_error *error_r);
+
+/*
+ * Loading the binary
+ */
+
+struct sieve_binary *
+sieve_binary_open(struct sieve_instance *svinst, const char *path,
+ struct sieve_script *script, enum sieve_error *error_r);
+bool sieve_binary_up_to_date(struct sieve_binary *sbin,
+ enum sieve_compile_flags cpflags);
+
+int sieve_binary_check_executable(struct sieve_binary *sbin,
+ enum sieve_error *error_r,
+ const char **client_error_r);
+
+/*
+ * Block management
+ */
+
+enum sieve_binary_system_block {
+ SBIN_SYSBLOCK_SCRIPT_DATA,
+ SBIN_SYSBLOCK_EXTENSIONS,
+ SBIN_SYSBLOCK_MAIN_PROGRAM,
+ SBIN_SYSBLOCK_LAST
+};
+
+struct sieve_binary_block *sieve_binary_block_create(struct sieve_binary *sbin);
+
+unsigned int sieve_binary_block_count(struct sieve_binary *sbin);
+
+struct sieve_binary_block *
+sieve_binary_block_get(struct sieve_binary *sbin, unsigned int id);
+
+void sieve_binary_block_clear(struct sieve_binary_block *sblock);
+
+size_t sieve_binary_block_get_size(const struct sieve_binary_block *sblock);
+
+struct sieve_binary *
+sieve_binary_block_get_binary(const struct sieve_binary_block *sblock);
+
+unsigned int sieve_binary_block_get_id(const struct sieve_binary_block *sblock);
+
+/*
+ * Extension support
+ */
+
+struct sieve_binary_extension {
+ const struct sieve_extension_def *extension;
+
+ bool (*binary_pre_save)(const struct sieve_extension *ext,
+ struct sieve_binary *sbin, void *context,
+ enum sieve_error *error_r);
+ bool (*binary_post_save)(const struct sieve_extension *ext,
+ struct sieve_binary *sbin, void *context,
+ enum sieve_error *error_r);
+ bool (*binary_open)(const struct sieve_extension *ext,
+ struct sieve_binary *sbin, void *context);
+
+ void (*binary_free)(const struct sieve_extension *ext,
+ struct sieve_binary *sbin, void *context);
+
+ bool (*binary_up_to_date)(const struct sieve_extension *ext,
+ struct sieve_binary *sbin, void *context,
+ enum sieve_compile_flags cpflags);
+};
+
+void sieve_binary_extension_set_context(struct sieve_binary *sbin,
+ const struct sieve_extension *ext,
+ void *context);
+const void *
+sieve_binary_extension_get_context(struct sieve_binary *sbin,
+ const struct sieve_extension *ext);
+
+void sieve_binary_extension_set(struct sieve_binary *sbin,
+ const struct sieve_extension *ext,
+ const struct sieve_binary_extension *bext,
+ void *context);
+
+struct sieve_binary_block *
+sieve_binary_extension_create_block(struct sieve_binary *sbin,
+ const struct sieve_extension *ext);
+struct sieve_binary_block *
+sieve_binary_extension_get_block(struct sieve_binary *sbin,
+ const struct sieve_extension *ext);
+
+int sieve_binary_extension_link(struct sieve_binary *sbin,
+ const struct sieve_extension *ext);
+const struct sieve_extension *
+sieve_binary_extension_get_by_index(struct sieve_binary *sbin, int index);
+int sieve_binary_extension_get_index(struct sieve_binary *sbin,
+ const struct sieve_extension *ext);
+int sieve_binary_extensions_count(struct sieve_binary *sbin);
+
+/*
+ * Code emission
+ */
+
+/* Low-level emission functions */
+
+sieve_size_t sieve_binary_emit_data(struct sieve_binary_block *sblock,
+ const void *data, sieve_size_t size);
+sieve_size_t sieve_binary_emit_byte(struct sieve_binary_block *sblock,
+ uint8_t byte);
+void sieve_binary_update_data(struct sieve_binary_block *sblock,
+ sieve_size_t address, const void *data,
+ sieve_size_t size);
+
+/* Offset emission functions */
+
+sieve_size_t sieve_binary_emit_offset(struct sieve_binary_block *sblock,
+ sieve_offset_t offset);
+void sieve_binary_resolve_offset(struct sieve_binary_block *sblock,
+ sieve_size_t address);
+
+/* Literal emission functions */
+
+sieve_size_t sieve_binary_emit_integer(struct sieve_binary_block *sblock,
+ sieve_number_t integer);
+sieve_size_t sieve_binary_emit_string(struct sieve_binary_block *sblock,
+ const string_t *str);
+sieve_size_t sieve_binary_emit_cstring(struct sieve_binary_block *sblock,
+ const char *str);
+
+static inline sieve_size_t
+sieve_binary_emit_unsigned(struct sieve_binary_block *sblock,
+ unsigned int count)
+{
+ return sieve_binary_emit_integer(sblock, count);
+}
+
+/* Extension emission functions */
+
+sieve_size_t sieve_binary_emit_extension(struct sieve_binary_block *sblock,
+ const struct sieve_extension *ext,
+ unsigned int offset);
+void sieve_binary_emit_extension_object(
+ struct sieve_binary_block *sblock,
+ const struct sieve_extension_objects *objs, unsigned int code);
+
+/*
+ * Code retrieval
+ */
+
+/* Literals */
+
+bool sieve_binary_read_byte(struct sieve_binary_block *sblock,
+ sieve_size_t *address, unsigned int *byte_r)
+ ATTR_NULL(3);
+bool sieve_binary_read_code(struct sieve_binary_block *sblock,
+ sieve_size_t *address, signed int *code_r)
+ ATTR_NULL(3);
+bool sieve_binary_read_offset(struct sieve_binary_block *sblock,
+ sieve_size_t *address, sieve_offset_t *offset_r)
+ ATTR_NULL(3);
+bool sieve_binary_read_integer(struct sieve_binary_block *sblock,
+ sieve_size_t *address, sieve_number_t *int_r)
+ ATTR_NULL(3);
+bool sieve_binary_read_string(struct sieve_binary_block *sblock,
+ sieve_size_t *address, string_t **str_r)
+ ATTR_NULL(3);
+
+static inline bool ATTR_NULL(3)
+sieve_binary_read_unsigned(struct sieve_binary_block *sblock,
+ sieve_size_t *address, unsigned int *count_r)
+{
+ sieve_number_t integer = 0;
+
+ if (!sieve_binary_read_integer(sblock, address, &integer))
+ return FALSE;
+ if (count_r != NULL)
+ *count_r = integer;
+ return TRUE;
+}
+
+/* Extensions */
+
+bool sieve_binary_read_extension(struct sieve_binary_block *sblock,
+ sieve_size_t *address, unsigned int *offset_r,
+ const struct sieve_extension **ext_r);
+const void *
+sieve_binary_read_extension_object(struct sieve_binary_block *sblock,
+ sieve_size_t *address,
+ const struct sieve_extension_objects *objs);
+
+/*
+ * Debug info
+ */
+
+/* Writer */
+
+struct sieve_binary_debug_writer;
+
+struct sieve_binary_debug_writer *
+sieve_binary_debug_writer_init(struct sieve_binary_block *sblock);
+void sieve_binary_debug_writer_deinit(
+ struct sieve_binary_debug_writer **dwriter);
+
+void sieve_binary_debug_emit(struct sieve_binary_debug_writer *dwriter,
+ sieve_size_t code_address, unsigned int code_line,
+ unsigned int code_column);
+
+/* Reader */
+
+struct sieve_binary_debug_reader *
+sieve_binary_debug_reader_init(struct sieve_binary_block *sblock);
+void sieve_binary_debug_reader_deinit(
+ struct sieve_binary_debug_reader **dreader);
+
+void sieve_binary_debug_reader_reset(struct sieve_binary_debug_reader *dreader);
+
+unsigned int
+sieve_binary_debug_read_line(struct sieve_binary_debug_reader *dreader,
+ sieve_size_t code_address);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-code-dumper.c b/pigeonhole/src/lib-sieve/sieve-code-dumper.c
new file mode 100644
index 0000000..17e2768
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-code-dumper.c
@@ -0,0 +1,351 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "lib.h"
+#include "str.h"
+#include "mempool.h"
+#include "ostream.h"
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-actions.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-result.h"
+#include "sieve-comparators.h"
+
+#include "sieve-dump.h"
+
+/*
+ * Code dumper extension
+ */
+
+struct sieve_code_dumper_extension_reg {
+ const struct sieve_code_dumper_extension *cdmpext;
+ const struct sieve_extension *ext;
+ void *context;
+};
+
+struct sieve_code_dumper {
+ pool_t pool;
+
+ /* Dump status */
+ struct sieve_operation oprtn;
+ sieve_size_t mark_address;
+ unsigned int mark_line;
+ unsigned int mark_last_line;
+ unsigned int indent;
+
+ /* Dump environment */
+ struct sieve_dumptime_env *dumpenv;
+
+ struct sieve_binary_debug_reader *dreader;
+
+ ARRAY(struct sieve_code_dumper_extension_reg) extensions;
+};
+
+struct sieve_code_dumper *sieve_code_dumper_create
+(struct sieve_dumptime_env *denv)
+{
+ pool_t pool;
+ struct sieve_code_dumper *cdumper;
+
+ pool = pool_alloconly_create("sieve_code_dumper", 4096);
+ cdumper = p_new(pool, struct sieve_code_dumper, 1);
+ cdumper->pool = pool;
+ cdumper->dumpenv = denv;
+
+ /* Setup storage for extension contexts */
+ p_array_init(&cdumper->extensions, pool,
+ sieve_extensions_get_count(denv->svinst));
+
+ return cdumper;
+}
+
+void sieve_code_dumper_free(struct sieve_code_dumper **_cdumper)
+{
+ struct sieve_code_dumper *cdumper = *_cdumper;
+ const struct sieve_code_dumper_extension_reg *eregs;
+ unsigned int count, i;
+
+ sieve_binary_debug_reader_deinit(&cdumper->dreader);
+
+ /* Signal registered extensions that the dumper is being destroyed */
+ eregs = array_get(&cdumper->extensions, &count);
+ for ( i = 0; i < count; i++ ) {
+ if ( eregs[i].cdmpext != NULL && eregs[i].cdmpext->free != NULL )
+ eregs[i].cdmpext->free(cdumper, eregs[i].context);
+ }
+
+ pool_unref(&cdumper->pool);
+ *_cdumper = NULL;
+}
+
+pool_t sieve_code_dumper_pool(struct sieve_code_dumper *cdumper)
+{
+ return cdumper->pool;
+}
+
+/* EXtension support */
+
+void sieve_dump_extension_register
+(struct sieve_code_dumper *cdumper, const struct sieve_extension *ext,
+ const struct sieve_code_dumper_extension *cdmpext, void *context)
+{
+ struct sieve_code_dumper_extension_reg *reg;
+
+ if ( ext->id < 0 ) return;
+
+ reg = array_idx_get_space(&cdumper->extensions, (unsigned int) ext->id);
+ reg->cdmpext = cdmpext;
+ reg->ext = ext;
+ reg->context = context;
+}
+
+void sieve_dump_extension_set_context
+(struct sieve_code_dumper *cdumper, const struct sieve_extension *ext,
+ void *context)
+{
+ struct sieve_code_dumper_extension_reg *reg;
+
+ if ( ext->id < 0 ) return;
+
+ reg = array_idx_get_space(&cdumper->extensions, (unsigned int) ext->id);
+ reg->context = context;
+}
+
+void *sieve_dump_extension_get_context
+(struct sieve_code_dumper *cdumper, const struct sieve_extension *ext)
+{
+ const struct sieve_code_dumper_extension_reg *reg;
+
+ if ( ext->id < 0 || ext->id >= (int) array_count(&cdumper->extensions) )
+ return NULL;
+
+ reg = array_idx(&cdumper->extensions, (unsigned int) ext->id);
+
+ return reg->context;
+}
+
+/* Dump functions */
+
+void sieve_code_dumpf
+(const struct sieve_dumptime_env *denv, const char *fmt, ...)
+{
+ struct sieve_code_dumper *cdumper = denv->cdumper;
+ unsigned tab = cdumper->indent;
+
+ string_t *outbuf = t_str_new(128);
+ va_list args;
+
+ va_start(args, fmt);
+ str_printfa(outbuf, "%08llx: ", (unsigned long long) cdumper->mark_address);
+
+ if ( cdumper->mark_line > 0 && (cdumper->indent == 0 ||
+ cdumper->mark_line != cdumper->mark_last_line) ) {
+ str_printfa(outbuf, "%4u: ", cdumper->mark_line);
+ cdumper->mark_last_line = cdumper->mark_line;
+ } else {
+ str_append(outbuf, " ");
+ }
+
+ while ( tab > 0 ) {
+ str_append(outbuf, " ");
+ tab--;
+ }
+
+ str_vprintfa(outbuf, fmt, args);
+ str_append_c(outbuf, '\n');
+ va_end(args);
+
+ o_stream_nsend(denv->stream, str_data(outbuf), str_len(outbuf));
+}
+
+static inline void sieve_code_line_mark
+(const struct sieve_dumptime_env *denv, sieve_size_t location)
+{
+ if ( denv->cdumper->dreader != NULL ) {
+ denv->cdumper->mark_line = sieve_binary_debug_read_line
+ (denv->cdumper->dreader, location);
+ }
+}
+
+void sieve_code_mark(const struct sieve_dumptime_env *denv)
+{
+ denv->cdumper->mark_address = denv->offset;
+ sieve_code_line_mark(denv, denv->offset);
+}
+
+void sieve_code_mark_specific
+(const struct sieve_dumptime_env *denv, sieve_size_t location)
+{
+ denv->cdumper->mark_address = location;
+ sieve_code_line_mark(denv, location);
+}
+
+void sieve_code_descend(const struct sieve_dumptime_env *denv)
+{
+ denv->cdumper->indent++;
+}
+
+void sieve_code_ascend(const struct sieve_dumptime_env *denv)
+{
+ if ( denv->cdumper->indent > 0 )
+ denv->cdumper->indent--;
+}
+
+/* Code Dump */
+
+static bool sieve_code_dumper_print_operation
+(struct sieve_code_dumper *cdumper)
+{
+ struct sieve_dumptime_env *denv = cdumper->dumpenv;
+ struct sieve_operation *oprtn = &(cdumper->oprtn);
+ sieve_size_t *address = &(denv->offset);
+
+ /* Mark start address of operation */
+ cdumper->indent = 0;
+ cdumper->mark_address = *address;
+
+ sieve_code_line_mark(denv, *address);
+
+ /* Read operation */
+ if ( sieve_operation_read(denv->sblock, address, oprtn) ) {
+ const struct sieve_operation_def *opdef = oprtn->def;
+
+ if ( opdef->dump != NULL )
+ return opdef->dump(denv, address);
+ else if ( opdef->mnemonic != NULL )
+ sieve_code_dumpf(denv, "%s", opdef->mnemonic);
+ else
+ return FALSE;
+
+ return TRUE;
+ }
+
+ sieve_code_dumpf(denv, "Failed to read opcode.");
+ return FALSE;
+}
+
+static bool sieve_code_dumper_print_extension
+(struct sieve_code_dumper *cdumper)
+{
+ struct sieve_dumptime_env *denv = cdumper->dumpenv;
+ sieve_size_t *address = &(denv->offset);
+ struct sieve_binary_block *sblock = denv->sblock;
+ unsigned int code = 0, deferred;
+ const struct sieve_extension *ext;
+
+ sieve_code_mark(denv);
+
+ if ( !sieve_binary_read_extension
+ (sblock, address, &code, &ext) ||
+ !sieve_binary_read_byte
+ (sblock, address, &deferred) ) {
+ return FALSE;
+ }
+
+ if ( ext->def == NULL) {
+ sieve_code_dumpf(denv, "[undefined]");
+
+ } else {
+ sieve_code_dumpf(denv, "%s%s",
+ sieve_extension_name(ext),
+ (deferred > 0 ? " (deferred)" : ""));
+
+ if (ext->def->code_dump != NULL ) {
+ sieve_code_descend(denv);
+ if ( !ext->def->code_dump(ext, denv, address) )
+ return FALSE;
+ sieve_code_ascend(denv);
+ }
+ }
+ return TRUE;
+}
+
+void sieve_code_dumper_run(struct sieve_code_dumper *cdumper)
+{
+ struct sieve_dumptime_env *denv = cdumper->dumpenv;
+ struct sieve_binary *sbin = denv->sbin;
+ struct sieve_binary_block *sblock = denv->sblock;
+ unsigned int debug_block_id, ext_count;
+ bool success;
+ sieve_size_t *address;
+
+ denv->offset = 0;
+ denv->oprtn = &(cdumper->oprtn);
+ address = &(denv->offset);
+
+ /* Heading */
+ o_stream_nsend_str(denv->stream, "Address Line Code\n");
+
+ /* Load debug block */
+ sieve_code_mark(denv);
+
+ if ( sieve_binary_read_unsigned(sblock, address, &debug_block_id) ) {
+ struct sieve_binary_block *debug_block =
+ sieve_binary_block_get(sbin, debug_block_id);
+
+ if ( debug_block == NULL ) {
+ sieve_code_dumpf(denv, "Invalid id %d for debug block.", debug_block_id);
+ return;
+ } else {
+ /* Initialize debug reader */
+ cdumper->dreader = sieve_binary_debug_reader_init(debug_block);
+
+ /* Dump block id */
+ sieve_code_dumpf(denv, "DEBUG BLOCK: %d", debug_block_id);
+ }
+ } else {
+ sieve_code_dumpf(denv, "Binary code header is corrupt.");
+ return;
+ }
+
+ /* Load and dump extensions listed in code */
+ sieve_code_mark(denv);
+
+ success = TRUE;
+ if ( sieve_binary_read_unsigned(sblock, address, &ext_count) ) {
+ unsigned int i;
+
+ sieve_code_dumpf(denv, "EXTENSIONS [%d]:", ext_count);
+ sieve_code_descend(denv);
+
+ for ( i = 0; success && (i < ext_count); i++ ) {
+ T_BEGIN {
+ success = success &&
+ sieve_code_dumper_print_extension(cdumper);
+ } T_END;
+ }
+
+ sieve_code_ascend(denv);
+ } else
+ success = FALSE;
+
+ if ( !success ) {
+ sieve_code_dumpf(denv, "Binary code header is corrupt.");
+ return;
+ }
+
+ while ( *address < sieve_binary_block_get_size(sblock) ) {
+
+ T_BEGIN {
+ success = sieve_code_dumper_print_operation(cdumper);
+ } T_END;
+
+ if ( !success ) {
+ sieve_code_dumpf(denv, "Binary is corrupt.");
+ return;
+ }
+ }
+
+ /* Mark end of the binary */
+ cdumper->indent = 0;
+ cdumper->mark_address = sieve_binary_block_get_size(sblock);
+ sieve_code_dumpf(denv, "[End of code]");
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-code-dumper.h b/pigeonhole/src/lib-sieve/sieve-code-dumper.h
new file mode 100644
index 0000000..651bd11
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-code-dumper.h
@@ -0,0 +1,55 @@
+#ifndef SIEVE_CODE_DUMPER_H
+#define SIEVE_CODE_DUMPER_H
+
+#include "sieve-common.h"
+
+struct sieve_code_dumper;
+
+struct sieve_code_dumper *sieve_code_dumper_create
+ (struct sieve_dumptime_env *denv);
+void sieve_code_dumper_free
+ (struct sieve_code_dumper **_dumper);
+pool_t sieve_code_dumper_pool
+ (struct sieve_code_dumper *dumper);
+
+/*
+ * Extension support
+ */
+
+struct sieve_code_dumper_extension {
+ const struct sieve_extension_def *ext;
+
+ void (*free)(struct sieve_code_dumper *dumper, void *context);
+};
+
+void sieve_dump_extension_register
+(struct sieve_code_dumper *dumper, const struct sieve_extension *ext,
+ const struct sieve_code_dumper_extension *dump_ext, void *context);
+void sieve_dump_extension_set_context
+ (struct sieve_code_dumper *dumper, const struct sieve_extension *ext,
+ void *context);
+void *sieve_dump_extension_get_context
+ (struct sieve_code_dumper *dumper, const struct sieve_extension *ext);
+
+/* Dump functions */
+
+void sieve_code_dumpf
+ (const struct sieve_dumptime_env *denv, const char *fmt, ...)
+ ATTR_FORMAT(2, 3);
+
+void sieve_code_mark(const struct sieve_dumptime_env *denv);
+void sieve_code_mark_specific
+ (const struct sieve_dumptime_env *denv, sieve_size_t location);
+void sieve_code_descend(const struct sieve_dumptime_env *denv);
+void sieve_code_ascend(const struct sieve_dumptime_env *denv);
+
+/* Operations and operands */
+
+bool sieve_code_dumper_print_optional_operands
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+
+/* Code dump (debugging purposes) */
+
+void sieve_code_dumper_run(struct sieve_code_dumper *dumper);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-code.c b/pigeonhole/src/lib-sieve/sieve-code.c
new file mode 100644
index 0000000..82bd7f1
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-code.c
@@ -0,0 +1,1169 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "str-sanitize.h"
+
+#include "sieve-common.h"
+#include "sieve-limits.h"
+#include "sieve-extensions.h"
+#include "sieve-stringlist.h"
+#include "sieve-actions.h"
+#include "sieve-binary.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "sieve-code.h"
+
+#include <stdio.h>
+
+/*
+ * Code stringlist
+ */
+
+/* Forward declarations */
+
+static int sieve_code_stringlist_next_item
+ (struct sieve_stringlist *_strlist, string_t **str_r);
+static void sieve_code_stringlist_reset
+ (struct sieve_stringlist *_strlist);
+static int sieve_code_stringlist_get_length
+ (struct sieve_stringlist *_strlist);
+
+/* Coded stringlist object */
+
+struct sieve_code_stringlist {
+ struct sieve_stringlist strlist;
+
+ sieve_size_t start_address;
+ sieve_size_t end_address;
+ sieve_size_t current_offset;
+ int length;
+ int index;
+};
+
+static struct sieve_stringlist *sieve_code_stringlist_create
+(const struct sieve_runtime_env *renv,
+ sieve_size_t start_address, unsigned int length, sieve_size_t end)
+{
+ struct sieve_code_stringlist *strlist;
+
+ if ( end > sieve_binary_block_get_size(renv->sblock) )
+ return NULL;
+
+ strlist = t_new(struct sieve_code_stringlist, 1);
+ strlist->strlist.runenv = renv;
+ strlist->strlist.exec_status = SIEVE_EXEC_OK;
+ strlist->strlist.next_item = sieve_code_stringlist_next_item;
+ strlist->strlist.reset = sieve_code_stringlist_reset;
+ strlist->strlist.get_length = sieve_code_stringlist_get_length;
+ strlist->start_address = start_address;
+ strlist->current_offset = start_address;
+ strlist->end_address = end;
+ strlist->length = length;
+ strlist->index = 0;
+
+ return &strlist->strlist;
+}
+
+/* Stringlist implementation */
+
+static int sieve_code_stringlist_next_item
+(struct sieve_stringlist *_strlist, string_t **str_r)
+{
+ struct sieve_code_stringlist *strlist =
+ (struct sieve_code_stringlist *) _strlist;
+ sieve_size_t address;
+ *str_r = NULL;
+ int ret;
+
+ /* Check for end of list */
+ if ( strlist->index >= strlist->length )
+ return 0;
+
+ /* Read next item */
+ address = strlist->current_offset;
+ if ( (ret=sieve_opr_string_read(_strlist->runenv, &address, NULL, str_r))
+ == SIEVE_EXEC_OK ) {
+ strlist->index++;
+ strlist->current_offset = address;
+ return 1;
+ }
+
+ _strlist->exec_status = ret;
+ return -1;
+}
+
+static void sieve_code_stringlist_reset
+(struct sieve_stringlist *_strlist)
+{
+ struct sieve_code_stringlist *strlist =
+ (struct sieve_code_stringlist *) _strlist;
+
+ strlist->current_offset = strlist->start_address;
+ strlist->index = 0;
+}
+
+static int sieve_code_stringlist_get_length
+(struct sieve_stringlist *_strlist)
+{
+ struct sieve_code_stringlist *strlist =
+ (struct sieve_code_stringlist *) _strlist;
+
+ return strlist->length;
+}
+
+static bool sieve_code_stringlist_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address,
+ unsigned int length, sieve_size_t end, const char *field_name)
+{
+ unsigned int i;
+
+ if ( end > sieve_binary_block_get_size(denv->sblock) )
+ return FALSE;
+
+ if ( field_name != NULL )
+ sieve_code_dumpf(denv, "%s: STRLIST [%u] (end: %08llx)",
+ field_name, length, (unsigned long long) end);
+ else
+ sieve_code_dumpf(denv, "STRLIST [%u] (end: %08llx)",
+ length, (unsigned long long) end);
+
+ sieve_code_descend(denv);
+
+ for ( i = 0; i < length; i++ ) {
+ bool success = TRUE;
+
+ T_BEGIN {
+ success = sieve_opr_string_dump(denv, address, NULL);
+ } T_END;
+
+ if ( !success || *address > end )
+ return FALSE;
+ }
+
+ if ( *address != end ) return FALSE;
+
+ sieve_code_ascend(denv);
+
+ return TRUE;
+}
+
+/*
+ * Core operands
+ */
+
+extern const struct sieve_operand_def comparator_operand;
+extern const struct sieve_operand_def match_type_operand;
+extern const struct sieve_operand_def address_part_operand;
+
+const struct sieve_operand_def *sieve_operands[] = {
+ &omitted_operand, /* SIEVE_OPERAND_OPTIONAL */
+ &number_operand,
+ &string_operand,
+ &stringlist_operand,
+ &comparator_operand,
+ &match_type_operand,
+ &address_part_operand,
+ &catenated_string_operand
+};
+
+const unsigned int sieve_operand_count =
+ N_ELEMENTS(sieve_operands);
+
+/*
+ * Operand functions
+ */
+
+sieve_size_t sieve_operand_emit
+(struct sieve_binary_block *sblock, const struct sieve_extension *ext,
+ const struct sieve_operand_def *opr_def)
+{
+ sieve_size_t address;
+
+ if ( ext != NULL ) {
+ address = sieve_binary_emit_extension
+ (sblock, ext, sieve_operand_count);
+
+ sieve_binary_emit_extension_object
+ (sblock, &opr_def->ext_def->operands, opr_def->code);
+
+ return address;
+ }
+
+ return sieve_binary_emit_byte(sblock, opr_def->code);
+}
+
+bool sieve_operand_read
+(struct sieve_binary_block *sblock, sieve_size_t *address,
+ const char *field_name, struct sieve_operand *operand)
+{
+ unsigned int code = sieve_operand_count;
+
+ operand->address = *address;
+ operand->field_name = field_name;
+ operand->ext = NULL;
+ operand->def = NULL;
+
+ if ( !sieve_binary_read_extension(sblock, address, &code, &operand->ext) )
+ return FALSE;
+
+ if ( operand->ext == NULL ) {
+ if ( code < sieve_operand_count )
+ operand->def = sieve_operands[code];
+
+ return ( operand->def != NULL );
+ }
+
+ if ( operand->ext->def == NULL )
+ return FALSE;
+
+ operand->def = (const struct sieve_operand_def *)
+ sieve_binary_read_extension_object(sblock, address,
+ &operand->ext->def->operands);
+
+ return ( operand->def != NULL );
+}
+
+/*
+ * Optional operand
+ */
+
+int sieve_opr_optional_next
+(struct sieve_binary_block *sblock, sieve_size_t *address, signed int *opt_code)
+{
+ /* Start of optional operand block */
+ if ( *opt_code == 0 ) {
+ sieve_size_t tmp_addr = *address;
+ unsigned int op;
+
+ if ( !sieve_binary_read_byte(sblock, &tmp_addr, &op) ||
+ op != SIEVE_OPERAND_OPTIONAL )
+ return 0;
+
+ *address = tmp_addr;
+ }
+
+ /* Read optional operand code */
+ if ( !sieve_binary_read_code(sblock, address, opt_code) )
+ return -1;
+
+ /* Return 0 at end of list */
+ return ( *opt_code != 0 ? 1 : 0 );
+}
+
+/*
+ * Operand definitions
+ */
+
+/* Omitted */
+
+const struct sieve_operand_class omitted_class =
+ { "OMITTED" };
+
+const struct sieve_operand_def omitted_operand = {
+ .name = "@OMITTED",
+ .code = SIEVE_OPERAND_OPTIONAL,
+ .class = &omitted_class
+};
+
+/* Number */
+
+static bool opr_number_dump
+ (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address);
+static int opr_number_read
+ (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, sieve_number_t *number_r);
+
+const struct sieve_opr_number_interface number_interface = {
+ opr_number_dump,
+ opr_number_read
+};
+
+const struct sieve_operand_class number_class =
+ { "number" };
+
+const struct sieve_operand_def number_operand = {
+ .name = "@number",
+ .code = SIEVE_OPERAND_NUMBER,
+ .class = &number_class,
+ .interface = &number_interface
+};
+
+/* String */
+
+static bool opr_string_dump
+ (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address);
+static int opr_string_read
+ (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, string_t **str_r);
+
+const struct sieve_opr_string_interface string_interface ={
+ opr_string_dump,
+ opr_string_read
+};
+
+const struct sieve_operand_class string_class =
+ { "string" };
+
+const struct sieve_operand_def string_operand = {
+ .name = "@string",
+ .code = SIEVE_OPERAND_STRING,
+ .class = &string_class,
+ .interface = &string_interface
+};
+
+/* String List */
+
+static bool opr_stringlist_dump
+ (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address);
+static int opr_stringlist_read
+ (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, struct sieve_stringlist **strlist_r);
+
+const struct sieve_opr_stringlist_interface stringlist_interface = {
+ opr_stringlist_dump,
+ opr_stringlist_read
+};
+
+const struct sieve_operand_class stringlist_class =
+ { "string-list" };
+
+const struct sieve_operand_def stringlist_operand = {
+ .name = "@string-list",
+ .code = SIEVE_OPERAND_STRING_LIST,
+ .class = &stringlist_class,
+ .interface = &stringlist_interface
+};
+
+/* Catenated String */
+
+static bool opr_catenated_string_dump
+ (const struct sieve_dumptime_env *denv, const struct sieve_operand *operand,
+ sieve_size_t *address);
+static int opr_catenated_string_read
+ (const struct sieve_runtime_env *renv, const struct sieve_operand *operand,
+ sieve_size_t *address, string_t **str);
+
+const struct sieve_opr_string_interface catenated_string_interface = {
+ opr_catenated_string_dump,
+ opr_catenated_string_read
+};
+
+const struct sieve_operand_def catenated_string_operand = {
+ .name = "@catenated-string",
+ .code = SIEVE_OPERAND_CATENATED_STRING,
+ .class = &string_class,
+ .interface = &catenated_string_interface
+};
+
+/*
+ * Operand implementations
+ */
+
+/* Omitted */
+
+void sieve_opr_omitted_emit(struct sieve_binary_block *sblock)
+{
+ (void) sieve_operand_emit(sblock, NULL, &omitted_operand);
+}
+
+/* Number */
+
+void sieve_opr_number_emit
+(struct sieve_binary_block *sblock, sieve_number_t number)
+{
+ (void) sieve_operand_emit(sblock, NULL, &number_operand);
+ (void) sieve_binary_emit_integer(sblock, number);
+}
+
+bool sieve_opr_number_dump_data
+(const struct sieve_dumptime_env *denv, struct sieve_operand *oprnd,
+ sieve_size_t *address, const char *field_name)
+{
+ const struct sieve_opr_number_interface *intf;
+
+ oprnd->field_name = field_name;
+
+ if ( !sieve_operand_is_number(oprnd) )
+ return FALSE;
+
+ intf = (const struct sieve_opr_number_interface *) oprnd->def->interface;
+
+ if ( intf->dump == NULL )
+ return FALSE;
+
+ return intf->dump(denv, oprnd, address);
+}
+
+bool sieve_opr_number_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address,
+ const char *field_name)
+{
+ struct sieve_operand operand;
+
+ sieve_code_mark(denv);
+
+ if ( !sieve_operand_read(denv->sblock, address, field_name, &operand) )
+ return FALSE;
+
+ return sieve_opr_number_dump_data(denv, &operand, address, field_name);
+}
+
+int sieve_opr_number_read_data
+(const struct sieve_runtime_env *renv, struct sieve_operand *oprnd,
+ sieve_size_t *address, const char *field_name, sieve_number_t *number_r)
+{
+ const struct sieve_opr_number_interface *intf;
+
+ oprnd->field_name = field_name;
+
+ if ( !sieve_operand_is_number(oprnd) ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "expected number operand but found %s", sieve_operand_name(oprnd));
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ intf = (const struct sieve_opr_number_interface *) oprnd->def->interface;
+
+ if ( intf->read == NULL ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "number operand not implemented");
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ return intf->read(renv, oprnd, address, number_r);
+}
+
+int sieve_opr_number_read
+(const struct sieve_runtime_env *renv, sieve_size_t *address,
+ const char *field_name, sieve_number_t *number_r)
+{
+ struct sieve_operand operand;
+ int ret;
+
+ if ( (ret=sieve_operand_runtime_read(renv, address, field_name, &operand))
+ <= 0)
+ return ret;
+
+ return sieve_opr_number_read_data
+ (renv, &operand, address, field_name, number_r);
+}
+
+static bool opr_number_dump
+(const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address)
+{
+ sieve_number_t number = 0;
+
+ if (sieve_binary_read_integer(denv->sblock, address, &number) ) {
+ if ( oprnd->field_name != NULL )
+ sieve_code_dumpf(denv, "%s: NUM %llu", oprnd->field_name,
+ (unsigned long long) number);
+ else
+ sieve_code_dumpf(denv, "NUM %llu", (unsigned long long) number);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int opr_number_read
+(const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, sieve_number_t *number_r)
+{
+ if ( !sieve_binary_read_integer(renv->sblock, address, number_r) ) {
+ sieve_runtime_trace_operand_error(renv, oprnd, "invalid number operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+/* String */
+
+void sieve_opr_string_emit(struct sieve_binary_block *sblock, string_t *str)
+{
+ (void) sieve_operand_emit(sblock, NULL, &string_operand);
+ (void) sieve_binary_emit_string(sblock, str);
+}
+
+bool sieve_opr_string_dump_data
+(const struct sieve_dumptime_env *denv, struct sieve_operand *oprnd,
+ sieve_size_t *address, const char *field_name)
+{
+ const struct sieve_opr_string_interface *intf;
+
+ oprnd->field_name = field_name;
+
+ if ( !sieve_operand_is_string(oprnd) ) {
+ sieve_code_dumpf(denv, "ERROR: INVALID STRING OPERAND %s",
+ sieve_operand_name(oprnd));
+ return FALSE;
+ }
+
+ intf = (const struct sieve_opr_string_interface *) oprnd->def->interface;
+
+ if ( intf->dump == NULL ) {
+ sieve_code_dumpf(denv, "ERROR: DUMP STRING OPERAND");
+ return FALSE;
+ }
+
+ return intf->dump(denv, oprnd, address);
+}
+
+bool sieve_opr_string_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address,
+ const char *field_name)
+{
+ struct sieve_operand operand;
+
+ sieve_code_mark(denv);
+
+ if ( !sieve_operand_read(denv->sblock, address, field_name, &operand) ) {
+ sieve_code_dumpf(denv, "ERROR: INVALID OPERAND");
+ return FALSE;
+ }
+
+ return sieve_opr_string_dump_data(denv, &operand, address, field_name);
+}
+
+bool sieve_opr_string_dump_ex
+(const struct sieve_dumptime_env *denv, sieve_size_t *address,
+ const char *field_name, const char *omitted_value)
+{
+ struct sieve_operand operand;
+
+ sieve_code_mark(denv);
+ if ( !sieve_operand_read(denv->sblock, address, field_name, &operand) ) {
+ sieve_code_dumpf(denv, "ERROR: INVALID OPERAND");
+ return FALSE;
+ }
+
+ if ( omitted_value != NULL && sieve_operand_is_omitted(&operand) ) {
+ if ( *omitted_value != '\0' )
+ sieve_code_dumpf(denv, "%s: %s", field_name, omitted_value);
+ return TRUE;
+ }
+
+ return sieve_opr_string_dump_data(denv, &operand, address, field_name);
+}
+
+int sieve_opr_string_read_data
+(const struct sieve_runtime_env *renv, struct sieve_operand *oprnd,
+ sieve_size_t *address, const char *field_name, string_t **str_r)
+{
+ const struct sieve_opr_string_interface *intf;
+
+ oprnd->field_name = field_name;
+
+ if ( !sieve_operand_is_string(oprnd) ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "expected string operand but found %s", sieve_operand_name(oprnd));
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ intf = (const struct sieve_opr_string_interface *) oprnd->def->interface;
+
+ if ( intf->read == NULL ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "string operand not implemented");
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ return intf->read(renv, oprnd, address, str_r);
+}
+
+int sieve_opr_string_read
+(const struct sieve_runtime_env *renv, sieve_size_t *address,
+ const char *field_name, string_t **str_r)
+{
+ struct sieve_operand operand;
+ int ret;
+
+ if ( (ret=sieve_operand_runtime_read(renv, address, field_name, &operand))
+ <= 0 )
+ return ret;
+
+ return sieve_opr_string_read_data(renv, &operand, address, field_name, str_r);
+}
+
+int sieve_opr_string_read_ex
+(const struct sieve_runtime_env *renv, sieve_size_t *address,
+ const char *field_name, bool optional, string_t **str_r, bool *literal_r)
+{
+ struct sieve_operand operand;
+ int ret;
+
+ if ( (ret=sieve_operand_runtime_read(renv, address, field_name, &operand))
+ <= 0 )
+ return ret;
+
+ if ( optional && sieve_operand_is_omitted(&operand) ) {
+ *str_r = NULL;
+ return 1;
+ }
+
+ if ( literal_r != NULL )
+ *literal_r = sieve_operand_is_string_literal(&operand);
+
+ return sieve_opr_string_read_data(renv, &operand, address, field_name, str_r);
+}
+
+static void _dump_string
+(const struct sieve_dumptime_env *denv, string_t *str,
+ const char *field_name)
+{
+ if ( str_len(str) > 80 ) {
+ if ( field_name != NULL )
+ sieve_code_dumpf(denv, "%s: STR[%ld] \"%s",
+ field_name, (long) str_len(str), str_sanitize(str_c(str), 80));
+ else
+ sieve_code_dumpf(denv, "STR[%ld] \"%s",
+ (long) str_len(str), str_sanitize(str_c(str), 80));
+ } else {
+ if ( field_name != NULL )
+ sieve_code_dumpf(denv, "%s: STR[%ld] \"%s\"",
+ field_name, (long) str_len(str), str_sanitize(str_c(str), 80));
+ else
+ sieve_code_dumpf(denv, "STR[%ld] \"%s\"",
+ (long) str_len(str), str_sanitize(str_c(str), 80));
+ }
+}
+
+bool opr_string_dump
+(const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address)
+{
+ string_t *str;
+
+ if ( sieve_binary_read_string(denv->sblock, address, &str) ) {
+ _dump_string(denv, str, oprnd->field_name);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int opr_string_read
+(const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, string_t **str_r)
+{
+ if ( !sieve_binary_read_string(renv->sblock, address, str_r) ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "invalid string operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+/* String list */
+
+void sieve_opr_stringlist_emit_start
+(struct sieve_binary_block *sblock, unsigned int listlen, void **context)
+{
+ sieve_size_t *end_offset = t_new(sieve_size_t, 1);
+
+ /* Emit byte identifying the type of operand */
+ (void) sieve_operand_emit(sblock, NULL, &stringlist_operand);
+
+ /* Give the interpreter an easy way to skip over this string list */
+ *end_offset = sieve_binary_emit_offset(sblock, 0);
+ *context = (void *) end_offset;
+
+ /* Emit the length of the list */
+ (void) sieve_binary_emit_unsigned(sblock, listlen);
+}
+
+void sieve_opr_stringlist_emit_item
+(struct sieve_binary_block *sblock, void *context ATTR_UNUSED, string_t *item)
+{
+ (void) sieve_opr_string_emit(sblock, item);
+}
+
+void sieve_opr_stringlist_emit_end
+(struct sieve_binary_block *sblock, void *context)
+{
+ sieve_size_t *end_offset = (sieve_size_t *) context;
+
+ (void) sieve_binary_resolve_offset(sblock, *end_offset);
+}
+
+bool sieve_opr_stringlist_dump_data
+(const struct sieve_dumptime_env *denv, struct sieve_operand *oprnd,
+ sieve_size_t *address, const char *field_name)
+{
+ if ( oprnd == NULL || oprnd->def == NULL )
+ return FALSE;
+
+ oprnd->field_name = field_name;
+
+ if ( oprnd->def->class == &stringlist_class ) {
+ const struct sieve_opr_stringlist_interface *intf =
+ (const struct sieve_opr_stringlist_interface *) oprnd->def->interface;
+
+ if ( intf->dump == NULL )
+ return FALSE;
+
+ return intf->dump(denv, oprnd, address);
+ } else if ( oprnd->def->class == &string_class ) {
+ const struct sieve_opr_string_interface *intf =
+ (const struct sieve_opr_string_interface *) oprnd->def->interface;
+
+ if ( intf->dump == NULL )
+ return FALSE;
+
+ return intf->dump(denv, oprnd, address);
+ }
+
+ return FALSE;
+}
+
+bool sieve_opr_stringlist_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address,
+ const char *field_name)
+{
+ struct sieve_operand operand;
+
+ sieve_code_mark(denv);
+
+ if ( !sieve_operand_read(denv->sblock, address, field_name, &operand) ) {
+ return FALSE;
+ }
+
+ return sieve_opr_stringlist_dump_data(denv, &operand, address, field_name);
+}
+
+bool sieve_opr_stringlist_dump_ex
+(const struct sieve_dumptime_env *denv, sieve_size_t *address,
+ const char *field_name, const char *omitted_value)
+{
+ struct sieve_operand operand;
+
+ sieve_code_mark(denv);
+
+ if ( !sieve_operand_read(denv->sblock, address, field_name, &operand) ) {
+ return FALSE;
+ }
+
+ if ( omitted_value != NULL && sieve_operand_is_omitted(&operand) ) {
+ if ( *omitted_value != '\0' )
+ sieve_code_dumpf(denv, "%s: %s", field_name, omitted_value);
+ return TRUE;
+ }
+
+ return sieve_opr_stringlist_dump_data(denv, &operand, address, field_name);
+}
+
+int sieve_opr_stringlist_read_data
+(const struct sieve_runtime_env *renv, struct sieve_operand *oprnd,
+ sieve_size_t *address, const char *field_name,
+ struct sieve_stringlist **strlist_r)
+{
+ if ( oprnd == NULL || oprnd->def == NULL )
+ return SIEVE_EXEC_FAILURE;
+
+ oprnd->field_name = field_name;
+
+ if ( oprnd->def->class == &stringlist_class ) {
+ const struct sieve_opr_stringlist_interface *intf =
+ (const struct sieve_opr_stringlist_interface *) oprnd->def->interface;
+ int ret;
+
+ if ( intf->read == NULL ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "stringlist operand not implemented");
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ if ( (ret=intf->read(renv, oprnd, address, strlist_r)) <= 0 )
+ return ret;
+
+ return SIEVE_EXEC_OK;
+ } else if ( oprnd->def->class == &string_class ) {
+ /* Special case, accept single string as string list as well. */
+ const struct sieve_opr_string_interface *intf =
+ (const struct sieve_opr_string_interface *) oprnd->def->interface;
+ int ret;
+
+ if ( intf->read == NULL ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "stringlist string operand not implemented");
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ if ( strlist_r == NULL ) {
+ if ( (ret=intf->read(renv, oprnd, address, NULL)) <= 0 )
+ return ret;
+ } else {
+ string_t *stritem;
+ if ( (ret=intf->read(renv, oprnd, address, &stritem)) <= 0 )
+ return ret;
+
+ *strlist_r = sieve_single_stringlist_create
+ (renv, stritem, FALSE);
+ }
+ return SIEVE_EXEC_OK;
+ }
+
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "expected stringlist or string operand but found %s",
+ sieve_operand_name(oprnd));
+ return SIEVE_EXEC_BIN_CORRUPT;
+}
+
+int sieve_opr_stringlist_read
+(const struct sieve_runtime_env *renv, sieve_size_t *address,
+ const char *field_name, struct sieve_stringlist **strlist_r)
+{
+ struct sieve_operand operand;
+ int ret;
+
+ if ( (ret=sieve_operand_runtime_read(renv, address, field_name, &operand))
+ <= 0 )
+ return ret;
+
+ return sieve_opr_stringlist_read_data
+ (renv, &operand, address, field_name, strlist_r);
+}
+
+int sieve_opr_stringlist_read_ex
+(const struct sieve_runtime_env *renv, sieve_size_t *address,
+ const char *field_name, bool optional, struct sieve_stringlist **strlist_r)
+{
+ struct sieve_operand operand;
+ int ret;
+
+ if ( (ret=sieve_operand_runtime_read(renv, address, field_name, &operand))
+ <= 0 )
+ return ret;
+
+ if ( optional && sieve_operand_is_omitted(&operand) ) {
+ *strlist_r = NULL;
+ return 1;
+ }
+
+ return sieve_opr_stringlist_read_data
+ (renv, &operand, address, field_name, strlist_r);
+}
+
+static bool opr_stringlist_dump
+(const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address)
+{
+ sieve_size_t pc = *address;
+ sieve_size_t end;
+ unsigned int length = 0;
+ sieve_offset_t end_offset;
+
+ if ( !sieve_binary_read_offset(denv->sblock, address, &end_offset) )
+ return FALSE;
+
+ end = pc + end_offset;
+
+ if ( !sieve_binary_read_unsigned(denv->sblock, address, &length) )
+ return FALSE;
+
+ return sieve_code_stringlist_dump
+ (denv, address, length, end, oprnd->field_name);
+}
+
+static int opr_stringlist_read
+(const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, struct sieve_stringlist **strlist_r)
+{
+ sieve_size_t pc = *address;
+ sieve_size_t end;
+ unsigned int length = 0;
+ sieve_offset_t end_offset;
+
+ if ( !sieve_binary_read_offset(renv->sblock, address, &end_offset) ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "stringlist corrupt: invalid end offset");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ end = pc + end_offset;
+
+ if ( !sieve_binary_read_unsigned(renv->sblock, address, &length) ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "stringlist corrupt: invalid length data");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if ( strlist_r != NULL )
+ *strlist_r = sieve_code_stringlist_create
+ (renv, *address, (unsigned int) length, end);
+
+ /* Skip over the string list for now */
+ *address = end;
+
+ return SIEVE_EXEC_OK;
+}
+
+/* Catenated String */
+
+void sieve_opr_catenated_string_emit
+(struct sieve_binary_block *sblock, unsigned int elements)
+{
+ (void) sieve_operand_emit(sblock, NULL, &catenated_string_operand);
+ (void) sieve_binary_emit_unsigned(sblock, elements);
+}
+
+static bool opr_catenated_string_dump
+(const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address)
+{
+ unsigned int elements = 0;
+ unsigned int i;
+
+ if ( !sieve_binary_read_unsigned(denv->sblock, address, &elements) )
+ return FALSE;
+
+ if ( oprnd->field_name != NULL )
+ sieve_code_dumpf(denv, "%s: CAT-STR [%ld]:",
+ oprnd->field_name, (long) elements);
+ else
+ sieve_code_dumpf(denv, "CAT-STR [%ld]:", (long) elements);
+
+ sieve_code_descend(denv);
+ for ( i = 0; i < (unsigned int) elements; i++ ) {
+ if ( !sieve_opr_string_dump(denv, address, NULL) )
+ return FALSE;
+ }
+ sieve_code_ascend(denv);
+
+ return TRUE;
+}
+
+static int opr_catenated_string_read
+(const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, string_t **str)
+{
+ unsigned int elements = 0;
+ unsigned int i;
+ int ret;
+
+ if ( !sieve_binary_read_unsigned(renv->sblock, address, &elements) ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "catenated string corrupt: invalid element count data");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ /* Parameter str can be NULL if we are requested to only skip and not
+ * actually read the argument.
+ */
+ if ( str == NULL ) {
+ for ( i = 0; i < (unsigned int) elements; i++ ) {
+ if ( (ret=sieve_opr_string_read(renv, address, NULL, NULL)) <= 0 )
+ return ret;
+ }
+ } else {
+ string_t *strelm;
+ string_t **elm = &strelm;
+
+ *str = t_str_new(128);
+ for ( i = 0; i < (unsigned int) elements; i++ ) {
+
+ if ( (ret=sieve_opr_string_read(renv, address, NULL, elm)) <= 0 )
+ return ret;
+
+ if ( elm != NULL ) {
+ str_append_str(*str, strelm);
+
+ if ( str_len(*str) > SIEVE_MAX_STRING_LEN ) {
+ str_truncate(*str, SIEVE_MAX_STRING_LEN);
+ elm = NULL;
+ }
+ }
+ }
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Core operations
+ */
+
+/* Forward declarations */
+
+static bool opc_jmp_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+
+static int opc_jmp_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+static int opc_jmptrue_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+static int opc_jmpfalse_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+/* Operation objects defined in this file */
+
+const struct sieve_operation_def sieve_jmp_operation = {
+ .mnemonic = "JMP",
+ .code = SIEVE_OPERATION_JMP,
+ .dump = opc_jmp_dump,
+ .execute = opc_jmp_execute
+};
+
+const struct sieve_operation_def sieve_jmptrue_operation = {
+ .mnemonic = "JMPTRUE",
+ .code = SIEVE_OPERATION_JMPTRUE,
+ .dump = opc_jmp_dump,
+ .execute = opc_jmptrue_execute
+};
+
+const struct sieve_operation_def sieve_jmpfalse_operation = {
+ .mnemonic = "JMPFALSE",
+ .code = SIEVE_OPERATION_JMPFALSE,
+ .dump = opc_jmp_dump,
+ .execute = opc_jmpfalse_execute
+};
+
+/* Operation objects defined in other files */
+
+extern const struct sieve_operation_def cmd_stop_operation;
+extern const struct sieve_operation_def cmd_keep_operation;
+extern const struct sieve_operation_def cmd_discard_operation;
+extern const struct sieve_operation_def cmd_redirect_operation;
+
+extern const struct sieve_operation_def tst_address_operation;
+extern const struct sieve_operation_def tst_header_operation;
+extern const struct sieve_operation_def tst_exists_operation;
+extern const struct sieve_operation_def tst_size_over_operation;
+extern const struct sieve_operation_def tst_size_under_operation;
+
+const struct sieve_operation_def *sieve_operations[] = {
+ NULL,
+
+ &sieve_jmp_operation,
+ &sieve_jmptrue_operation,
+ &sieve_jmpfalse_operation,
+
+ &cmd_stop_operation,
+ &cmd_keep_operation,
+ &cmd_discard_operation,
+ &cmd_redirect_operation,
+
+ &tst_address_operation,
+ &tst_header_operation,
+ &tst_exists_operation,
+ &tst_size_over_operation,
+ &tst_size_under_operation
+};
+
+const unsigned int sieve_operation_count =
+ N_ELEMENTS(sieve_operations);
+
+/*
+ * Operation functions
+ */
+
+sieve_size_t sieve_operation_emit
+(struct sieve_binary_block *sblock, const struct sieve_extension *ext,
+ const struct sieve_operation_def *op_def)
+{
+ sieve_size_t address;
+
+ if ( ext != NULL ) {
+ i_assert( op_def->ext_def != NULL );
+ address = sieve_binary_emit_extension
+ (sblock, ext, sieve_operation_count);
+
+ sieve_binary_emit_extension_object
+ (sblock, &op_def->ext_def->operations, op_def->code);
+ return address;
+ }
+
+ i_assert( op_def->ext_def == NULL );
+ return sieve_binary_emit_byte(sblock, op_def->code);
+}
+
+bool sieve_operation_read
+(struct sieve_binary_block *sblock, sieve_size_t *address,
+ struct sieve_operation *oprtn)
+{
+ unsigned int code = sieve_operation_count;
+
+ oprtn->address = *address;
+ oprtn->def = NULL;
+ oprtn->ext = NULL;
+
+ if ( !sieve_binary_read_extension(sblock, address, &code, &oprtn->ext) )
+ return FALSE;
+
+ if ( oprtn->ext == NULL ) {
+ if ( code < sieve_operation_count ) {
+ oprtn->def = sieve_operations[code];
+ }
+
+ return ( oprtn->def != NULL );
+ }
+
+ oprtn->def = (const struct sieve_operation_def *)
+ sieve_binary_read_extension_object(sblock, address,
+ &oprtn->ext->def->operations);
+
+ return ( oprtn->def != NULL );
+}
+
+/*
+ * Jump operations
+ */
+
+/* Code dump */
+
+static bool opc_jmp_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ const struct sieve_operation *oprtn = denv->oprtn;
+ unsigned int pc = *address;
+ sieve_offset_t offset;
+
+ if ( sieve_binary_read_offset(denv->sblock, address, &offset) )
+ sieve_code_dumpf(denv, "%s %d [%08x]",
+ sieve_operation_mnemonic(oprtn), offset, pc + offset);
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Code execution */
+
+static int opc_jmp_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address ATTR_UNUSED)
+{
+ return sieve_interpreter_program_jump(renv->interp, TRUE, FALSE);
+}
+
+static int opc_jmptrue_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address ATTR_UNUSED)
+{
+ bool result = sieve_interpreter_get_test_result(renv->interp);
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "jump if result is true");
+ sieve_runtime_trace_descend(renv);
+
+ return sieve_interpreter_program_jump(renv->interp, result, FALSE);
+}
+
+static int opc_jmpfalse_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address ATTR_UNUSED)
+{
+ bool result = sieve_interpreter_get_test_result(renv->interp);
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "jump if result is false");
+ sieve_runtime_trace_descend(renv);
+
+ return sieve_interpreter_program_jump(renv->interp, !result, FALSE);
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-code.h b/pigeonhole/src/lib-sieve/sieve-code.h
new file mode 100644
index 0000000..00bf68b
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-code.h
@@ -0,0 +1,351 @@
+#ifndef SIEVE_CODE_H
+#define SIEVE_CODE_H
+
+#include "lib.h"
+#include "buffer.h"
+#include "mempool.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-runtime.h"
+#include "sieve-runtime-trace.h"
+#include "sieve-dump.h"
+
+/*
+ * Operand object
+ */
+
+struct sieve_operand_class {
+ const char *name;
+};
+
+struct sieve_operand_def {
+ const char *name;
+
+ const struct sieve_extension_def *ext_def;
+ unsigned int code;
+
+ const struct sieve_operand_class *class;
+ const void *interface;
+};
+
+struct sieve_operand {
+ const struct sieve_operand_def *def;
+ const struct sieve_extension *ext;
+ sieve_size_t address;
+ const char *field_name;
+};
+
+#define sieve_operand_name(opr) \
+ ( (opr)->def == NULL ? "(NULL)" : (opr)->def->name )
+#define sieve_operand_is(opr, definition) \
+ ( (opr)->def == &(definition) )
+
+sieve_size_t sieve_operand_emit
+ (struct sieve_binary_block *sblock, const struct sieve_extension *ext,
+ const struct sieve_operand_def *oprnd);
+bool sieve_operand_read
+ (struct sieve_binary_block *sblock, sieve_size_t *address,
+ const char *field_name, struct sieve_operand *oprnd);
+
+static inline int sieve_operand_runtime_read
+(const struct sieve_runtime_env *renv, sieve_size_t *address,
+ const char *field_name, struct sieve_operand *operand)
+{
+ if ( !sieve_operand_read(renv->sblock, address, field_name, operand) ) {
+ sieve_runtime_trace_operand_error(renv, operand, "invalid operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Optional operands
+ */
+
+int sieve_opr_optional_next
+(struct sieve_binary_block *sblock, sieve_size_t *address,
+ signed int *opt_code);
+
+static inline int sieve_opr_optional_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address,
+ signed int *opt_code)
+{
+ sieve_size_t pc = *address;
+ int ret;
+
+ if ( (ret=sieve_opr_optional_next(denv->sblock, address, opt_code)) <= 0 )
+ return ret;
+
+ sieve_code_mark_specific(denv, pc);
+ return ret;
+}
+
+static inline int sieve_opr_optional_read
+(const struct sieve_runtime_env *renv, sieve_size_t *address,
+ signed int *opt_code)
+{
+ int ret;
+
+ if ( (ret=sieve_opr_optional_next(renv->sblock, address, opt_code)) < 0 )
+ sieve_runtime_trace_error(renv, "invalid optional operand code");
+
+ return ret;
+}
+
+/*
+ * Core operands
+ */
+
+/* Operand codes */
+
+enum sieve_core_operand {
+ SIEVE_OPERAND_OPTIONAL = 0x00,
+ SIEVE_OPERAND_NUMBER,
+ SIEVE_OPERAND_STRING,
+ SIEVE_OPERAND_STRING_LIST,
+ SIEVE_OPERAND_COMPARATOR,
+ SIEVE_OPERAND_MATCH_TYPE,
+ SIEVE_OPERAND_ADDRESS_PART,
+ SIEVE_OPERAND_CATENATED_STRING,
+
+ SIEVE_OPERAND_CUSTOM
+};
+
+/* Operand classes */
+
+extern const struct sieve_operand_class number_class;
+extern const struct sieve_operand_class string_class;
+extern const struct sieve_operand_class stringlist_class;
+
+/* Operand objects */
+
+extern const struct sieve_operand_def omitted_operand;
+extern const struct sieve_operand_def number_operand;
+extern const struct sieve_operand_def string_operand;
+extern const struct sieve_operand_def stringlist_operand;
+extern const struct sieve_operand_def catenated_string_operand;
+
+extern const struct sieve_operand_def *sieve_operands[];
+extern const unsigned int sieve_operand_count;
+
+/* Operand object interfaces */
+
+struct sieve_opr_number_interface {
+ bool (*dump)
+ (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address);
+ int (*read)
+ (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, sieve_number_t *number_r);
+};
+
+struct sieve_opr_string_interface {
+ bool (*dump)
+ (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address);
+ int (*read)
+ (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, string_t **str_r);
+};
+
+struct sieve_opr_stringlist_interface {
+ bool (*dump)
+ (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address);
+ int (*read)
+ (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, struct sieve_stringlist **strlist_r);
+};
+
+/*
+ * Core operand functions
+ */
+
+/* Omitted */
+
+void sieve_opr_omitted_emit(struct sieve_binary_block *sblock);
+
+static inline bool sieve_operand_is_omitted
+(const struct sieve_operand *operand)
+{
+ return ( operand != NULL && operand->def != NULL &&
+ operand->def == &omitted_operand );
+}
+
+/* Number */
+
+void sieve_opr_number_emit
+ (struct sieve_binary_block *sblock, sieve_number_t number);
+bool sieve_opr_number_dump_data
+ (const struct sieve_dumptime_env *denv, struct sieve_operand *operand,
+ sieve_size_t *address, const char *field_name);
+bool sieve_opr_number_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address,
+ const char *field_name);
+int sieve_opr_number_read_data
+ (const struct sieve_runtime_env *renv, struct sieve_operand *operand,
+ sieve_size_t *address, const char *field_name, sieve_number_t *number_r);
+int sieve_opr_number_read
+ (const struct sieve_runtime_env *renv, sieve_size_t *address,
+ const char *field_name, sieve_number_t *number_r);
+
+static inline bool sieve_operand_is_number
+(const struct sieve_operand *operand)
+{
+ return ( operand != NULL && operand->def != NULL &&
+ operand->def->class == &number_class );
+}
+
+/* String */
+
+void sieve_opr_string_emit
+ (struct sieve_binary_block *sblock, string_t *str);
+bool sieve_opr_string_dump_data
+ (const struct sieve_dumptime_env *denv, struct sieve_operand *operand,
+ sieve_size_t *address, const char *field_name);
+bool sieve_opr_string_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address,
+ const char *field_name);
+bool sieve_opr_string_dump_ex
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address,
+ const char *field_name, const char *omitted_value);
+int sieve_opr_string_read_data
+ (const struct sieve_runtime_env *renv, struct sieve_operand *operand,
+ sieve_size_t *address, const char *field_name, string_t **str_r);
+int sieve_opr_string_read
+ (const struct sieve_runtime_env *renv, sieve_size_t *address,
+ const char *field_name, string_t **str_r);
+int sieve_opr_string_read_ex
+ (const struct sieve_runtime_env *renv, sieve_size_t *address,
+ const char *field_name, bool optional, string_t **str_r, bool *literal_r);
+
+static inline bool sieve_operand_is_string
+(const struct sieve_operand *operand)
+{
+ return ( operand != NULL && operand->def != NULL &&
+ operand->def->class == &string_class );
+}
+
+static inline bool sieve_operand_is_string_literal
+(const struct sieve_operand *operand)
+{
+ return ( operand != NULL && sieve_operand_is(operand, string_operand) );
+}
+
+/* String list */
+
+void sieve_opr_stringlist_emit_start
+ (struct sieve_binary_block *sblock, unsigned int listlen, void **context);
+void sieve_opr_stringlist_emit_item
+ (struct sieve_binary_block *sblock, void *context ATTR_UNUSED,
+ string_t *item);
+void sieve_opr_stringlist_emit_end
+ (struct sieve_binary_block *sblock, void *context);
+bool sieve_opr_stringlist_dump_data
+ (const struct sieve_dumptime_env *denv, struct sieve_operand *operand,
+ sieve_size_t *address, const char *field_name);
+bool sieve_opr_stringlist_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address,
+ const char *field_name);
+bool sieve_opr_stringlist_dump_ex
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address,
+ const char *field_name, const char *omitted_value);
+int sieve_opr_stringlist_read_data
+ (const struct sieve_runtime_env *renv, struct sieve_operand *operand,
+ sieve_size_t *address, const char *field_name,
+ struct sieve_stringlist **strlist_r);
+int sieve_opr_stringlist_read
+ (const struct sieve_runtime_env *renv, sieve_size_t *address,
+ const char *field_name, struct sieve_stringlist **strlist_r);
+int sieve_opr_stringlist_read_ex
+ (const struct sieve_runtime_env *renv, sieve_size_t *address,
+ const char *field_name, bool optional, struct sieve_stringlist **strlist_r);
+
+static inline bool sieve_operand_is_stringlist
+(const struct sieve_operand *operand)
+{
+ return ( operand != NULL && operand->def != NULL &&
+ (operand->def->class == &stringlist_class ||
+ operand->def->class == &string_class) );
+}
+
+/* Catenated string */
+
+void sieve_opr_catenated_string_emit
+ (struct sieve_binary_block *sblock, unsigned int elements);
+
+/*
+ * Operation object
+ */
+
+struct sieve_operation_def {
+ const char *mnemonic;
+
+ const struct sieve_extension_def *ext_def;
+ unsigned int code;
+
+ bool (*dump)
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+ int (*execute)
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+};
+
+struct sieve_operation {
+ const struct sieve_operation_def *def;
+ const struct sieve_extension *ext;
+
+ sieve_size_t address;
+};
+
+#define sieve_operation_is(oprtn, definition) \
+ ( (oprtn)->def == &(definition) )
+#define sieve_operation_mnemonic(oprtn) \
+ ( (oprtn)->def == NULL ? "(NULL)" : (oprtn)->def->mnemonic )
+
+sieve_size_t sieve_operation_emit
+ (struct sieve_binary_block *sblock, const struct sieve_extension *ext,
+ const struct sieve_operation_def *op_def);
+bool sieve_operation_read
+ (struct sieve_binary_block *sblock, sieve_size_t *address,
+ struct sieve_operation *oprtn);
+const char *sieve_operation_read_string
+ (struct sieve_binary_block *sblock, sieve_size_t *address);
+
+/*
+ * Core operations
+ */
+
+/* Opcodes */
+
+enum sieve_operation_code {
+ SIEVE_OPERATION_INVALID,
+ SIEVE_OPERATION_JMP,
+ SIEVE_OPERATION_JMPTRUE,
+ SIEVE_OPERATION_JMPFALSE,
+
+ SIEVE_OPERATION_STOP,
+ SIEVE_OPERATION_KEEP,
+ SIEVE_OPERATION_DISCARD,
+ SIEVE_OPERATION_REDIRECT,
+
+ SIEVE_OPERATION_ADDRESS,
+ SIEVE_OPERATION_HEADER,
+ SIEVE_OPERATION_EXISTS,
+ SIEVE_OPERATION_SIZE_OVER,
+ SIEVE_OPERATION_SIZE_UNDER,
+
+ SIEVE_OPERATION_CUSTOM
+};
+
+/* Operation objects */
+
+extern const struct sieve_operation_def sieve_jmp_operation;
+extern const struct sieve_operation_def sieve_jmptrue_operation;
+extern const struct sieve_operation_def sieve_jmpfalse_operation;
+
+extern const struct sieve_operation_def *sieve_operations[];
+extern const unsigned int sieve_operations_count;
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-commands.c b/pigeonhole/src/lib-sieve/sieve-commands.c
new file mode 100644
index 0000000..324b66d
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-commands.c
@@ -0,0 +1,403 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "str-sanitize.h"
+
+#include "rfc2822.h"
+
+#include "sieve-common.h"
+#include "sieve-ast.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-interpreter.h"
+
+/*
+ * Literal arguments
+ */
+
+/* Forward declarations */
+
+static bool arg_number_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *context);
+static bool arg_string_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *context);
+static bool arg_string_list_validate
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *context);
+static bool arg_string_list_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *context);
+
+/* Argument objects */
+
+const struct sieve_argument_def number_argument = {
+ .identifier = "@number",
+ .generate = arg_number_generate
+};
+
+const struct sieve_argument_def string_argument = {
+ .identifier = "@string",
+ .generate = arg_string_generate
+};
+
+const struct sieve_argument_def string_list_argument = {
+ .identifier = "@string-list",
+ .validate = arg_string_list_validate,
+ .generate = arg_string_list_generate
+};
+
+/* Argument implementations */
+
+static bool arg_number_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ sieve_opr_number_emit(cgenv->sblock, sieve_ast_argument_number(arg));
+
+ return TRUE;
+}
+
+static bool arg_string_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ sieve_opr_string_emit(cgenv->sblock, sieve_ast_argument_str(arg));
+
+ return TRUE;
+}
+
+static bool arg_string_list_validate
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *stritem;
+
+ stritem = sieve_ast_strlist_first(*arg);
+ while ( stritem != NULL ) {
+ if ( !sieve_validator_argument_activate(valdtr, cmd, stritem, FALSE) )
+ return FALSE;
+
+ stritem = sieve_ast_strlist_next(stritem);
+ }
+
+ return TRUE;
+}
+
+static bool emit_string_list_operand
+(const struct sieve_codegen_env *cgenv, const struct sieve_ast_argument *strlist,
+ struct sieve_command *cmd)
+{
+ void *list_context;
+ struct sieve_ast_argument *stritem;
+
+ sieve_opr_stringlist_emit_start
+ (cgenv->sblock, sieve_ast_strlist_count(strlist), &list_context);
+
+ stritem = sieve_ast_strlist_first(strlist);
+ while ( stritem != NULL ) {
+ if ( !sieve_generate_argument(cgenv, stritem, cmd) )
+ return FALSE;
+
+ stritem = sieve_ast_strlist_next(stritem);
+ }
+
+ sieve_opr_stringlist_emit_end(cgenv->sblock, list_context);
+
+ return TRUE;
+}
+
+static bool arg_string_list_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd)
+{
+ if ( sieve_ast_argument_type(arg) == SAAT_STRING ) {
+ return ( sieve_generate_argument(cgenv, arg, cmd) );
+
+ } else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) {
+ bool result = TRUE;
+
+ if ( sieve_ast_strlist_count(arg) == 1 )
+ return ( sieve_generate_argument
+ (cgenv, sieve_ast_strlist_first(arg), cmd) );
+ else {
+ T_BEGIN {
+ result=emit_string_list_operand(cgenv, arg, cmd);
+ } T_END;
+ }
+
+ return result;
+ }
+
+ return FALSE;
+}
+
+/*
+ * Abstract arguments
+ *
+ * (Generated by processing and not by parsing the grammar)
+ */
+
+/* Catenated string */
+
+struct sieve_arg_catenated_string {
+ struct sieve_ast_arg_list *str_parts;
+};
+
+struct sieve_arg_catenated_string *sieve_arg_catenated_string_create
+(struct sieve_ast_argument *orig_arg)
+{
+ pool_t pool = sieve_ast_pool(orig_arg->ast);
+ struct sieve_ast_arg_list *arglist;
+ struct sieve_arg_catenated_string *catstr;
+
+ arglist = sieve_ast_arg_list_create(pool);
+
+ catstr = p_new(pool, struct sieve_arg_catenated_string, 1);
+ catstr->str_parts = arglist;
+ (orig_arg)->argument->data = (void *) catstr;
+
+ return catstr;
+}
+
+void sieve_arg_catenated_string_add_element
+(struct sieve_arg_catenated_string *catstr,
+ struct sieve_ast_argument *element)
+{
+ sieve_ast_arg_list_add(catstr->str_parts, element);
+}
+
+#define _cat_string_first(catstr) __AST_LIST_FIRST((catstr)->str_parts)
+#define _cat_string_count(catstr) __AST_LIST_COUNT((catstr)->str_parts)
+#define _cat_string_next(item) __AST_LIST_NEXT(item)
+
+bool sieve_arg_catenated_string_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_arg_catenated_string *catstr =
+ (struct sieve_arg_catenated_string *) arg->argument->data;
+ struct sieve_ast_argument *strpart;
+
+ if ( _cat_string_count(catstr) == 1 )
+ sieve_generate_argument(cgenv, _cat_string_first(catstr), cmd);
+ else {
+ sieve_opr_catenated_string_emit(cgenv->sblock, _cat_string_count(catstr));
+
+ strpart = _cat_string_first(catstr);
+ while ( strpart != NULL ) {
+ if ( !sieve_generate_argument(cgenv, strpart, cmd) )
+ return FALSE;
+
+ strpart = _cat_string_next(strpart);
+ }
+ }
+
+ return TRUE;
+}
+
+/*
+ * Argument creation
+ */
+
+struct sieve_argument *sieve_argument_create
+(struct sieve_ast *ast, const struct sieve_argument_def *def,
+ const struct sieve_extension *ext, int id_code)
+{
+ struct sieve_argument *arg;
+ pool_t pool;
+
+ pool = sieve_ast_pool(ast);
+ arg = p_new(pool, struct sieve_argument, 1);
+ arg->def = def;
+ arg->ext = ext;
+ arg->id_code = id_code;
+
+ return arg;
+}
+
+/*
+ * Core tests and commands
+ */
+
+const struct sieve_command_def *sieve_core_tests[] = {
+ &tst_false, &tst_true,
+ &tst_not, &tst_anyof, &tst_allof,
+ &tst_address, &tst_header, &tst_exists, &tst_size
+};
+
+const unsigned int sieve_core_tests_count = N_ELEMENTS(sieve_core_tests);
+
+const struct sieve_command_def *sieve_core_commands[] = {
+ &cmd_require,
+ &cmd_stop, &cmd_if, &cmd_elsif, &cmd_else,
+ &cmd_keep, &cmd_discard, &cmd_redirect
+};
+
+const unsigned int sieve_core_commands_count = N_ELEMENTS(sieve_core_commands);
+
+/*
+ * Command context
+ */
+
+struct sieve_command *sieve_command_prev
+(struct sieve_command *cmd)
+{
+ struct sieve_ast_node *node = sieve_ast_node_prev(cmd->ast_node);
+
+ if ( node != NULL ) {
+ return node->command;
+ }
+
+ return NULL;
+}
+
+struct sieve_command *sieve_command_parent
+(struct sieve_command *cmd)
+{
+ struct sieve_ast_node *node = sieve_ast_node_parent(cmd->ast_node);
+
+ return ( node != NULL ? node->command : NULL );
+}
+
+struct sieve_command *sieve_command_create
+(struct sieve_ast_node *cmd_node, const struct sieve_extension *ext,
+ const struct sieve_command_def *cmd_def,
+ struct sieve_command_registration *cmd_reg)
+{
+ struct sieve_command *cmd;
+
+ cmd = p_new(sieve_ast_node_pool(cmd_node), struct sieve_command, 1);
+
+ cmd->ast_node = cmd_node;
+ cmd->def = cmd_def;
+ cmd->ext = ext;
+ cmd->reg = cmd_reg;
+
+ cmd->block_exit_command = NULL;
+
+ return cmd;
+}
+
+const char *sieve_command_def_type_name
+(const struct sieve_command_def *cmd_def)
+{
+ switch ( cmd_def->type ) {
+ case SCT_NONE: return "command of unspecified type (bug)";
+ case SCT_TEST: return "test";
+ case SCT_COMMAND: return "command";
+ case SCT_HYBRID: return "command or test";
+ default:
+ break;
+ }
+ return "??COMMAND-TYPE??";
+}
+
+const char *sieve_command_type_name
+ (const struct sieve_command *cmd)
+{
+ switch ( cmd->def->type ) {
+ case SCT_NONE: return "command of unspecified type (bug)";
+ case SCT_TEST: return "test";
+ case SCT_COMMAND: return "command";
+ case SCT_HYBRID:
+ if ( cmd->ast_node->type == SAT_TEST )
+ return "test";
+ return "command";
+ default:
+ break;
+ }
+ return "??COMMAND-TYPE??";
+}
+
+struct sieve_ast_argument *sieve_command_add_dynamic_tag
+(struct sieve_command *cmd, const struct sieve_extension *ext,
+ const struct sieve_argument_def *tag, int id_code)
+{
+ struct sieve_ast_argument *arg;
+
+ if ( cmd->first_positional != NULL )
+ arg = sieve_ast_argument_tag_insert
+ (cmd->first_positional, tag->identifier, cmd->ast_node->source_line);
+ else
+ arg = sieve_ast_argument_tag_create
+ (cmd->ast_node, tag->identifier, cmd->ast_node->source_line);
+
+ arg->argument = sieve_argument_create(cmd->ast_node->ast, tag, ext, id_code);
+
+ return arg;
+}
+
+struct sieve_ast_argument *sieve_command_find_argument
+(struct sieve_command *cmd, const struct sieve_argument_def *arg_def)
+{
+ struct sieve_ast_argument *arg = sieve_ast_argument_first(cmd->ast_node);
+
+ /* Visit tagged and optional arguments */
+ while ( arg != NULL ) {
+ if ( arg->argument != NULL && arg->argument->def == arg_def )
+ return arg;
+
+ arg = sieve_ast_argument_next(arg);
+ }
+
+ return arg;
+}
+
+/* Use this function with caution. The command commits to exiting the block.
+ * When it for some reason does not, the interpretation will break later on,
+ * because exiting jumps are not generated when they would otherwise be
+ * necessary.
+ */
+void sieve_command_exit_block_unconditionally
+ (struct sieve_command *cmd)
+{
+ struct sieve_command *parent = sieve_command_parent(cmd);
+
+ /* Only the first unconditional exit is of importance */
+ if ( parent != NULL && parent->block_exit_command == NULL )
+ parent->block_exit_command = cmd;
+}
+
+bool sieve_command_block_exits_unconditionally
+ (struct sieve_command *cmd)
+{
+ return ( cmd->block_exit_command != NULL );
+}
+
+/*
+ * Command utility functions
+ */
+
+/* NOTE: this may be moved */
+
+static int _verify_header_name_item
+(void *context, struct sieve_ast_argument *header)
+{
+ struct sieve_validator *valdtr = (struct sieve_validator *) context;
+ string_t *name = sieve_ast_argument_str(header);
+
+ if ( sieve_argument_is_string_literal(header) &&
+ !rfc2822_header_field_name_verify(str_c(name), str_len(name)) ) {
+ sieve_argument_validate_warning
+ (valdtr, header, "specified header field name '%s' is invalid",
+ str_sanitize(str_c(name), 80));
+
+ return 0;
+ }
+
+ return 1;
+}
+
+bool sieve_command_verify_headers_argument
+(struct sieve_validator *valdtr, struct sieve_ast_argument *headers)
+{
+ return ( sieve_ast_stringlist_map
+ (&headers, (void *) valdtr, _verify_header_name_item) >= 0 );
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-commands.h b/pigeonhole/src/lib-sieve/sieve-commands.h
new file mode 100644
index 0000000..f9b83e3
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-commands.h
@@ -0,0 +1,286 @@
+#ifndef SIEVE_COMMANDS_H
+#define SIEVE_COMMANDS_H
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-ast.h"
+
+/*
+ * Argument definition
+ */
+
+enum sieve_argument_flag {
+ /* More than one of this (type of) tagged argument is allowed */
+ SIEVE_ARGUMENT_FLAG_MULTIPLE = (1 << 0)
+};
+
+struct sieve_argument_def {
+ const char *identifier;
+ enum sieve_argument_flag flags;
+
+ bool (*is_instance_of)
+ (struct sieve_validator *valdtr, struct sieve_command *cmd,
+ const struct sieve_extension *ext, const char *identifier, void **data);
+
+ bool (*validate)
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+ bool (*validate_context)
+ (struct sieve_validator *valdtr, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd);
+ bool (*validate_persistent)
+ (struct sieve_validator *valdtr, struct sieve_command *cmd,
+ const struct sieve_extension *ext);
+
+ bool (*generate)
+ (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd);
+};
+
+/*
+ * Argument instance
+ */
+
+struct sieve_argument {
+ const struct sieve_argument_def *def;
+ const struct sieve_extension *ext;
+ int id_code;
+
+ /* Context data */
+ void *data;
+};
+
+#define sieve_argument_is(ast_arg, definition) \
+ ( (ast_arg)->argument->def == &(definition) )
+#define sieve_argument_ext(ast_arg) \
+ ( (ast_arg)->argument->ext )
+#define sieve_argument_identifier(ast_arg) \
+ ( (ast_arg)->argument->def->identifier )
+
+/* Utility macros */
+
+#define sieve_argument_is_string_literal(arg) \
+ ( (arg)->argument->def == &string_argument )
+
+/* Error handling */
+
+#define sieve_argument_validate_error(validator, arg_node, ...) \
+ sieve_validator_error(validator, \
+ ((arg_node) == NULL ? 0 : (arg_node)->source_line), \
+ __VA_ARGS__)
+#define sieve_argument_validate_warning(validator, arg_node, ...) \
+ sieve_validator_warning(validator, \
+ ((arg_node) == NULL ? 0 : (arg_node)->source_line), \
+ __VA_ARGS__)
+
+#define sieve_argument_generate_error(gentr, arg_node, ...) \
+ sieve_generator_error(gentr, \
+ ((arg_node) == NULL ? 0 : (arg_node)->source_line), \
+ __VA_ARGS__)
+#define sieve_argument_generate_warning(gentr, arg_node, ...) \
+ sieve_generator_warning(gentr, \
+ ((arg_node) == NULL ? 0 : (arg_node)->source_line), \
+ __VA_ARGS__)
+
+/* Argument API */
+
+struct sieve_argument *sieve_argument_create
+ (struct sieve_ast *ast, const struct sieve_argument_def *def,
+ const struct sieve_extension *ext, int id_code);
+
+/* Literal arguments */
+
+extern const struct sieve_argument_def number_argument;
+extern const struct sieve_argument_def string_argument;
+extern const struct sieve_argument_def string_list_argument;
+
+/* Catenated string argument */
+
+bool sieve_arg_catenated_string_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *context);
+
+struct sieve_arg_catenated_string;
+
+struct sieve_arg_catenated_string *sieve_arg_catenated_string_create
+ (struct sieve_ast_argument *orig_arg);
+void sieve_arg_catenated_string_add_element
+ (struct sieve_arg_catenated_string *strdata,
+ struct sieve_ast_argument *element);
+
+/*
+ * Command definition
+ */
+
+enum sieve_command_type {
+ SCT_NONE,
+ SCT_COMMAND,
+ SCT_TEST,
+ SCT_HYBRID
+};
+
+struct sieve_command_def {
+ const char *identifier;
+ enum sieve_command_type type;
+
+ /* High-level command syntax */
+ int positional_args;
+ int subtests;
+ bool block_allowed;
+ bool block_required;
+
+ bool (*registered)
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+ bool (*pre_validate)
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+ bool (*validate)
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+ bool (*validate_const)
+ (struct sieve_validator *valdtr, struct sieve_command *cmd,
+ int *const_current, int const_next);
+ bool (*generate)
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
+ bool (*control_generate)
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd,
+ struct sieve_jumplist *jumps, bool jump_true);
+};
+
+/*
+ * Command instance
+ */
+
+struct sieve_command {
+ const struct sieve_command_def *def;
+ const struct sieve_extension *ext;
+
+ /* The registration of this command in the validator (sieve-validator.h) */
+ struct sieve_command_registration *reg;
+
+ /* The ast node of this command */
+ struct sieve_ast_node *ast_node;
+
+ /* First positional argument, found during argument validation */
+ struct sieve_ast_argument *first_positional;
+
+ /* The child ast node that unconditionally exits this command's block */
+ struct sieve_command *block_exit_command;
+
+ /* Context data*/
+ void *data;
+};
+
+#define sieve_command_is(cmd, definition) \
+ ( (cmd)->def == &(definition) )
+#define sieve_command_identifier(cmd) \
+ ( (cmd)->def->identifier )
+
+#define sieve_commands_equal(cmd1, cmd2) \
+ ( (cmd1) != NULL && (cmd2) != NULL && (cmd1)->def == (cmd2)->def )
+
+/* Context API */
+
+struct sieve_command *sieve_command_create
+ (struct sieve_ast_node *cmd_node, const struct sieve_extension *ext,
+ const struct sieve_command_def *cmd_def,
+ struct sieve_command_registration *cmd_reg);
+
+const char *sieve_command_def_type_name
+ (const struct sieve_command_def *cmd_def);
+const char *sieve_command_type_name
+ (const struct sieve_command *cmd);
+
+struct sieve_command *sieve_command_prev
+ (struct sieve_command *cmd);
+struct sieve_command *sieve_command_parent
+ (struct sieve_command *cmd);
+
+struct sieve_ast_argument *sieve_command_add_dynamic_tag
+ (struct sieve_command *cmd, const struct sieve_extension *ext,
+ const struct sieve_argument_def *tag, int id_code);
+struct sieve_ast_argument *sieve_command_find_argument
+ (struct sieve_command *cmd, const struct sieve_argument_def *argument);
+
+void sieve_command_exit_block_unconditionally
+ (struct sieve_command *cmd);
+bool sieve_command_block_exits_unconditionally
+ (struct sieve_command *cmd);
+
+/* Error handling */
+
+#define sieve_command_validate_error(validator, context, ...) \
+ sieve_validator_error(validator, \
+ ((context) == NULL ? 0 : (context)->ast_node->source_line), \
+ __VA_ARGS__)
+#define sieve_command_validate_warning(validator, context, ...) \
+ sieve_validator_warning(validator, \
+ ((context) == NULL ? 0 : (context)->ast_node->source_line), \
+ __VA_ARGS__)
+
+#define sieve_command_generate_error(gentr, context, ...) \
+ sieve_generator_error(gentr, \
+ ((context) == NULL ? 0 : (context)->ast_node->source_line), \
+ __VA_ARGS__)
+#define sieve_command_generate_warning(gentr, context, ...) \
+ sieve_generator_warning(gentr, \
+ ((context) == NULL ? 0 : (context)->ast_node->source_line), \
+ __VA_ARGS__)
+
+/* Utility macros */
+
+#define sieve_command_pool(context) \
+ sieve_ast_node_pool((context)->ast_node)
+
+#define sieve_command_source_line(context) \
+ (context)->ast_node->source_line
+
+#define sieve_command_first_argument(context) \
+ sieve_ast_argument_first((context)->ast_node)
+
+#define sieve_command_is_toplevel(context) \
+ ( sieve_ast_node_type(sieve_ast_node_parent((context)->ast_node)) == SAT_ROOT )
+#define sieve_command_is_first(context) \
+ ( sieve_ast_node_prev((context)->ast_node) == NULL )
+
+/*
+ * Core commands
+ */
+
+extern const struct sieve_command_def cmd_require;
+extern const struct sieve_command_def cmd_stop;
+extern const struct sieve_command_def cmd_if;
+extern const struct sieve_command_def cmd_elsif;
+extern const struct sieve_command_def cmd_else;
+extern const struct sieve_command_def cmd_redirect;
+extern const struct sieve_command_def cmd_keep;
+extern const struct sieve_command_def cmd_discard;
+
+extern const struct sieve_command_def *sieve_core_commands[];
+extern const unsigned int sieve_core_commands_count;
+
+/*
+ * Core tests
+ */
+
+extern const struct sieve_command_def tst_true;
+extern const struct sieve_command_def tst_false;
+extern const struct sieve_command_def tst_not;
+extern const struct sieve_command_def tst_anyof;
+extern const struct sieve_command_def tst_allof;
+extern const struct sieve_command_def tst_address;
+extern const struct sieve_command_def tst_header;
+extern const struct sieve_command_def tst_exists;
+extern const struct sieve_command_def tst_size;
+
+extern const struct sieve_command_def *sieve_core_tests[];
+extern const unsigned int sieve_core_tests_count;
+
+/*
+ * Command utility functions
+ */
+
+bool sieve_command_verify_headers_argument
+(struct sieve_validator *valdtr, struct sieve_ast_argument *headers);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-common.h b/pigeonhole/src/lib-sieve/sieve-common.h
new file mode 100644
index 0000000..e79fb4d
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-common.h
@@ -0,0 +1,240 @@
+#ifndef SIEVE_COMMON_H
+#define SIEVE_COMMON_H
+
+#include "lib.h"
+
+#include "sieve.h"
+
+#include <sys/types.h>
+
+/*
+ * Types
+ */
+
+typedef size_t sieve_size_t;
+typedef uint32_t sieve_offset_t;
+typedef uint64_t sieve_number_t;
+
+#define SIEVE_MAX_NUMBER ((sieve_number_t)-1)
+#define SIEVE_PRI_NUMBER PRIu64
+
+/*
+ * Forward declarations
+ */
+
+/* sieve-error.h */
+struct sieve_error_handler;
+
+/* sieve-ast.h */
+enum sieve_ast_argument_type;
+
+struct sieve_ast;
+struct sieve_ast_node;
+struct sieve_ast_argument;
+
+/* sieve-commands.h */
+struct sieve_argument;
+struct sieve_argument_def;
+struct sieve_command;
+struct sieve_command_def;
+struct sieve_command_context;
+struct sieve_command_registration;
+
+/* sieve-stringlist.h */
+struct sieve_stringlist;
+
+/* sieve-code.h */
+struct sieve_operation_extension;
+
+/* sieve-lexer.h */
+struct sieve_lexer;
+
+/* sieve-parser.h */
+struct sieve_parser;
+
+/* sieve-validator.h */
+struct sieve_validator;
+
+/* sieve-generator.h */
+struct sieve_jumplist;
+struct sieve_generator;
+struct sieve_codegen_env;
+
+/* sieve-runtime.h */
+struct sieve_runtime_env;
+
+/* sieve-interpreter.h */
+struct sieve_interpreter;
+
+/* sieve-dump.h */
+struct sieve_dumptime_env;
+
+/* sieve-binary-dumper.h */
+struct sieve_binary_dumper;
+
+/* sieve-code-dumper.h */
+struct sieve_code_dumper;
+
+/* sieve-extension.h */
+struct sieve_extension;
+struct sieve_extension_def;
+struct sieve_extension_objects;
+
+/* sieve-code.h */
+struct sieve_operand;
+struct sieve_operand_def;
+struct sieve_operand_class;
+struct sieve_operation;
+struct sieve_coded_stringlist;
+
+/* sieve-binary.h */
+struct sieve_binary;
+struct sieve_binary_block;
+struct sieve_binary_debug_writer;
+struct sieve_binary_debug_reader;
+
+/* sieve-execute.h */
+struct sieve_execute;
+
+/* sieve-objects.h */
+struct sieve_object_def;
+struct sieve_object;
+
+/* sieve-comparator.h */
+struct sieve_comparator;
+
+/* sieve-match-types.h */
+struct sieve_match_type;
+
+/* sieve-match.h */
+struct sieve_match_context;
+
+/* sieve-address.h */
+struct sieve_address_list;
+
+/* sieve-address-parts.h */
+struct sieve_address_part_def;
+struct sieve_address_part;
+
+/* sieve-result.h */
+struct sieve_result;
+struct sieve_side_effects_list;
+struct sieve_result_print_env;
+
+/* sieve-actions.h */
+struct sieve_action_exec_env;
+struct sieve_action;
+struct sieve_action_def;
+struct sieve_side_effect;
+struct sieve_side_effect_def;
+
+/* sieve-script.h */
+struct sieve_script;
+struct sieve_script_sequence;
+
+/* sieve-storage.h */
+struct sieve_storage_class_registry;
+struct sieve_storage;
+
+/* sieve-message.h */
+struct sieve_message_context;
+struct sieve_message_override;
+struct sieve_message_override_def;
+
+/* sieve-plugins.h */
+struct sieve_plugin;
+
+/* sieve.c */
+struct sieve_ast *sieve_parse
+ (struct sieve_script *script, struct sieve_error_handler *ehandler,
+ enum sieve_error *error_r);
+bool sieve_validate
+ (struct sieve_ast *ast, struct sieve_error_handler *ehandler,
+ enum sieve_compile_flags flags, enum sieve_error *error_r);
+
+/*
+ * Parent category
+ */
+
+extern struct event_category event_category_sieve;
+
+/*
+ * Sieve engine instance
+ */
+
+#include "sieve-address-source.h"
+
+struct sieve_instance {
+ /* Main engine pool */
+ pool_t pool;
+
+ /* System environment */
+ const char *hostname;
+ const char *domainname;
+ const char *base_dir;
+ const char *temp_dir;
+
+ /* User environment */
+ const char *username;
+ const char *home_dir;
+
+ /* Flags */
+ enum sieve_flag flags;
+
+ /* Callbacks */
+ const struct sieve_callbacks *callbacks;
+ void *context;
+
+ /* Logging, events, and debug */
+ struct event *event;
+ bool debug;
+
+ /* Extension registry */
+ struct sieve_extension_registry *ext_reg;
+
+ /* Storage class registry */
+ struct sieve_storage_class_registry *storage_reg;
+
+ /* Plugin modules */
+ struct sieve_plugin *plugins;
+ enum sieve_env_location env_location;
+ enum sieve_delivery_phase delivery_phase;
+
+ /* Settings */
+ size_t max_script_size;
+ unsigned int max_actions;
+ unsigned int max_redirects;
+ unsigned int max_cpu_time_secs;
+ unsigned int resource_usage_timeout_secs;
+ const struct smtp_address *user_email, *user_email_implicit;
+ struct sieve_address_source redirect_from;
+ unsigned int redirect_duplicate_period;
+};
+
+/*
+ * Script trace log
+ */
+
+void sieve_trace_log_write_line
+ (struct sieve_trace_log *trace_log, const string_t *line)
+ ATTR_NULL(2);
+
+/*
+ * User e-mail address
+ */
+
+const struct smtp_address *sieve_get_user_email
+ (struct sieve_instance *svinst);
+
+/*
+ * Postmaster address
+ */
+
+const struct message_address *
+sieve_get_postmaster(const struct sieve_script_env *senv);
+const struct smtp_address *
+sieve_get_postmaster_smtp(const struct sieve_script_env *senv);
+const char *
+sieve_get_postmaster_address(const struct sieve_script_env *senv);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-comparators.c b/pigeonhole/src/lib-sieve/sieve-comparators.c
new file mode 100644
index 0000000..56c33ab
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-comparators.c
@@ -0,0 +1,260 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+#include "hash.h"
+#include "array.h"
+
+#include "sieve-extensions.h"
+#include "sieve-code.h"
+#include "sieve-commands.h"
+#include "sieve-binary.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "sieve-comparators.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * Core comparators
+ */
+
+const struct sieve_comparator_def *sieve_core_comparators[] = {
+ &i_octet_comparator, &i_ascii_casemap_comparator
+};
+
+const unsigned int sieve_core_comparators_count =
+ N_ELEMENTS(sieve_core_comparators);
+
+/*
+ * Comparator 'extension'
+ */
+
+static bool cmp_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def comparator_extension = {
+ .name = "@comparators",
+ .validator_load = cmp_validator_load
+};
+
+/*
+ * Validator context:
+ * name-based comparator registry.
+ */
+
+static struct sieve_validator_object_registry *_get_object_registry
+(struct sieve_validator *valdtr)
+{
+ struct sieve_instance *svinst;
+ const struct sieve_extension *mcht_ext;
+
+ svinst = sieve_validator_svinst(valdtr);
+ mcht_ext = sieve_get_comparator_extension(svinst);
+ return sieve_validator_object_registry_get(valdtr, mcht_ext);
+}
+
+void sieve_comparator_register
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ const struct sieve_comparator_def *cmp)
+{
+ struct sieve_validator_object_registry *regs = _get_object_registry(valdtr);
+
+ sieve_validator_object_registry_add(regs, ext, &cmp->obj_def);
+}
+
+static struct sieve_comparator *sieve_comparator_create
+(struct sieve_validator *valdtr, struct sieve_command *cmd,
+ const char *identifier)
+{
+ struct sieve_validator_object_registry *regs = _get_object_registry(valdtr);
+ struct sieve_object object;
+ struct sieve_comparator *cmp;
+
+ if ( !sieve_validator_object_registry_find(regs, identifier, &object) )
+ return NULL;
+
+ cmp = p_new(sieve_command_pool(cmd), struct sieve_comparator, 1);
+ cmp->object = object;
+ cmp->def = (const struct sieve_comparator_def *) object.def;
+
+ return cmp;
+}
+
+bool cmp_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ struct sieve_validator_object_registry *regs =
+ sieve_validator_object_registry_init(valdtr, ext);
+ unsigned int i;
+
+ /* Register core comparators */
+ for ( i = 0; i < sieve_core_comparators_count; i++ ) {
+ sieve_validator_object_registry_add
+ (regs, NULL, &(sieve_core_comparators[i]->obj_def));
+ }
+
+ return TRUE;
+}
+
+/*
+ * Comparator tagged argument
+ */
+
+/* Forward declarations */
+
+static bool tag_comparator_validate
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool tag_comparator_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd);
+
+/* Argument object */
+
+const struct sieve_argument_def comparator_tag = {
+ .identifier = "comparator",
+ .validate = tag_comparator_validate,
+ .generate = tag_comparator_generate
+};
+
+/* Argument implementation */
+
+static bool tag_comparator_validate
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+ const struct sieve_comparator *cmp;
+
+ /* Skip tag */
+ *arg = sieve_ast_argument_next(*arg);
+
+ /* Check syntax:
+ * ":comparator" <comparator-name: string>
+ */
+ if ( !sieve_validate_tag_parameter
+ (valdtr, cmd, tag, *arg, NULL, 0, SAAT_STRING, FALSE) ) {
+ return FALSE;
+ }
+
+ /* FIXME: We can currently only handle string literal argument, so
+ * variables are not allowed.
+ */
+ if ( !sieve_argument_is_string_literal(*arg) ) {
+ sieve_argument_validate_error(valdtr, *arg,
+ "this Sieve implementation currently only supports "
+ "a literal string argument for the :comparator tag");
+ return FALSE;
+ }
+
+ /* Get comparator from registry */
+ cmp = sieve_comparator_create(valdtr, cmd, sieve_ast_argument_strc(*arg));
+
+ if ( cmp == NULL ) {
+ sieve_argument_validate_error(valdtr, *arg,
+ "unknown comparator '%s'",
+ str_sanitize(sieve_ast_argument_strc(*arg),80));
+
+ return FALSE;
+ }
+
+ /* String argument not needed during code generation, so detach it from
+ * argument list
+ */
+ *arg = sieve_ast_arguments_detach(*arg, 1);
+
+ /* Store comparator in context */
+ tag->argument->data = (void *) cmp;
+
+ return TRUE;
+}
+
+static bool tag_comparator_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ const struct sieve_comparator *cmp =
+ (const struct sieve_comparator *) arg->argument->data;
+
+ sieve_opr_comparator_emit(cgenv->sblock, cmp);
+
+ return TRUE;
+}
+
+/* Functions to enable and evaluate comparator tag for commands */
+
+void sieve_comparators_link_tag
+(struct sieve_validator *valdtr, struct sieve_command_registration *cmd_reg,
+ int id_code)
+{
+ struct sieve_instance *svinst;
+ const struct sieve_extension *mcht_ext;
+
+ svinst = sieve_validator_svinst(valdtr);
+ mcht_ext = sieve_get_comparator_extension(svinst);
+
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, mcht_ext, &comparator_tag, id_code);
+}
+
+bool sieve_comparator_tag_is
+(struct sieve_ast_argument *tag, const struct sieve_comparator_def *cmp_def)
+{
+ const struct sieve_comparator *cmp;
+
+ if ( !sieve_argument_is(tag, comparator_tag) )
+ return FALSE;
+
+ cmp = (const struct sieve_comparator *) tag->argument->data;
+
+ return ( cmp->def == cmp_def );
+}
+
+const struct sieve_comparator *sieve_comparator_tag_get
+(struct sieve_ast_argument *tag)
+{
+ if ( !sieve_argument_is(tag, comparator_tag) )
+ return NULL;
+
+
+ return (const struct sieve_comparator *) tag->argument->data;
+}
+
+/*
+ * Comparator coding
+ */
+
+const struct sieve_operand_class sieve_comparator_operand_class =
+ { "comparator" };
+
+static const struct sieve_extension_objects core_comparators =
+ SIEVE_EXT_DEFINE_COMPARATORS(sieve_core_comparators);
+
+const struct sieve_operand_def comparator_operand = {
+ .name = "comparator",
+ .code = SIEVE_OPERAND_COMPARATOR,
+ .class = &sieve_comparator_operand_class,
+ .interface = &core_comparators
+};
+
+/*
+ * Trivial/Common comparator method implementations
+ */
+
+bool sieve_comparator_octet_skip
+ (const struct sieve_comparator *cmp ATTR_UNUSED,
+ const char **val, const char *val_end)
+{
+ if ( *val < val_end ) {
+ (*val)++;
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-comparators.h b/pigeonhole/src/lib-sieve/sieve-comparators.h
new file mode 100644
index 0000000..fdfb9ee
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-comparators.h
@@ -0,0 +1,153 @@
+#ifndef SIEVE_COMPARATORS_H
+#define SIEVE_COMPARATORS_H
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-objects.h"
+#include "sieve-code.h"
+
+/*
+ * Core comparators
+ */
+
+enum sieve_comparator_code {
+ SIEVE_COMPARATOR_I_OCTET,
+ SIEVE_COMPARATOR_I_ASCII_CASEMAP,
+ SIEVE_COMPARATOR_CUSTOM
+};
+
+extern const struct sieve_comparator_def i_octet_comparator;
+extern const struct sieve_comparator_def i_ascii_casemap_comparator;
+
+/*
+ * Comparator flags
+ */
+
+enum sieve_comparator_flags {
+ SIEVE_COMPARATOR_FLAG_ORDERING = (1 << 0),
+ SIEVE_COMPARATOR_FLAG_EQUALITY = (1 << 1),
+ SIEVE_COMPARATOR_FLAG_PREFIX_MATCH = (1 << 2),
+ SIEVE_COMPARATOR_FLAG_SUBSTRING_MATCH = (1 << 3),
+};
+
+/*
+ * Comparator definition
+ */
+
+struct sieve_comparator_def {
+ struct sieve_object_def obj_def;
+
+ unsigned int flags;
+
+ /* Equality and ordering */
+
+ int (*compare)(const struct sieve_comparator *cmp,
+ const char *val1, size_t val1_size,
+ const char *val2, size_t val2_size);
+
+ /* Prefix and substring match */
+
+ bool (*char_match)(const struct sieve_comparator *cmp,
+ const char **val, const char *val_end,
+ const char **key, const char *key_end);
+ bool (*char_skip)(const struct sieve_comparator *cmp,
+ const char **val, const char *val_end);
+};
+
+/*
+ * Comparator instance
+ */
+
+struct sieve_comparator {
+ struct sieve_object object;
+
+ const struct sieve_comparator_def *def;
+};
+
+#define SIEVE_COMPARATOR_DEFAULT(definition) \
+ { SIEVE_OBJECT_DEFAULT(definition), &(definition) }
+
+#define sieve_comparator_name(cmp) \
+ ( (cmp)->object.def->identifier )
+#define sieve_comparator_is(cmp, definition) \
+ ( (cmp)->def == &(definition) )
+
+static inline const struct sieve_comparator *sieve_comparator_copy
+(pool_t pool, const struct sieve_comparator *cmp_orig)
+{
+ struct sieve_comparator *cmp = p_new(pool, struct sieve_comparator, 1);
+
+ *cmp = *cmp_orig;
+
+ return cmp;
+}
+
+/*
+ * Comparator tagged argument
+ */
+
+extern const struct sieve_argument_def comparator_tag;
+
+static inline bool sieve_argument_is_comparator
+(struct sieve_ast_argument *arg)
+{
+ return ( arg->argument != NULL &&
+ (arg->argument->def == &comparator_tag) );
+}
+
+void sieve_comparators_link_tag
+ (struct sieve_validator *validator,
+ struct sieve_command_registration *cmd_reg, int id_code);
+bool sieve_comparator_tag_is
+ (struct sieve_ast_argument *tag, const struct sieve_comparator_def *cmp);
+const struct sieve_comparator *sieve_comparator_tag_get
+ (struct sieve_ast_argument *tag);
+
+void sieve_comparator_register
+ (struct sieve_validator *validator, const struct sieve_extension *ext,
+ const struct sieve_comparator_def *cmp);
+
+/*
+ * Comparator operand
+ */
+
+#define SIEVE_EXT_DEFINE_COMPARATOR(OP) SIEVE_EXT_DEFINE_OBJECT(OP)
+#define SIEVE_EXT_DEFINE_COMPARATORS(OPS) SIEVE_EXT_DEFINE_OBJECTS(OPS)
+
+extern const struct sieve_operand_class sieve_comparator_operand_class;
+extern const struct sieve_operand_def comparator_operand;
+
+static inline void sieve_opr_comparator_emit
+(struct sieve_binary_block *sblock, const struct sieve_comparator *cmp)
+{
+ sieve_opr_object_emit(sblock, cmp->object.ext, cmp->object.def);
+}
+static inline bool sieve_opr_comparator_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ return sieve_opr_object_dump
+ (denv, &sieve_comparator_operand_class, address, NULL);
+}
+
+static inline int sieve_opr_comparator_read
+(const struct sieve_runtime_env *renv, sieve_size_t *address,
+ struct sieve_comparator *cmp)
+{
+ if ( !sieve_opr_object_read
+ (renv, &sieve_comparator_operand_class, address, &cmp->object) )
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ cmp->def = (const struct sieve_comparator_def *) cmp->object.def;
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Trivial/Common comparator method implementations
+ */
+
+bool sieve_comparator_octet_skip
+ (const struct sieve_comparator *cmp ATTR_UNUSED,
+ const char **val, const char *val_end);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-config.h b/pigeonhole/src/lib-sieve/sieve-config.h
new file mode 100644
index 0000000..a0fed7c
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-config.h
@@ -0,0 +1,16 @@
+#ifndef SIEVE_CONFIG_H
+#define SIEVE_CONFIG_H
+
+#include "pigeonhole-config.h"
+#include "pigeonhole-version.h"
+
+#define SIEVE_IMPLEMENTATION PIGEONHOLE_NAME " Sieve " PIGEONHOLE_VERSION_FULL
+
+#define SIEVE_SCRIPT_FILEEXT "sieve"
+#define SIEVE_BINARY_FILEEXT "svbin"
+
+#define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON"
+
+#define DEFAULT_REDIRECT_DUPLICATE_PERIOD (3600 * 12)
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-dump.h b/pigeonhole/src/lib-sieve/sieve-dump.h
new file mode 100644
index 0000000..d704877
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-dump.h
@@ -0,0 +1,30 @@
+#ifndef SIEVE_DUMP_H
+#define SIEVE_DUMP_H
+
+#include "sieve-common.h"
+#include "sieve-code-dumper.h"
+#include "sieve-binary-dumper.h"
+
+/*
+ * Dumptime environment
+ */
+
+struct sieve_dumptime_env {
+ /* Dumpers */
+ struct sieve_instance *svinst;
+ struct sieve_binary_dumper *dumper;
+ struct sieve_code_dumper *cdumper;
+
+ /* Binary */
+ struct sieve_binary *sbin;
+ struct sieve_binary_block *sblock;
+
+ /* Code position */
+ const struct sieve_operation *oprtn;
+ sieve_size_t offset;
+
+ /* Output stream */
+ struct ostream *stream;
+};
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-error-private.h b/pigeonhole/src/lib-sieve/sieve-error-private.h
new file mode 100644
index 0000000..e0172b2
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-error-private.h
@@ -0,0 +1,67 @@
+#ifndef SIEVE_ERROR_PRIVATE_H
+#define SIEVE_ERROR_PRIVATE_H
+
+#include "sieve-error.h"
+
+/*
+ * Initialization
+ */
+
+void sieve_errors_init(struct sieve_instance *svinst);
+void sieve_errors_deinit(struct sieve_instance *svinst);
+
+/*
+ * Error handler object
+ */
+
+struct sieve_error_handler {
+ pool_t pool;
+ int refcount;
+
+ struct sieve_instance *svinst;
+
+ unsigned int max_errors;
+
+ unsigned int errors;
+ unsigned int warnings;
+
+ void (*log)(struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ enum sieve_error_flags flags,
+ const char *message);
+
+ void (*free)(struct sieve_error_handler *ehandler);
+
+ bool master_log:1; /* this logs through master log facility */
+ bool log_info:1; /* handle or discard info log */
+ bool log_debug:1; /* handle or discard debug log */
+};
+
+void sieve_error_handler_init(struct sieve_error_handler *ehandler,
+ struct sieve_instance *svinst, pool_t pool,
+ unsigned int max_errors);
+
+/*
+ * Direct handler calls
+ */
+
+void sieve_direct_logv(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ enum sieve_error_flags flags,
+ const char *fmt, va_list args) ATTR_FORMAT(5, 0);
+
+static inline void ATTR_FORMAT(5, 6)
+sieve_direct_log(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ enum sieve_error_flags flags, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ sieve_direct_logv(svinst, ehandler, params, flags, fmt, args);
+ va_end(args);
+}
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-error.c b/pigeonhole/src/lib-sieve/sieve-error.c
new file mode 100644
index 0000000..aae13a5
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-error.c
@@ -0,0 +1,1064 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "array.h"
+#include "ostream.h"
+#include "var-expand.h"
+#include "eacces-error.h"
+
+#include "sieve-common.h"
+#include "sieve-script.h"
+#include "sieve-error-private.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+
+/*
+ * Definitions
+ */
+
+#define CRITICAL_MSG \
+ "internal error occurred: refer to server log for more information."
+#define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]"
+
+/* Logfile error handler will rotate log when it exceeds 10k bytes */
+#define LOGFILE_MAX_SIZE (10 * 1024)
+
+/*
+ * Utility
+ */
+
+const char *
+sieve_error_script_location(const struct sieve_script *script,
+ unsigned int source_line)
+{
+ const char *sname;
+
+ sname = (script == NULL ? NULL : sieve_script_name(script));
+
+ if (sname == NULL || *sname == '\0') {
+ if (source_line == 0)
+ return NULL;
+
+ return t_strdup_printf("line %d", source_line);
+ }
+
+ if (source_line == 0)
+ return sname;
+
+ return t_strdup_printf("%s: line %d", sname, source_line);
+}
+
+const char *sieve_error_from_external(const char *msg)
+{
+ char *new_msg;
+
+ if (msg == NULL || *msg == '\0')
+ return msg;
+
+ new_msg = t_strdup_noconst(msg);
+ new_msg[0] = i_tolower(new_msg[0]);
+
+ return new_msg;
+}
+
+/*
+ * Initialization
+ */
+
+void sieve_errors_init(struct sieve_instance *svinst ATTR_UNUSED)
+{
+ /* nothing */
+}
+
+void sieve_errors_deinit(struct sieve_instance *svinst ATTR_UNUSED)
+{
+ /* nothing */
+}
+
+/*
+ * Direct handler calls
+ */
+
+static void
+sieve_direct_master_log(struct sieve_instance *svinst,
+ const struct sieve_error_params *params,
+ const char *message)
+{
+ struct event_log_params event_params = {
+ .log_type = params->log_type,
+ .source_filename = params->csrc.filename,
+ .source_linenum = params->csrc.linenum,
+
+ .base_event = svinst->event,
+ };
+ struct event *event = (params->event != NULL ?
+ params->event : svinst->event);
+
+ if (params->location != NULL && *params->location != '\0') {
+ event_params.base_send_prefix =
+ t_strconcat(params->location, ": ", NULL);
+ }
+
+ event_log(event, &event_params, "%s", message);
+}
+
+void sieve_direct_logv(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ enum sieve_error_flags flags,
+ const char *fmt, va_list args)
+{
+ struct event_log_params event_params = {
+ .log_type = params->log_type,
+ .source_filename = params->csrc.filename,
+ .source_linenum = params->csrc.linenum,
+ .base_event = svinst->event,
+ .base_str_out = NULL,
+ .no_send = TRUE,
+ };
+ struct event *event = (params->event != NULL ?
+ params->event : svinst->event);
+ bool event_log = FALSE, ehandler_log = FALSE;
+
+ if (ehandler != NULL) {
+ switch (params->log_type) {
+ case LOG_TYPE_ERROR:
+ ehandler_log = sieve_errors_more_allowed(ehandler);
+ break;
+ case LOG_TYPE_WARNING:
+ ehandler_log = TRUE;
+ break;
+ case LOG_TYPE_INFO:
+ ehandler_log = ehandler->log_info;
+ break;
+ case LOG_TYPE_DEBUG:
+ ehandler_log = ehandler->log_debug;
+ break;
+ case LOG_TYPE_FATAL:
+ case LOG_TYPE_PANIC:
+ case LOG_TYPE_COUNT:
+ case LOG_TYPE_OPTION:
+ i_unreached();
+ }
+ }
+
+ if (ehandler != NULL && ehandler->master_log) {
+ event_log = ehandler_log;
+ ehandler_log = FALSE;
+ }
+ if ((flags & SIEVE_ERROR_FLAG_GLOBAL) != 0) {
+ event_log = TRUE;
+ if ((flags & SIEVE_ERROR_FLAG_GLOBAL_MAX_INFO) != 0 &&
+ params->log_type > LOG_TYPE_INFO)
+ event_params.log_type = LOG_TYPE_INFO;
+ }
+
+ if (event_log) {
+ event_params.no_send = FALSE;
+ if (params->location != NULL && *params->location != '\0') {
+ event_params.base_send_prefix =
+ t_strconcat(params->location, ": ", NULL);
+ }
+ }
+ if (ehandler_log) {
+ if (ehandler->log == NULL)
+ ehandler_log = FALSE;
+ else
+ event_params.base_str_out = t_str_new(128);
+ }
+
+ if (event_log || ehandler_log)
+ event_logv(event, &event_params, fmt, args);
+
+ if (ehandler_log) {
+ ehandler->log(ehandler, params, flags,
+ str_c(event_params.base_str_out));
+ }
+
+ if (ehandler != NULL && ehandler->pool != NULL) {
+ switch (params->log_type) {
+ case LOG_TYPE_ERROR:
+ ehandler->errors++;
+ break;
+ case LOG_TYPE_WARNING:
+ ehandler->warnings++;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * User errors
+ */
+
+void sieve_global_logv(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ const char *fmt, va_list args)
+{
+ sieve_direct_logv(svinst, ehandler, params,
+ SIEVE_ERROR_FLAG_GLOBAL, fmt, args);
+}
+
+void sieve_global_info_logv(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ const char *fmt, va_list args)
+{
+ sieve_direct_logv(svinst, ehandler, params,
+ (SIEVE_ERROR_FLAG_GLOBAL |
+ SIEVE_ERROR_FLAG_GLOBAL_MAX_INFO), fmt, args);
+}
+
+#undef sieve_global_error
+void sieve_global_error(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_ERROR,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .location = location,
+ };
+ va_list args;
+ va_start(args, fmt);
+
+ T_BEGIN {
+ sieve_global_logv(svinst, ehandler, &params, fmt, args);
+ } T_END;
+
+ va_end(args);
+}
+
+#undef sieve_global_warning
+void sieve_global_warning(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_WARNING,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .location = location,
+ };
+ va_list args;
+ va_start(args, fmt);
+
+ T_BEGIN {
+ sieve_global_logv(svinst, ehandler, &params, fmt, args);
+ } T_END;
+
+ va_end(args);
+}
+
+#undef sieve_global_info
+void sieve_global_info(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_INFO,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .location = location,
+ };
+ va_list args;
+ va_start(args, fmt);
+
+ T_BEGIN {
+ sieve_global_logv(svinst, ehandler, &params, fmt, args);
+ } T_END;
+
+ va_end(args);
+}
+
+#undef sieve_global_info_error
+void sieve_global_info_error(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_ERROR,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .location = location,
+ };
+ va_list args;
+ va_start(args, fmt);
+
+ T_BEGIN {
+ sieve_global_info_logv(svinst, ehandler, &params, fmt, args);
+ } T_END;
+
+ va_end(args);
+}
+
+#undef sieve_global_info_warning
+void sieve_global_info_warning(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_WARNING,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .location = location,
+ };
+ va_list args;
+ va_start(args, fmt);
+
+ T_BEGIN {
+ sieve_global_info_logv(svinst, ehandler, &params, fmt, args);
+ } T_END;
+
+ va_end(args);
+}
+
+/*
+ * Default (user) error functions
+ */
+
+void sieve_internal_error_params(struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ const char *user_prefix)
+{
+ char str[256];
+ const char *msg;
+ struct tm *tm;
+
+ if (ehandler == NULL || ehandler->master_log)
+ return;
+
+ tm = localtime(&ioloop_time);
+ msg = (strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ?
+ str : CRITICAL_MSG);
+
+ if (user_prefix == NULL || *user_prefix == '\0') {
+ sieve_direct_log(ehandler->svinst, ehandler, params, 0,
+ "%s", msg);
+ } else {
+ sieve_direct_log(ehandler->svinst, ehandler, params, 0,
+ "%s: %s", user_prefix, msg);
+ }
+}
+
+#undef sieve_internal_error
+void sieve_internal_error(struct sieve_error_handler *ehandler,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *user_prefix)
+
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_ERROR,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .location = location,
+ };
+
+ sieve_internal_error_params(ehandler, &params, user_prefix);
+}
+
+void sieve_logv(struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ const char *fmt, va_list args)
+{
+ if (ehandler == NULL) return;
+
+ sieve_direct_logv(ehandler->svinst, ehandler, params, 0, fmt, args);
+}
+
+void sieve_event_logv(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ struct event *event, enum log_type log_type,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, enum sieve_error_flags flags,
+ const char *fmt, va_list args)
+{
+ struct sieve_error_params params = {
+ .log_type = log_type,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .event = event,
+ .location = location,
+ };
+
+ T_BEGIN {
+ sieve_direct_logv(svinst, ehandler, &params, flags, fmt, args);
+ } T_END;
+}
+
+
+#undef sieve_event_log
+void sieve_event_log(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ struct event *event, enum log_type log_type,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, enum sieve_error_flags flags,
+ const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+
+ sieve_event_logv(svinst, ehandler, event, log_type, csrc_filename,
+ csrc_linenum, location, flags, fmt, args);
+
+ va_end(args);
+}
+
+void sieve_criticalv(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ const char *user_prefix, const char *fmt, va_list args)
+{
+ struct sieve_error_params new_params = *params;
+
+ new_params.log_type = LOG_TYPE_ERROR;
+
+ sieve_direct_master_log(svinst, &new_params,
+ t_strdup_vprintf(fmt, args));
+ sieve_internal_error_params(ehandler, &new_params, user_prefix);
+}
+
+#undef sieve_error
+void sieve_error(struct sieve_error_handler *ehandler,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_ERROR,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .location = location,
+ };
+ va_list args;
+ va_start(args, fmt);
+
+ T_BEGIN {
+ sieve_logv(ehandler, &params, fmt, args);
+ } T_END;
+
+ va_end(args);
+}
+
+#undef sieve_warning
+void sieve_warning(struct sieve_error_handler *ehandler,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_WARNING,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .location = location,
+ };
+ va_list args;
+ va_start(args, fmt);
+
+ T_BEGIN {
+ sieve_logv(ehandler, &params, fmt, args);
+ } T_END;
+
+ va_end(args);
+}
+
+#undef sieve_info
+void sieve_info(struct sieve_error_handler *ehandler,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_INFO,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .location = location,
+ };
+ va_list args;
+ va_start(args, fmt);
+
+ T_BEGIN {
+ sieve_logv(ehandler, &params, fmt, args);
+ } T_END;
+
+ va_end(args);
+}
+
+#undef sieve_debug
+void sieve_debug(struct sieve_error_handler *ehandler,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_DEBUG,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .location = location,
+ };
+ va_list args;
+ va_start(args, fmt);
+
+ T_BEGIN {
+ sieve_logv(ehandler, &params, fmt, args);
+ } T_END;
+
+ va_end(args);
+}
+
+#undef sieve_critical
+void sieve_critical(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *user_prefix,
+ const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_ERROR,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .location = location,
+ };
+ va_list args;
+
+ va_start(args, fmt);
+
+ T_BEGIN {
+ sieve_criticalv(svinst, ehandler, &params, user_prefix,
+ fmt, args);
+ } T_END;
+
+ va_end(args);
+}
+
+/*
+ * Error statistics
+ */
+
+unsigned int sieve_get_errors(struct sieve_error_handler *ehandler)
+{
+ if (ehandler == NULL || ehandler->pool == NULL)
+ return 0;
+
+ return ehandler->errors;
+}
+
+unsigned int sieve_get_warnings(struct sieve_error_handler *ehandler)
+{
+ if (ehandler == NULL || ehandler->pool == NULL)
+ return 0;
+
+ return ehandler->warnings;
+}
+
+bool sieve_errors_more_allowed(struct sieve_error_handler *ehandler)
+{
+ if (ehandler == NULL || ehandler->pool == NULL)
+ return TRUE;
+
+ return (ehandler->max_errors == 0 ||
+ ehandler->errors < ehandler->max_errors);
+}
+
+/*
+ * Error handler configuration
+ */
+
+void sieve_error_handler_accept_infolog(struct sieve_error_handler *ehandler,
+ bool enable)
+{
+ ehandler->log_info = enable;
+}
+
+void sieve_error_handler_accept_debuglog(struct sieve_error_handler *ehandler,
+ bool enable)
+{
+ ehandler->log_debug = enable;
+}
+
+/*
+ * Error handler init
+ */
+
+void sieve_error_handler_init(struct sieve_error_handler *ehandler,
+ struct sieve_instance *svinst,
+ pool_t pool, unsigned int max_errors)
+{
+ ehandler->pool = pool;
+ ehandler->svinst = svinst;
+ ehandler->refcount = 1;
+ ehandler->max_errors = max_errors;
+
+ ehandler->errors = 0;
+ ehandler->warnings = 0;
+}
+
+void sieve_error_handler_ref(struct sieve_error_handler *ehandler)
+{
+ if (ehandler == NULL || ehandler->pool == NULL)
+ return;
+
+ ehandler->refcount++;
+}
+
+void sieve_error_handler_unref(struct sieve_error_handler **ehandler)
+{
+ if (*ehandler == NULL || (*ehandler)->pool == NULL)
+ return;
+
+ i_assert((*ehandler)->refcount > 0);
+
+ if (--(*ehandler)->refcount != 0)
+ return;
+
+ if ((*ehandler)->free != NULL)
+ (*ehandler)->free(*ehandler);
+
+ pool_unref(&((*ehandler)->pool));
+ *ehandler = NULL;
+}
+
+void sieve_error_handler_reset(struct sieve_error_handler *ehandler)
+{
+ if (ehandler == NULL || ehandler->pool == NULL)
+ return;
+
+ ehandler->errors = 0;
+ ehandler->warnings = 0;
+}
+
+/*
+ * Error params utility
+ */
+
+static void
+sieve_error_params_add_prefix(struct sieve_error_handler *ehandler ATTR_UNUSED,
+ const struct sieve_error_params *params,
+ string_t *prefix)
+{
+ if (params->location != NULL && *params->location != '\0') {
+ str_append(prefix, params->location);
+ str_append(prefix, ": ");
+ }
+
+ switch (params->log_type) {
+ case LOG_TYPE_ERROR:
+ str_append(prefix, "error: ");
+ break;
+ case LOG_TYPE_WARNING:
+ str_append(prefix, "warning: ");
+ break;
+ case LOG_TYPE_INFO:
+ str_append(prefix, "info: ");
+ break;
+ case LOG_TYPE_DEBUG:
+ str_append(prefix, "debug: ");
+ break;
+ default:
+ i_unreached();
+ }
+}
+
+/*
+ * Master/System error handler
+ *
+ * - Output errors directly to Dovecot master log
+ */
+
+struct sieve_error_handler *
+sieve_master_ehandler_create(struct sieve_instance *svinst,
+ unsigned int max_errors)
+{
+ struct sieve_error_handler *ehandler;
+ pool_t pool;
+
+ pool = pool_alloconly_create("master_error_handler", 256);
+ ehandler = p_new(pool, struct sieve_error_handler, 1);
+ sieve_error_handler_init(ehandler, svinst, pool, max_errors);
+ ehandler->master_log = TRUE;
+ ehandler->log_debug = svinst->debug;
+
+ return ehandler;
+}
+
+/*
+ * STDERR error handler
+ *
+ * - Output errors directly to stderror
+ */
+
+static void
+sieve_stderr_log(struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ enum sieve_error_flags flags ATTR_UNUSED,
+ const char *message)
+{
+ string_t *prefix = t_str_new(64);
+
+ sieve_error_params_add_prefix(ehandler, params, prefix);
+
+ fprintf(stderr, "%s%s.\n", str_c(prefix), message);
+}
+
+struct sieve_error_handler *
+sieve_stderr_ehandler_create(struct sieve_instance *svinst,
+ unsigned int max_errors)
+{
+ pool_t pool;
+ struct sieve_error_handler *ehandler;
+
+ /* Pool is not strictly necessary, but other handler types will need
+ * a pool, so this one will have one too.
+ */
+ pool = pool_alloconly_create("stderr_error_handler",
+ sizeof(struct sieve_error_handler));
+ ehandler = p_new(pool, struct sieve_error_handler, 1);
+ sieve_error_handler_init(ehandler, svinst, pool, max_errors);
+
+ ehandler->log = sieve_stderr_log;
+
+ return ehandler;
+}
+
+/* String buffer error handler
+ *
+ * - Output errors to a string buffer
+ */
+
+struct sieve_strbuf_ehandler {
+ struct sieve_error_handler handler;
+
+ string_t *errors;
+ bool crlf;
+};
+
+static void
+sieve_strbuf_log(struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ enum sieve_error_flags flags ATTR_UNUSED, const char *message)
+{
+ struct sieve_strbuf_ehandler *handler =
+ (struct sieve_strbuf_ehandler *) ehandler;
+
+ sieve_error_params_add_prefix(ehandler, params, handler->errors);
+ str_append(handler->errors, message);
+
+ if (!handler->crlf)
+ str_append(handler->errors, ".\n");
+ else
+ str_append(handler->errors, ".\r\n");
+}
+
+struct sieve_error_handler *
+sieve_strbuf_ehandler_create(struct sieve_instance *svinst, string_t *strbuf,
+ bool crlf, unsigned int max_errors)
+{
+ pool_t pool;
+ struct sieve_strbuf_ehandler *ehandler;
+
+ pool = pool_alloconly_create("strbuf_error_handler", 256);
+ ehandler = p_new(pool, struct sieve_strbuf_ehandler, 1);
+ ehandler->errors = strbuf;
+
+ sieve_error_handler_init(&ehandler->handler, svinst, pool, max_errors);
+
+ ehandler->handler.log = sieve_strbuf_log;
+ ehandler->crlf = crlf;
+
+ return &(ehandler->handler);
+}
+
+/*
+ * Logfile error handler
+ *
+ * - Output errors to a log file
+ */
+
+struct sieve_logfile_ehandler {
+ struct sieve_error_handler handler;
+
+ const char *logfile;
+ bool started;
+ int fd;
+ struct ostream *stream;
+};
+
+static void
+sieve_logfile_write(struct sieve_logfile_ehandler *ehandler,
+ const struct sieve_error_params *params,
+ const char *message)
+{
+ string_t *outbuf;
+ ssize_t ret = 0, remain;
+ const char *data;
+
+ if (ehandler->stream == NULL)
+ return;
+
+ T_BEGIN {
+ outbuf = t_str_new(256);
+ sieve_error_params_add_prefix(&ehandler->handler,
+ params, outbuf);
+ str_append(outbuf, message);
+ str_append(outbuf, ".\n");
+
+ remain = str_len(outbuf);
+ data = (const char *) str_data(outbuf);
+
+ while (remain > 0) {
+ if ((ret = o_stream_send(ehandler->stream,
+ data, remain)) < 0)
+ break;
+
+ remain -= ret;
+ data += ret;
+ }
+ } T_END;
+
+ if (ret < 0) {
+ e_error(ehandler->handler.svinst->event,
+ "o_stream_send() failed on logfile %s: %m",
+ ehandler->logfile);
+ }
+}
+
+inline static void ATTR_FORMAT(5, 6)
+sieve_logfile_printf(struct sieve_logfile_ehandler *ehandler,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_INFO,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .location = location,
+ };
+ va_list args;
+ va_start(args, fmt);
+
+ sieve_logfile_write(ehandler, &params, t_strdup_vprintf(fmt, args));
+
+ va_end(args);
+}
+
+static void sieve_logfile_start(struct sieve_logfile_ehandler *ehandler)
+{
+ struct sieve_instance *svinst = ehandler->handler.svinst;
+ struct ostream *ostream = NULL;
+ struct stat st;
+ struct tm *tm;
+ char buf[256];
+ time_t now;
+ int fd;
+
+ /* Open the logfile */
+
+ fd = open(ehandler->logfile, O_CREAT | O_APPEND | O_WRONLY, 0600);
+ if (fd == -1) {
+ if (errno == EACCES) {
+ e_error(svinst->event,
+ "failed to open logfile "
+ "(LOGGING TO STDERR): %s",
+ eacces_error_get_creating("open",
+ ehandler->logfile));
+ } else {
+ e_error(svinst->event, "failed to open logfile "
+ "(LOGGING TO STDERR): "
+ "open(%s) failed: %m", ehandler->logfile);
+ }
+ fd = STDERR_FILENO;
+ } else {
+ /* fd_close_on_exec(fd, TRUE); Necessary? */
+
+ /* Stat the log file to obtain size information */
+ if (fstat(fd, &st) != 0) {
+ e_error(svinst->event, "failed to stat logfile "
+ "(logging to STDERR): "
+ "fstat(fd=%s) failed: %m", ehandler->logfile);
+
+ if (close(fd) < 0) {
+ e_error(svinst->event,
+ "failed to close logfile after error: "
+ "close(fd=%s) failed: %m",
+ ehandler->logfile);
+ }
+
+ fd = STDERR_FILENO;
+ }
+
+ /* Rotate log when it has grown too large */
+ if (st.st_size >= LOGFILE_MAX_SIZE) {
+ const char *rotated;
+
+ /* Close open file */
+ if (close(fd) < 0) {
+ e_error(svinst->event,
+ "failed to close logfile: "
+ "close(fd=%s) failed: %m",
+ ehandler->logfile);
+ }
+
+ /* Rotate logfile */
+ rotated = t_strconcat(ehandler->logfile, ".0", NULL);
+ if (rename(ehandler->logfile, rotated) < 0 &&
+ errno != ENOENT) {
+ if (errno == EACCES) {
+ const char *target =
+ t_strconcat(ehandler->logfile,
+ ", ", rotated, NULL);
+ e_error(svinst->event,
+ "failed to rotate logfile: %s",
+ eacces_error_get_creating(
+ "rename", target));
+ } else {
+ e_error(svinst->event,
+ "failed to rotate logfile: "
+ "rename(%s, %s) failed: %m",
+ ehandler->logfile, rotated);
+ }
+ }
+
+ /* Open clean logfile (overwrites existing if rename() failed earlier) */
+ fd = open(ehandler->logfile,
+ O_CREAT | O_APPEND | O_WRONLY | O_TRUNC, 0600);
+ if (fd == -1) {
+ if (errno == EACCES) {
+ e_error(svinst->event,
+ "failed to open logfile "
+ "(LOGGING TO STDERR): %s",
+ eacces_error_get_creating(
+ "open", ehandler->logfile));
+ } else {
+ e_error(svinst->event,
+ "failed to open logfile "
+ "(LOGGING TO STDERR): "
+ "open(%s) failed: %m",
+ ehandler->logfile);
+ }
+ fd = STDERR_FILENO;
+ }
+ }
+ }
+
+ ostream = o_stream_create_fd(fd, 0);
+ if (ostream == NULL) {
+ /* Can't we do anything else in this most awkward situation? */
+ e_error(svinst->event,
+ "failed to open log stream on open file: "
+ "o_stream_create_fd(fd=%s) failed "
+ "(non-critical messages are not logged!)",
+ ehandler->logfile);
+ }
+
+ ehandler->fd = fd;
+ ehandler->stream = ostream;
+ ehandler->started = TRUE;
+
+ if (ostream != NULL) {
+ now = time(NULL);
+ tm = localtime(&now);
+
+ if (strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %z", tm) > 0) {
+ sieve_logfile_printf(ehandler, __FILE__, __LINE__,
+ "sieve", "started log at %s", buf);
+ }
+ }
+}
+
+static void
+sieve_logfile_log(struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ enum sieve_error_flags flags ATTR_UNUSED,
+ const char *message)
+{
+ struct sieve_logfile_ehandler *handler =
+ (struct sieve_logfile_ehandler *) ehandler;
+
+ if (!handler->started)
+ sieve_logfile_start(handler);
+
+ sieve_logfile_write(handler, params, message);
+}
+
+static void sieve_logfile_free(struct sieve_error_handler *ehandler)
+{
+ struct sieve_logfile_ehandler *handler =
+ (struct sieve_logfile_ehandler *) ehandler;
+
+ if (handler->stream != NULL) {
+ o_stream_destroy(&(handler->stream));
+ if (handler->fd != STDERR_FILENO) {
+ if (close(handler->fd) < 0) {
+ e_error(ehandler->svinst->event,
+ "failed to close logfile: "
+ "close(fd=%s) failed: %m",
+ handler->logfile);
+ }
+ }
+ }
+}
+
+struct sieve_error_handler *
+sieve_logfile_ehandler_create(struct sieve_instance *svinst,
+ const char *logfile, unsigned int max_errors)
+{
+ pool_t pool;
+ struct sieve_logfile_ehandler *ehandler;
+
+ pool = pool_alloconly_create("logfile_error_handler", 512);
+ ehandler = p_new(pool, struct sieve_logfile_ehandler, 1);
+ sieve_error_handler_init(&ehandler->handler, svinst, pool, max_errors);
+
+ ehandler->handler.log = sieve_logfile_log;
+ ehandler->handler.free = sieve_logfile_free;
+
+ /* Don't open logfile until something is actually logged.
+ * Let's not pullute the sieve directory with useless logfiles.
+ */
+ ehandler->logfile = p_strdup(pool, logfile);
+ ehandler->started = FALSE;
+ ehandler->stream = NULL;
+ ehandler->fd = -1;
+
+ return &(ehandler->handler);
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-error.h b/pigeonhole/src/lib-sieve/sieve-error.h
new file mode 100644
index 0000000..83b26b7
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-error.h
@@ -0,0 +1,235 @@
+#ifndef SIEVE_ERROR_H
+#define SIEVE_ERROR_H
+
+#include "lib.h"
+#include "compat.h"
+
+#include <stdarg.h>
+
+/*
+ * Forward declarations
+ */
+
+struct var_expand_table;
+
+struct sieve_instance;
+struct sieve_script;
+struct sieve_error_handler;
+
+/*
+ * Types
+ */
+
+enum sieve_error_flags {
+ SIEVE_ERROR_FLAG_GLOBAL = (1 << 0),
+ SIEVE_ERROR_FLAG_GLOBAL_MAX_INFO = (1 << 1),
+};
+
+struct sieve_error_params {
+ enum log_type log_type;
+ struct event *event;
+
+ /* Location log command in C source code */
+ struct {
+ const char *filename;
+ unsigned int linenum;
+ } csrc;
+
+ /* Location in Sieve source script */
+ const char *location;
+};
+
+/*
+ * Utility
+ */
+
+/* Converts external messages to a style that better matches Sieve user errors
+ */
+const char *sieve_error_from_external(const char *msg);
+
+/*
+ * Global (user+system) errors
+ */
+
+void sieve_global_logv(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ const char *fmt, va_list args) ATTR_FORMAT(4, 0);
+void sieve_global_info_logv(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ const char *fmt, va_list args) ATTR_FORMAT(4, 0);
+
+void sieve_global_error(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+ ATTR_FORMAT(6, 7);
+#define sieve_global_error(svinst, ehandler, ...) \
+ sieve_global_error(svinst, ehandler, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_global_warning(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+ ATTR_FORMAT(6, 7);
+#define sieve_global_warning(svinst, ehandler, ...) \
+ sieve_global_warning(svinst, ehandler, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_global_info(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+ ATTR_FORMAT(6, 7);
+#define sieve_global_info(svinst, ehandler, ...) \
+ sieve_global_info(svinst, ehandler, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_global_info_error(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+ ATTR_FORMAT(6, 7);
+#define sieve_global_info_error(svinst, ehandler, ...) \
+ sieve_global_info_error(svinst, ehandler, __FILE__, __LINE__, \
+ __VA_ARGS__)
+void sieve_global_info_warning(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+ ATTR_FORMAT(6, 7);
+#define sieve_global_info_warning(svinst, ehandler, ...) \
+ sieve_global_info_warning(svinst, ehandler, __FILE__, __LINE__, \
+ __VA_ARGS__)
+
+/*
+ * Main (user) error functions
+ */
+
+/* For these functions it is the responsibility of the caller to
+ * manage the datastack.
+ */
+
+const char *
+sieve_error_script_location(const struct sieve_script *script,
+ unsigned int source_line);
+
+void sieve_logv(struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ const char *fmt, va_list args) ATTR_FORMAT(3, 0);
+
+void sieve_event_logv(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ struct event *event, enum log_type log_type,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, enum sieve_error_flags flags,
+ const char *fmt, va_list args) ATTR_FORMAT(9, 0);
+void sieve_event_log(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ struct event *event, enum log_type log_type,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, enum sieve_error_flags flags,
+ const char *fmt, ...) ATTR_FORMAT(9, 10);
+#define sieve_event_log(svinst, ehandler, event, log_type, ...) \
+ sieve_event_log(svinst, ehandler, event, log_type, __FILE__, __LINE__, \
+ __VA_ARGS__)
+
+void sieve_criticalv(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ const char *user_prefix, const char *fmt, va_list args)
+ ATTR_FORMAT(5, 0);
+
+void sieve_error(struct sieve_error_handler *ehandler,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...) ATTR_FORMAT(5, 6);
+#define sieve_error(ehandler, ...) \
+ sieve_error(ehandler, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_warning(struct sieve_error_handler *ehandler,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+ ATTR_FORMAT(5, 6);
+#define sieve_warning(ehandler, ...) \
+ sieve_warning(ehandler, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_info(struct sieve_error_handler *ehandler,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...) ATTR_FORMAT(5, 6);
+#define sieve_info(ehandler, ...) \
+ sieve_info(ehandler, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_debug(struct sieve_error_handler *ehandler,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...) ATTR_FORMAT(5, 6);
+#define sieve_debug(ehandler, ...) \
+ sieve_debug(ehandler, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_critical(struct sieve_instance *svinst,
+ struct sieve_error_handler *ehandler,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *user_prefix,
+ const char *fmt, ...) ATTR_FORMAT(7, 8);
+#define sieve_critical(svinst, ehandler, ...) \
+ sieve_critical(svinst, ehandler, __FILE__, __LINE__, __VA_ARGS__)
+
+
+void sieve_internal_error_params(struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ const char *user_prefix);
+void sieve_internal_error(struct sieve_error_handler *ehandler,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *user_prefix)
+ ATTR_NULL(1, 4, 5);
+#define sieve_internal_error(ehandler, ...) \
+ sieve_internal_error(ehandler, __FILE__, __LINE__, __VA_ARGS__)
+
+/*
+ * Error handler configuration
+ */
+
+void sieve_error_handler_accept_infolog(struct sieve_error_handler *ehandler,
+ bool enable);
+void sieve_error_handler_accept_debuglog(struct sieve_error_handler *ehandler,
+ bool enable);
+
+/*
+ * Error handler statistics
+ */
+
+unsigned int sieve_get_errors(struct sieve_error_handler *ehandler);
+unsigned int sieve_get_warnings(struct sieve_error_handler *ehandler);
+
+bool sieve_errors_more_allowed(struct sieve_error_handler *ehandler);
+
+/*
+ * Error handler object
+ */
+
+void sieve_error_handler_ref(struct sieve_error_handler *ehandler);
+void sieve_error_handler_unref(struct sieve_error_handler **ehandler);
+
+void sieve_error_handler_reset(struct sieve_error_handler *ehandler);
+
+/*
+ * Error handlers
+ */
+
+/* Write errors to dovecot master log */
+struct sieve_error_handler *
+sieve_master_ehandler_create(struct sieve_instance *svinst,
+ unsigned int max_errors);
+
+/* Write errors to stderr */
+struct sieve_error_handler *
+sieve_stderr_ehandler_create(struct sieve_instance *svinst,
+ unsigned int max_errors);
+
+/* Write errors into a string buffer */
+struct sieve_error_handler *
+sieve_strbuf_ehandler_create(struct sieve_instance *svinst, string_t *strbuf,
+ bool crlf, unsigned int max_errors);
+
+/* Write errors to a logfile */
+struct sieve_error_handler *
+sieve_logfile_ehandler_create(struct sieve_instance *svinst,
+ const char *logfile, unsigned int max_errors);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-execute.c b/pigeonhole/src/lib-sieve/sieve-execute.c
new file mode 100644
index 0000000..a395cc6
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-execute.c
@@ -0,0 +1,162 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-execute.h"
+
+struct sieve_execute_state {
+ void *dup_trans;
+};
+
+struct event_category event_category_sieve_execute = {
+ .parent = &event_category_sieve,
+ .name = "sieve-execute",
+};
+
+static struct sieve_execute_state *
+sieve_execute_state_create(struct sieve_execute_env *eenv)
+{
+ return p_new(eenv->pool, struct sieve_execute_state, 1);
+}
+
+static void
+sieve_execute_state_free(struct sieve_execute_state **_estate,
+ struct sieve_execute_env *eenv)
+{
+ struct sieve_execute_state *estate = *_estate;
+ const struct sieve_script_env *senv = eenv->scriptenv;
+
+ *_estate = NULL;
+
+ if (senv->duplicate_transaction_rollback != NULL)
+ senv->duplicate_transaction_rollback(&estate->dup_trans);
+}
+
+void sieve_execute_init(struct sieve_execute_env *eenv,
+ struct sieve_instance *svinst, pool_t pool,
+ const struct sieve_message_data *msgdata,
+ const struct sieve_script_env *senv,
+ enum sieve_execute_flags flags)
+{
+ i_zero(eenv);
+ eenv->svinst = svinst;
+ eenv->pool = pool;
+ eenv->flags = flags;
+ eenv->msgdata = msgdata;
+ eenv->scriptenv = senv;
+
+ pool_ref(pool);
+ eenv->event = event_create(svinst->event);
+ event_add_category(eenv->event, &event_category_sieve_execute);
+ event_add_str(eenv->event, "message_id", msgdata->id);
+ if ((flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0) {
+ /* Make sure important envelope fields are available */
+ event_add_str(eenv->event, "mail_from",
+ smtp_address_encode(msgdata->envelope.mail_from));
+ event_add_str(eenv->event, "rcpt_to",
+ smtp_address_encode(msgdata->envelope.rcpt_to));
+ }
+
+ eenv->state = sieve_execute_state_create(eenv);
+
+ eenv->exec_status = senv->exec_status;
+ if (eenv->exec_status == NULL)
+ eenv->exec_status = p_new(pool, struct sieve_exec_status, 1);
+ else
+ i_zero(eenv->exec_status);
+}
+
+void sieve_execute_finish(struct sieve_execute_env *eenv, int status)
+{
+ const struct sieve_script_env *senv = eenv->scriptenv;
+
+ if (status == SIEVE_EXEC_OK) {
+ if (senv->duplicate_transaction_commit != NULL) {
+ senv->duplicate_transaction_commit(
+ &eenv->state->dup_trans);
+ }
+ } else {
+ if (senv->duplicate_transaction_rollback != NULL) {
+ senv->duplicate_transaction_rollback(
+ &eenv->state->dup_trans);
+ }
+ }
+}
+
+void sieve_execute_deinit(struct sieve_execute_env *eenv)
+{
+ sieve_execute_state_free(&eenv->state, eenv);
+ event_unref(&eenv->event);
+ pool_unref(&eenv->pool);
+}
+
+/*
+ * Checking for duplicates
+ */
+
+static void *
+sieve_execute_get_dup_transaction(const struct sieve_execute_env *eenv)
+{
+ const struct sieve_script_env *senv = eenv->scriptenv;
+
+ if (senv->duplicate_transaction_begin == NULL)
+ return NULL;
+ if (eenv->state->dup_trans == NULL) {
+ eenv->state->dup_trans =
+ senv->duplicate_transaction_begin(senv);
+ }
+ return eenv->state->dup_trans;
+}
+
+bool sieve_execute_duplicate_check_available(
+ const struct sieve_execute_env *eenv)
+{
+ const struct sieve_script_env *senv = eenv->scriptenv;
+
+ return (senv->duplicate_transaction_begin != NULL);
+}
+
+int sieve_execute_duplicate_check(const struct sieve_execute_env *eenv,
+ const void *id, size_t id_size,
+ bool *duplicate_r)
+{
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ void *dup_trans = sieve_execute_get_dup_transaction(eenv);
+ int ret;
+
+ *duplicate_r = FALSE;
+
+ if (senv->duplicate_check == NULL)
+ return SIEVE_EXEC_OK;
+
+ e_debug(eenv->svinst->event, "Check duplicate ID");
+
+ ret = senv->duplicate_check(dup_trans, senv, id, id_size);
+ switch (ret) {
+ case SIEVE_DUPLICATE_CHECK_RESULT_EXISTS:
+ *duplicate_r = TRUE;
+ break;
+ case SIEVE_DUPLICATE_CHECK_RESULT_NOT_FOUND:
+ break;
+ case SIEVE_DUPLICATE_CHECK_RESULT_FAILURE:
+ return SIEVE_EXEC_FAILURE;
+ case SIEVE_DUPLICATE_CHECK_RESULT_TEMP_FAILURE:
+ return SIEVE_EXEC_TEMP_FAILURE;
+ }
+ return SIEVE_EXEC_OK;
+}
+
+void sieve_execute_duplicate_mark(const struct sieve_execute_env *eenv,
+ const void *id, size_t id_size, time_t time)
+{
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ void *dup_trans = sieve_execute_get_dup_transaction(eenv);
+
+ if (senv->duplicate_mark == NULL)
+ return;
+
+ e_debug(eenv->svinst->event, "Mark ID as duplicate");
+
+ senv->duplicate_mark(dup_trans, senv, id, id_size, time);
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-execute.h b/pigeonhole/src/lib-sieve/sieve-execute.h
new file mode 100644
index 0000000..8af182b
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-execute.h
@@ -0,0 +1,42 @@
+#ifndef SIEVE_EXECUTE_H
+#define SIEVE_EXECUTE_H
+
+#include "sieve-common.h"
+
+struct sieve_execute_state;
+
+struct sieve_execute_env {
+ struct sieve_instance *svinst;
+ pool_t pool;
+
+ enum sieve_execute_flags flags;
+ struct event *event;
+
+ const struct sieve_message_data *msgdata;
+ const struct sieve_script_env *scriptenv;
+
+ struct sieve_execute_state *state;
+ struct sieve_exec_status *exec_status;
+};
+
+void sieve_execute_init(struct sieve_execute_env *eenv,
+ struct sieve_instance *svinst, pool_t pool,
+ const struct sieve_message_data *msgdata,
+ const struct sieve_script_env *senv,
+ enum sieve_execute_flags flags);
+void sieve_execute_finish(struct sieve_execute_env *eenv, int status);
+void sieve_execute_deinit(struct sieve_execute_env *eenv);
+
+/*
+ * Checking for duplicates
+ */
+
+bool sieve_execute_duplicate_check_available(
+ const struct sieve_execute_env *eenv);
+int sieve_execute_duplicate_check(const struct sieve_execute_env *eenv,
+ const void *id, size_t id_size,
+ bool *duplicate_r);
+void sieve_execute_duplicate_mark(const struct sieve_execute_env *eenv,
+ const void *id, size_t id_size, time_t time);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-extensions.c b/pigeonhole/src/lib-sieve/sieve-extensions.c
new file mode 100644
index 0000000..a1cb810
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-extensions.c
@@ -0,0 +1,879 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "mempool.h"
+#include "hash.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-settings.h"
+#include "sieve-extensions.h"
+
+/*
+ * Forward declarations
+ */
+
+static void sieve_extension_registry_init(struct sieve_instance *svinst);
+static void sieve_extension_registry_deinit(struct sieve_instance *svinst);
+
+static void sieve_capability_registry_init(struct sieve_instance *svinst);
+static void sieve_capability_registry_deinit(struct sieve_instance *svinst);
+
+static struct sieve_extension *_sieve_extension_register
+ (struct sieve_instance *svinst, const struct sieve_extension_def *extdef,
+ bool load, bool required);
+
+/*
+ * Instance global context
+ */
+
+struct sieve_extension_registry {
+ ARRAY(struct sieve_extension *) extensions;
+ HASH_TABLE(const char *, struct sieve_extension *) extension_index;
+ HASH_TABLE(const char *, struct sieve_capability_registration *) capabilities_index;
+
+ /* Core language 'extensions' */
+ const struct sieve_extension *comparator_extension;
+ const struct sieve_extension *match_type_extension;
+ const struct sieve_extension *address_part_extension;
+
+ /* Preloaded extensions */
+ ARRAY(const struct sieve_extension *) preloaded_extensions;
+};
+
+/*
+ * Pre-loaded 'extensions'
+ */
+
+extern const struct sieve_extension_def comparator_extension;
+extern const struct sieve_extension_def match_type_extension;
+extern const struct sieve_extension_def address_part_extension;
+
+/*
+ * Dummy extensions
+ */
+
+/* FIXME: This is stupid. Define a comparator-* extension and be done with it */
+
+const struct sieve_extension_def comparator_i_octet_extension = {
+ .name = "comparator-i;octet",
+};
+
+const struct sieve_extension_def comparator_i_ascii_casemap_extension = {
+ .name = "comparator-i;ascii-casemap",
+};
+
+/*
+ * List of native extensions
+ */
+
+/* Dummy extensions */
+
+extern const struct sieve_extension_def comparator_i_octet_extension;
+extern const struct sieve_extension_def comparator_i_ascii_casemap_extension;
+
+const struct sieve_extension_def *sieve_dummy_extensions[] = {
+ &comparator_i_octet_extension, &comparator_i_ascii_casemap_extension
+};
+
+const unsigned int sieve_dummy_extensions_count =
+ N_ELEMENTS(sieve_dummy_extensions);
+
+/* Core */
+
+extern const struct sieve_extension_def fileinto_extension;
+extern const struct sieve_extension_def reject_extension;
+extern const struct sieve_extension_def envelope_extension;
+extern const struct sieve_extension_def encoded_character_extension;
+
+extern const struct sieve_extension_def vacation_extension;
+extern const struct sieve_extension_def subaddress_extension;
+extern const struct sieve_extension_def comparator_i_ascii_numeric_extension;
+extern const struct sieve_extension_def relational_extension;
+extern const struct sieve_extension_def regex_extension;
+extern const struct sieve_extension_def imap4flags_extension;
+extern const struct sieve_extension_def copy_extension;
+extern const struct sieve_extension_def include_extension;
+extern const struct sieve_extension_def body_extension;
+extern const struct sieve_extension_def variables_extension;
+extern const struct sieve_extension_def enotify_extension;
+extern const struct sieve_extension_def environment_extension;
+extern const struct sieve_extension_def mailbox_extension;
+extern const struct sieve_extension_def date_extension;
+extern const struct sieve_extension_def index_extension;
+extern const struct sieve_extension_def ihave_extension;
+extern const struct sieve_extension_def duplicate_extension;
+extern const struct sieve_extension_def mime_extension;
+extern const struct sieve_extension_def foreverypart_extension;
+extern const struct sieve_extension_def extracttext_extension;
+extern const struct sieve_extension_def mboxmetadata_extension;
+extern const struct sieve_extension_def servermetadata_extension;
+
+const struct sieve_extension_def *sieve_core_extensions[] = {
+ /* Core extensions */
+ &fileinto_extension, &reject_extension, &envelope_extension,
+ &encoded_character_extension,
+
+ /* 'Plugins' */
+ &vacation_extension, &subaddress_extension,
+ &comparator_i_ascii_numeric_extension,
+ &relational_extension, &regex_extension, &imap4flags_extension,
+ &copy_extension, &include_extension, &body_extension,
+ &variables_extension, &enotify_extension, &environment_extension,
+ &mailbox_extension, &date_extension, &index_extension, &ihave_extension,
+ &duplicate_extension, &mime_extension, &foreverypart_extension,
+ &extracttext_extension
+};
+
+const unsigned int sieve_core_extensions_count =
+ N_ELEMENTS(sieve_core_extensions);
+
+/* Extra;
+ * These are not enabled by default, e.g. because explicit configuration is
+ * necessary to make these useful.
+ */
+
+extern const struct sieve_extension_def vacation_seconds_extension;
+extern const struct sieve_extension_def spamtest_extension;
+extern const struct sieve_extension_def spamtestplus_extension;
+extern const struct sieve_extension_def virustest_extension;
+extern const struct sieve_extension_def editheader_extension;
+extern const struct sieve_extension_def special_use_extension;
+
+extern const struct sieve_extension_def vnd_debug_extension;
+extern const struct sieve_extension_def vnd_environment_extension;
+extern const struct sieve_extension_def vnd_report_extension;
+
+const struct sieve_extension_def *sieve_extra_extensions[] = {
+ &vacation_seconds_extension, &spamtest_extension, &spamtestplus_extension,
+ &virustest_extension, &editheader_extension,
+ &mboxmetadata_extension, &servermetadata_extension,
+ &special_use_extension,
+
+ /* vnd.dovecot. */
+ &vnd_debug_extension, &vnd_environment_extension, &vnd_report_extension
+};
+
+const unsigned int sieve_extra_extensions_count =
+ N_ELEMENTS(sieve_extra_extensions);
+
+/*
+ * Deprecated extensions
+ */
+
+extern const struct sieve_extension_def imapflags_extension;
+extern const struct sieve_extension_def notify_extension;
+extern const struct sieve_extension_def vnd_duplicate_extension;
+
+const struct sieve_extension_def *sieve_deprecated_extensions[] = {
+ &imapflags_extension,
+ &notify_extension,
+ &vnd_duplicate_extension
+};
+
+const unsigned int sieve_deprecated_extensions_count =
+ N_ELEMENTS(sieve_deprecated_extensions);
+
+/*
+ * Unfinished extensions
+ */
+
+#ifdef HAVE_SIEVE_UNFINISHED
+
+extern const struct sieve_extension_def ereject_extension;
+
+const struct sieve_extension_def *sieve_unfinished_extensions[] = {
+ &ereject_extension
+};
+
+const unsigned int sieve_unfinished_extensions_count =
+ N_ELEMENTS(sieve_unfinished_extensions);
+
+#endif /* HAVE_SIEVE_UNFINISHED */
+
+/*
+ * Extensions init/deinit
+ */
+
+bool sieve_extensions_init(struct sieve_instance *svinst)
+{
+ unsigned int i;
+ struct sieve_extension_registry *ext_reg =
+ p_new(svinst->pool, struct sieve_extension_registry, 1);
+ struct sieve_extension *ext;
+
+ svinst->ext_reg = ext_reg;
+
+ sieve_extension_registry_init(svinst);
+ sieve_capability_registry_init(svinst);
+
+ /* Preloaded 'extensions' */
+ ext_reg->comparator_extension =
+ sieve_extension_register(svinst, &comparator_extension, TRUE);
+ ext_reg->match_type_extension =
+ sieve_extension_register(svinst, &match_type_extension, TRUE);
+ ext_reg->address_part_extension =
+ sieve_extension_register(svinst, &address_part_extension, TRUE);
+
+ p_array_init(&ext_reg->preloaded_extensions, svinst->pool, 5);
+ array_append(&ext_reg->preloaded_extensions,
+ &ext_reg->comparator_extension, 1);
+ array_append(&ext_reg->preloaded_extensions,
+ &ext_reg->match_type_extension, 1);
+ array_append(&ext_reg->preloaded_extensions,
+ &ext_reg->address_part_extension, 1);
+
+ /* Pre-load dummy extensions */
+ for ( i = 0; i < sieve_dummy_extensions_count; i++ ) {
+ if ( (ext=_sieve_extension_register
+ (svinst, sieve_dummy_extensions[i], TRUE, FALSE)) == NULL )
+ return FALSE;
+
+ ext->dummy = TRUE;
+ }
+
+ /* Pre-load core extensions */
+ for ( i = 0; i < sieve_core_extensions_count; i++ ) {
+ if ( sieve_extension_register
+ (svinst, sieve_core_extensions[i], TRUE) == NULL )
+ return FALSE;
+ }
+
+ /* Pre-load extra extensions */
+ for ( i = 0; i < sieve_extra_extensions_count; i++ ) {
+ if ( sieve_extension_register
+ (svinst, sieve_extra_extensions[i], FALSE) == NULL )
+ return FALSE;
+ }
+
+ /* Register deprecated extensions */
+ for ( i = 0; i < sieve_deprecated_extensions_count; i++ ) {
+ if ( sieve_extension_register
+ (svinst, sieve_deprecated_extensions[i], FALSE) == NULL )
+ return FALSE;
+ }
+
+#ifdef HAVE_SIEVE_UNFINISHED
+ /* Register unfinished extensions */
+ for ( i = 0; i < sieve_unfinished_extensions_count; i++ ) {
+ if ( sieve_extension_register
+ (svinst, sieve_unfinished_extensions[i], FALSE) == NULL )
+ return FALSE;
+ }
+#endif
+
+ /* More extensions can be added through plugins */
+
+ return TRUE;
+}
+
+void sieve_extensions_configure(struct sieve_instance *svinst)
+{
+ const char *extensions;
+
+ /* Apply sieve_extensions configuration */
+
+ if ( (extensions=sieve_setting_get
+ (svinst, "sieve_extensions")) != NULL )
+ sieve_extensions_set_string(svinst, extensions, FALSE, FALSE);
+
+ /* Apply sieve_global_extensions configuration */
+
+ if ( (extensions=sieve_setting_get
+ (svinst, "sieve_global_extensions")) != NULL )
+ sieve_extensions_set_string(svinst, extensions, TRUE, FALSE);
+
+ /* Apply sieve_implicit_extensions configuration */
+
+ if ( (extensions=sieve_setting_get
+ (svinst, "sieve_implicit_extensions")) != NULL )
+ sieve_extensions_set_string(svinst, extensions, FALSE, TRUE);
+}
+
+void sieve_extensions_deinit(struct sieve_instance *svinst)
+{
+ sieve_extension_registry_deinit(svinst);
+ sieve_capability_registry_deinit(svinst);
+}
+
+/*
+ * Pre-loaded extensions
+ */
+
+const struct sieve_extension *const *sieve_extensions_get_preloaded
+(struct sieve_instance *svinst, unsigned int *count_r)
+{
+ struct sieve_extension_registry *ext_reg = svinst->ext_reg;
+
+ return array_get(&ext_reg->preloaded_extensions, count_r);
+}
+
+/*
+ * Extension registry
+ */
+
+static bool _sieve_extension_load(struct sieve_extension *ext)
+{
+ /* Call load handler */
+ if ( ext->def != NULL && ext->def->load != NULL &&
+ !ext->def->load(ext, &ext->context) ) {
+ e_error(ext->svinst->event,
+ "failed to load '%s' extension support.",
+ ext->def->name);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void _sieve_extension_unload(struct sieve_extension *ext)
+{
+ /* Call unload handler */
+ if ( ext->def != NULL && ext->def->unload != NULL )
+ ext->def->unload(ext);
+ ext->context = NULL;
+}
+
+static void sieve_extension_registry_init(struct sieve_instance *svinst)
+{
+ struct sieve_extension_registry *ext_reg = svinst->ext_reg;
+
+ p_array_init(&ext_reg->extensions, svinst->pool, 50);
+ hash_table_create
+ (&ext_reg->extension_index, default_pool, 0, str_hash, strcmp);
+}
+
+static void sieve_extension_registry_deinit(struct sieve_instance *svinst)
+{
+ struct sieve_extension_registry *ext_reg = svinst->ext_reg;
+ struct sieve_extension * const *exts;
+ unsigned int i, ext_count;
+
+ if ( !hash_table_is_created(ext_reg->extension_index) ) return;
+
+ exts = array_get_modifiable(&ext_reg->extensions, &ext_count);
+ for ( i = 0; i < ext_count; i++ ) {
+ _sieve_extension_unload(exts[i]);
+ }
+
+ hash_table_destroy(&ext_reg->extension_index);
+}
+
+bool sieve_extension_reload(const struct sieve_extension *ext)
+{
+ struct sieve_extension_registry *ext_reg = ext->svinst->ext_reg;
+ struct sieve_extension * const *mod_ext;
+ int ext_id = ext->id;
+
+ /* Let's not just cast the 'const' away */
+ if ( ext_id >= 0 && ext_id < (int) array_count(&ext_reg->extensions) ) {
+ mod_ext = array_idx(&ext_reg->extensions, ext_id);
+
+ return _sieve_extension_load(*mod_ext);
+ }
+
+ return FALSE;
+}
+
+static struct sieve_extension *sieve_extension_lookup
+(struct sieve_instance *svinst, const char *name)
+{
+ struct sieve_extension_registry *ext_reg = svinst->ext_reg;
+
+ return hash_table_lookup(ext_reg->extension_index, name);
+}
+
+static struct sieve_extension *sieve_extension_alloc
+(struct sieve_instance *svinst,
+ const struct sieve_extension_def *extdef)
+{
+ struct sieve_extension_registry *ext_reg = svinst->ext_reg;
+ struct sieve_extension *ext, **extr;
+ int ext_id;
+
+ ext_id = (int)array_count(&ext_reg->extensions);
+
+ /* Add extension to the registry */
+ extr = array_append_space(&ext_reg->extensions);
+ *extr = ext = p_new(svinst->pool, struct sieve_extension, 1);
+ ext->id = ext_id;
+ ext->def = extdef;
+ ext->svinst = svinst;
+ return ext;
+}
+
+static struct sieve_extension *_sieve_extension_register
+(struct sieve_instance *svinst, const struct sieve_extension_def *extdef,
+ bool load, bool required)
+{
+ struct sieve_extension *ext;
+
+ ext = sieve_extension_lookup(svinst, extdef->name);
+
+ /* Register extension if it is not registered already */
+ if ( ext == NULL ) {
+ ext = sieve_extension_alloc(svinst, extdef);
+ hash_table_insert
+ (svinst->ext_reg->extension_index, extdef->name, ext);
+
+ } else if ( ext->overridden ) {
+ /* Create a dummy */
+ ext = sieve_extension_alloc(svinst, extdef);
+
+ } else {
+ /* Re-register it if it were previously unregistered
+ * (not going to happen)
+ */
+ i_assert( ext->def == NULL || ext->def == extdef );
+ ext->def = extdef;
+ }
+
+ /* Enable extension */
+ if ( load || required ) {
+ ext->enabled = ( ext->enabled || load );
+
+ /* Call load handler if extension was not loaded already */
+ if ( !ext->loaded ) {
+ if ( !_sieve_extension_load(ext) )
+ return NULL;
+ }
+
+ ext->loaded = TRUE;
+ }
+
+ ext->required = ( ext->required || required );
+
+ return ext;
+}
+
+const struct sieve_extension *sieve_extension_register
+(struct sieve_instance *svinst, const struct sieve_extension_def *extdef,
+ bool load)
+{
+ return _sieve_extension_register(svinst, extdef, load, FALSE);
+}
+
+void sieve_extension_unregister(const struct sieve_extension *ext)
+{
+ struct sieve_extension_registry *ext_reg = ext->svinst->ext_reg;
+ struct sieve_extension * const *mod_ext;
+ int ext_id = ext->id;
+
+ if ( ext_id >= 0 && ext_id < (int) array_count(&ext_reg->extensions) ) {
+ mod_ext = array_idx(&ext_reg->extensions, ext_id);
+
+ sieve_extension_capabilities_unregister(*mod_ext);
+ _sieve_extension_unload(*mod_ext);
+ (*mod_ext)->loaded = FALSE;
+ (*mod_ext)->enabled = FALSE;
+ (*mod_ext)->def = NULL;
+ }
+}
+
+const struct sieve_extension *sieve_extension_replace
+(struct sieve_instance *svinst, const struct sieve_extension_def *extdef,
+ bool load)
+{
+ struct sieve_extension *ext;
+
+ ext = sieve_extension_lookup(svinst, extdef->name);
+ if (ext != NULL)
+ sieve_extension_unregister(ext);
+ return sieve_extension_register(svinst, extdef, load);
+}
+
+const struct sieve_extension *sieve_extension_require
+(struct sieve_instance *svinst, const struct sieve_extension_def *extdef,
+ bool load)
+{
+ return _sieve_extension_register(svinst, extdef, load, TRUE);
+}
+
+void sieve_extension_override
+(struct sieve_instance *svinst, const char *name,
+ const struct sieve_extension *ext)
+{
+ struct sieve_extension_registry *ext_reg = ext->svinst->ext_reg;
+ struct sieve_extension * const *mod_ext;
+ struct sieve_extension *old_ext;
+
+ old_ext = sieve_extension_lookup(svinst, name);
+ if (old_ext == ext)
+ return;
+ i_assert( old_ext == NULL || !old_ext->overridden );
+
+ i_assert( ext->id >= 0 &&
+ ext->id < (int) array_count(&ext_reg->extensions) );
+ mod_ext = array_idx(&ext_reg->extensions, ext->id);
+
+ hash_table_update
+ (ext_reg->extension_index, name, *mod_ext);
+ if ( old_ext != NULL )
+ old_ext->overridden = TRUE;
+}
+
+unsigned int sieve_extensions_get_count(struct sieve_instance *svinst)
+{
+ struct sieve_extension_registry *ext_reg = svinst->ext_reg;
+
+ return array_count(&ext_reg->extensions);
+}
+
+const struct sieve_extension *const *
+sieve_extensions_get_all(struct sieve_instance *svinst,
+ unsigned int *count_r)
+{
+ struct sieve_extension_registry *ext_reg = svinst->ext_reg;
+
+ return (const struct sieve_extension *const *)
+ array_get(&ext_reg->extensions, count_r);
+}
+
+const struct sieve_extension *sieve_extension_get_by_id
+(struct sieve_instance *svinst, unsigned int ext_id)
+{
+ struct sieve_extension_registry *ext_reg = svinst->ext_reg;
+ struct sieve_extension * const *ext;
+
+ if ( ext_id < array_count(&ext_reg->extensions) ) {
+ ext = array_idx(&ext_reg->extensions, ext_id);
+
+ if ( (*ext)->def != NULL && ((*ext)->enabled || (*ext)->required) )
+ return *ext;
+ }
+
+ return NULL;
+}
+
+const struct sieve_extension *sieve_extension_get_by_name
+(struct sieve_instance *svinst, const char *name)
+{
+ const struct sieve_extension *ext;
+
+ if ( *name == '@' )
+ return NULL;
+
+ if ( strlen(name) > 128 )
+ return NULL;
+
+ ext = sieve_extension_lookup(svinst, name);
+ if ( ext == NULL || ext->def == NULL || (!ext->enabled && !ext->required))
+ return NULL;
+
+ return ext;
+}
+
+static inline bool _sieve_extension_listable(const struct sieve_extension *ext)
+{
+ return ( ext->enabled && ext->def != NULL && *(ext->def->name) != '@'
+ && !ext->dummy && !ext->global && !ext->overridden);
+}
+
+const char *sieve_extensions_get_string(struct sieve_instance *svinst)
+{
+ struct sieve_extension_registry *ext_reg = svinst->ext_reg;
+ string_t *extstr = t_str_new(256);
+ struct sieve_extension * const *exts;
+ unsigned int i, ext_count;
+
+ exts = array_get(&ext_reg->extensions, &ext_count);
+
+ if ( ext_count > 0 ) {
+ i = 0;
+
+ /* Find first listable extension */
+ while ( i < ext_count && !_sieve_extension_listable(exts[i]) )
+ i++;
+
+ if ( i < ext_count ) {
+ /* Add first to string */
+ str_append(extstr, exts[i]->def->name);
+ i++;
+
+ /* Add others */
+ for ( ; i < ext_count; i++ ) {
+ if ( _sieve_extension_listable(exts[i]) ) {
+ str_append_c(extstr, ' ');
+ str_append(extstr, exts[i]->def->name);
+ }
+ }
+ }
+ }
+
+ return str_c(extstr);
+}
+
+static void sieve_extension_set_enabled
+(struct sieve_extension *ext, bool enabled)
+{
+ if ( enabled ) {
+ ext->enabled = TRUE;
+
+ if ( !ext->loaded ) {
+ (void)_sieve_extension_load(ext);
+ }
+
+ ext->loaded = TRUE;
+ } else {
+ ext->enabled = FALSE;
+ }
+}
+
+static void sieve_extension_set_global
+(struct sieve_extension *ext, bool enabled)
+{
+ if ( enabled ) {
+ sieve_extension_set_enabled(ext, TRUE);
+ ext->global = TRUE;
+ } else {
+ ext->global = FALSE;
+ }
+}
+
+static void sieve_extension_set_implicit
+(struct sieve_extension *ext, bool enabled)
+{
+ if ( enabled ) {
+ sieve_extension_set_enabled(ext, TRUE);
+ ext->implicit = TRUE;
+ } else {
+ ext->implicit = FALSE;
+ }
+}
+
+void sieve_extensions_set_string
+(struct sieve_instance *svinst, const char *ext_string,
+ bool global, bool implicit)
+{
+ struct sieve_extension_registry *ext_reg = svinst->ext_reg;
+ ARRAY(const struct sieve_extension *) enabled_extensions;
+ ARRAY(const struct sieve_extension *) disabled_extensions;
+ const struct sieve_extension *const *ext_enabled;
+ const struct sieve_extension *const *ext_disabled;
+ struct sieve_extension **exts;
+ const char **ext_names;
+ unsigned int i, ext_count, ena_count, dis_count;
+ bool relative = FALSE;
+
+ if ( ext_string == NULL ) {
+ if ( global || implicit ) return;
+
+ /* Enable all */
+ exts = array_get_modifiable(&ext_reg->extensions, &ext_count);
+
+ for ( i = 0; i < ext_count; i++ )
+ sieve_extension_set_enabled(exts[i], TRUE);
+
+ return;
+ }
+
+ T_BEGIN {
+ t_array_init(&enabled_extensions, array_count(&ext_reg->extensions));
+ t_array_init(&disabled_extensions, array_count(&ext_reg->extensions));
+
+ ext_names = t_strsplit_spaces(ext_string, " \t");
+
+ while ( *ext_names != NULL ) {
+ const char *name = *ext_names;
+
+ ext_names++;
+
+ if ( *name != '\0' ) {
+ const struct sieve_extension *ext;
+ char op = '\0'; /* No add/remove operation */
+
+ if ( *name == '+' /* Add to existing config */
+ || *name == '-' ) { /* Remove from existing config */
+ op = *name++;
+ relative = TRUE;
+ }
+
+ if ( *name == '@' )
+ ext = NULL;
+ else
+ ext = hash_table_lookup(ext_reg->extension_index, name);
+
+ if ( ext == NULL || ext->def == NULL ) {
+ e_warning(svinst->event,
+ "ignored unknown extension '%s' while configuring "
+ "available extensions", name);
+ continue;
+ }
+
+ if ( op == '-' )
+ array_append(&disabled_extensions, &ext, 1);
+ else
+ array_append(&enabled_extensions, &ext, 1);
+ }
+ }
+
+ exts = array_get_modifiable(&ext_reg->extensions, &ext_count);
+ ext_enabled = array_get(&enabled_extensions, &ena_count);
+ ext_disabled = array_get(&disabled_extensions, &dis_count);
+
+ /* Set new extension status */
+
+ for ( i = 0; i < ext_count; i++ ) {
+ unsigned int j;
+ bool enabled = FALSE;
+
+ if ( exts[i]->id < 0 || exts[i]->def == NULL ||
+ *(exts[i]->def->name) == '@' ) {
+ continue;
+ }
+
+ /* If extensions are specified relative to the default set,
+ * we first need to check which ones are disabled
+ */
+
+ if ( relative ) {
+ if ( global )
+ enabled = exts[i]->global;
+ else if ( implicit )
+ enabled = exts[i]->implicit;
+ else
+ enabled = exts[i]->enabled;
+
+ if ( enabled ) {
+ /* Disable if explicitly disabled */
+ for ( j = 0; j < dis_count; j++ ) {
+ if ( ext_disabled[j]->def == exts[i]->def ) {
+ enabled = FALSE;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Enable if listed with '+' or no prefix */
+
+ for ( j = 0; j < ena_count; j++ ) {
+ if ( ext_enabled[j]->def == exts[i]->def ) {
+ enabled = TRUE;
+ break;
+ }
+ }
+
+ /* Perform actual activation/deactivation */
+ if ( global ) {
+ sieve_extension_set_global(exts[i], enabled);
+ } else if ( implicit ) {
+ sieve_extension_set_implicit(exts[i], enabled);
+ } else {
+ sieve_extension_set_enabled(exts[i], enabled);
+ }
+ }
+ } T_END;
+}
+
+const struct sieve_extension *sieve_get_match_type_extension
+ (struct sieve_instance *svinst)
+{
+ return svinst->ext_reg->match_type_extension;
+}
+
+const struct sieve_extension *sieve_get_comparator_extension
+ (struct sieve_instance *svinst)
+{
+ return svinst->ext_reg->comparator_extension;
+}
+
+const struct sieve_extension *sieve_get_address_part_extension
+ (struct sieve_instance *svinst)
+{
+ return svinst->ext_reg->address_part_extension;
+}
+
+void sieve_enable_debug_extension(struct sieve_instance *svinst)
+{
+ (void) sieve_extension_register(svinst, &vnd_debug_extension, TRUE);
+}
+
+/*
+ * Extension capabilities
+ */
+
+struct sieve_capability_registration {
+ const struct sieve_extension *ext;
+ const struct sieve_extension_capabilities *capabilities;
+};
+
+void sieve_capability_registry_init(struct sieve_instance *svinst)
+{
+ struct sieve_extension_registry *ext_reg = svinst->ext_reg;
+
+ hash_table_create
+ (&ext_reg->capabilities_index, default_pool, 0, str_hash, strcmp);
+}
+
+void sieve_capability_registry_deinit(struct sieve_instance *svinst)
+{
+ struct sieve_extension_registry *ext_reg = svinst->ext_reg;
+
+ if ( !hash_table_is_created(ext_reg->capabilities_index) ) return;
+
+ hash_table_destroy(&svinst->ext_reg->capabilities_index);
+}
+
+void sieve_extension_capabilities_register
+(const struct sieve_extension *ext,
+ const struct sieve_extension_capabilities *cap)
+{
+ struct sieve_instance *svinst = ext->svinst;
+ struct sieve_extension_registry *ext_reg = svinst->ext_reg;
+ struct sieve_capability_registration *reg;
+
+ reg = hash_table_lookup(ext_reg->capabilities_index, cap->name);
+ if (reg != NULL) {
+ /* Already registered */
+ return;
+ }
+
+ reg = p_new(svinst->pool, struct sieve_capability_registration, 1);
+ reg->ext = ext;
+ reg->capabilities = cap;
+
+ hash_table_insert(ext_reg->capabilities_index, cap->name, reg);
+}
+
+void sieve_extension_capabilities_unregister
+(const struct sieve_extension *ext)
+{
+ struct sieve_extension_registry *ext_reg = ext->svinst->ext_reg;
+ struct hash_iterate_context *hictx;
+ const char *name;
+ struct sieve_capability_registration *reg;
+
+ hictx = hash_table_iterate_init(ext_reg->capabilities_index);
+ while ( hash_table_iterate(hictx, ext_reg->capabilities_index, &name, &reg) ) {
+ if ( reg->ext == ext )
+ hash_table_remove(ext_reg->capabilities_index, name);
+ }
+ hash_table_iterate_deinit(&hictx);
+}
+
+const char *sieve_extension_capabilities_get_string
+(struct sieve_instance *svinst, const char *cap_name)
+{
+ struct sieve_extension_registry *ext_reg = svinst->ext_reg;
+ const struct sieve_capability_registration *cap_reg =
+ hash_table_lookup(ext_reg->capabilities_index, cap_name);
+ const struct sieve_extension_capabilities *cap;
+
+ if ( cap_reg == NULL || cap_reg->capabilities == NULL )
+ return NULL;
+
+ cap = cap_reg->capabilities;
+
+ if ( cap->get_string == NULL || !cap_reg->ext->enabled )
+ return NULL;
+
+ return cap->get_string(cap_reg->ext);
+}
+
+
+
+
diff --git a/pigeonhole/src/lib-sieve/sieve-extensions.h b/pigeonhole/src/lib-sieve/sieve-extensions.h
new file mode 100644
index 0000000..961cf41
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-extensions.h
@@ -0,0 +1,191 @@
+#ifndef SIEVE_EXTENSIONS_H
+#define SIEVE_EXTENSIONS_H
+
+#include "lib.h"
+#include "sieve-common.h"
+
+/*
+ * Per-extension object registry
+ */
+
+struct sieve_extension_objects {
+ const void *objects;
+ unsigned int count;
+};
+
+/*
+ * Extension definition
+ */
+
+struct sieve_extension_def {
+ const char *name;
+
+ /* Version */
+ unsigned int version;
+
+ /* Registration */
+ bool (*load)(const struct sieve_extension *ext, void **context);
+ void (*unload)(const struct sieve_extension *ext);
+
+ /* Compilation */
+ bool (*validator_load)
+ (const struct sieve_extension *ext, struct sieve_validator *validator);
+ bool (*generator_load)
+ (const struct sieve_extension *ext, const struct sieve_codegen_env *cgenv);
+ bool (*interpreter_load)
+ (const struct sieve_extension *ext, const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+ bool (*binary_load)
+ (const struct sieve_extension *ext, struct sieve_binary *binary);
+
+ /* Code dump */
+ bool (*binary_dump)
+ (const struct sieve_extension *ext, struct sieve_dumptime_env *denv);
+ bool (*code_dump)
+ (const struct sieve_extension *ext, const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+
+ /* Objects */
+ struct sieve_extension_objects operations;
+ struct sieve_extension_objects operands;
+};
+
+/* Defining opcodes and operands */
+
+#define SIEVE_EXT_DEFINE_NO_OBJECTS \
+ { NULL, 0 }
+#define SIEVE_EXT_DEFINE_OBJECT(OBJ) \
+ { &OBJ, 1 }
+#define SIEVE_EXT_DEFINE_OBJECTS(OBJS) \
+ { OBJS, N_ELEMENTS(OBJS) }
+
+#define SIEVE_EXT_GET_OBJECTS_COUNT(ext, field) \
+ ext->field->count;
+
+#define SIEVE_EXT_DEFINE_NO_OPERATIONS \
+ .operations = SIEVE_EXT_DEFINE_NO_OBJECTS
+#define SIEVE_EXT_DEFINE_OPERATION(OP) \
+ .operations = SIEVE_EXT_DEFINE_OBJECT(OP)
+#define SIEVE_EXT_DEFINE_OPERATIONS(OPS) \
+ .operations = SIEVE_EXT_DEFINE_OBJECTS(OPS)
+
+#define SIEVE_EXT_DEFINE_NO_OPERANDS \
+ .operands = SIEVE_EXT_DEFINE_NO_OBJECTS
+#define SIEVE_EXT_DEFINE_OPERAND(OP) \
+ .operands = SIEVE_EXT_DEFINE_OBJECT(OP)
+#define SIEVE_EXT_DEFINE_OPERANDS(OPS) \
+ .operands = SIEVE_EXT_DEFINE_OBJECTS(OPS)
+
+/*
+ * Extension instance
+ */
+
+struct sieve_extension {
+ const struct sieve_extension_def *def;
+ int id;
+
+ struct sieve_instance *svinst;
+ void *context;
+
+ bool required:1;
+ bool loaded:1;
+ bool enabled:1;
+ bool dummy:1;
+ bool global:1;
+ bool implicit:1;
+ bool overridden:1;
+};
+
+#define sieve_extension_is(ext, definition) \
+ ( (ext)->def == &(definition) )
+#define sieve_extension_name(ext) \
+ ((ext)->def->name)
+#define sieve_extension_name_is(ext, _name) \
+ ( strcmp((ext)->def->name, (_name)) == 0 )
+#define sieve_extension_version(ext) \
+ ((ext)->def->version)
+#define sieve_extension_version_is(ext, _version) \
+ ((ext)->def->version == (_version))
+
+/*
+ * Extensions init/deinit
+ */
+
+bool sieve_extensions_init(struct sieve_instance *svinst);
+void sieve_extensions_configure(struct sieve_instance *svinst);
+void sieve_extensions_deinit(struct sieve_instance *svinst);
+
+/*
+ * Pre-loaded extensions
+ */
+
+const struct sieve_extension *const *sieve_extensions_get_preloaded
+ (struct sieve_instance *svinst, unsigned int *count_r);
+
+/*
+ * Extension registry
+ */
+
+const struct sieve_extension *sieve_extension_register
+ (struct sieve_instance *svinst, const struct sieve_extension_def *extension,
+ bool load);
+const struct sieve_extension *sieve_extension_require
+ (struct sieve_instance *svinst, const struct sieve_extension_def *extension,
+ bool load);
+bool sieve_extension_reload(const struct sieve_extension *ext);
+
+void sieve_extension_unregister(const struct sieve_extension *ext);
+
+const struct sieve_extension *sieve_extension_replace
+ (struct sieve_instance *svinst,
+ const struct sieve_extension_def *extdef,
+ bool load);
+void sieve_extension_override
+ (struct sieve_instance *svinst, const char *name,
+ const struct sieve_extension *ext);
+
+unsigned int sieve_extensions_get_count(struct sieve_instance *svinst);
+const struct sieve_extension *const *
+sieve_extensions_get_all(struct sieve_instance *svinst,
+ unsigned int *count_r);
+
+const struct sieve_extension *sieve_extension_get_by_id
+ (struct sieve_instance *svinst, unsigned int ext_id);
+const struct sieve_extension *sieve_extension_get_by_name
+ (struct sieve_instance *svinst, const char *name);
+
+const char *sieve_extensions_get_string
+ (struct sieve_instance *svinst);
+void sieve_extensions_set_string
+ (struct sieve_instance *svinst, const char *ext_string,
+ bool global, bool implicit);
+
+const struct sieve_extension *sieve_get_match_type_extension
+ (struct sieve_instance *svinst);
+const struct sieve_extension *sieve_get_comparator_extension
+ (struct sieve_instance *svinst);
+const struct sieve_extension *sieve_get_address_part_extension
+ (struct sieve_instance *svinst);
+
+void sieve_enable_debug_extension(struct sieve_instance *svinst);
+
+/*
+ * Capability registries
+ */
+
+struct sieve_extension_capabilities {
+ const char *name;
+
+ const char *(*get_string)(const struct sieve_extension *ext);
+};
+
+void sieve_extension_capabilities_register
+ (const struct sieve_extension *ext,
+ const struct sieve_extension_capabilities *cap);
+void sieve_extension_capabilities_unregister
+ (const struct sieve_extension *ext);
+
+const char *sieve_extension_capabilities_get_string
+ (struct sieve_instance *svinst, const char *cap_name);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-generator.c b/pigeonhole/src/lib-sieve/sieve-generator.c
new file mode 100644
index 0000000..ebc06ed
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-generator.c
@@ -0,0 +1,578 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "mempool.h"
+
+#include "sieve-common.h"
+#include "sieve-script.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+
+#include "sieve-generator.h"
+
+/*
+ * Jump list
+ */
+
+struct sieve_jumplist *
+sieve_jumplist_create(pool_t pool, struct sieve_binary_block *sblock)
+{
+ struct sieve_jumplist *jlist;
+
+ jlist = p_new(pool, struct sieve_jumplist, 1);
+ jlist->block = sblock;
+ p_array_init(&jlist->jumps, pool, 4);
+
+ return jlist;
+}
+
+void sieve_jumplist_init_temp(struct sieve_jumplist *jlist,
+ struct sieve_binary_block *sblock)
+{
+ jlist->block = sblock;
+ t_array_init(&jlist->jumps, 4);
+}
+
+void sieve_jumplist_reset(struct sieve_jumplist *jlist)
+{
+ array_clear(&jlist->jumps);
+}
+
+void sieve_jumplist_add(struct sieve_jumplist *jlist, sieve_size_t jump)
+{
+ array_append(&jlist->jumps, &jump, 1);
+}
+
+void sieve_jumplist_resolve(struct sieve_jumplist *jlist)
+{
+ unsigned int i;
+
+ for (i = 0; i < array_count(&jlist->jumps); i++) {
+ const sieve_size_t *jump = array_idx(&jlist->jumps, i);
+
+ sieve_binary_resolve_offset(jlist->block, *jump);
+ }
+}
+
+/*
+ * Code Generator
+ */
+
+struct sieve_generator {
+ pool_t pool;
+
+ struct sieve_instance *instance;
+
+ struct sieve_error_handler *ehandler;
+
+ struct sieve_codegen_env genenv;
+ struct sieve_binary_debug_writer *dwriter;
+
+ ARRAY(void *) ext_contexts;
+};
+
+struct sieve_generator *
+sieve_generator_create(struct sieve_ast *ast,
+ struct sieve_error_handler *ehandler,
+ enum sieve_compile_flags flags)
+{
+ pool_t pool;
+ struct sieve_generator *gentr;
+ struct sieve_script *script;
+ struct sieve_instance *svinst;
+
+ pool = pool_alloconly_create("sieve_generator", 4096);
+ gentr = p_new(pool, struct sieve_generator, 1);
+ gentr->pool = pool;
+
+ gentr->ehandler = ehandler;
+ sieve_error_handler_ref(ehandler);
+
+ gentr->genenv.gentr = gentr;
+ gentr->genenv.flags = flags;
+ gentr->genenv.ast = ast;
+ sieve_ast_ref(ast);
+
+ script = sieve_ast_script(ast);
+ svinst = sieve_script_svinst(script);
+
+ gentr->genenv.script = script;
+ gentr->genenv.svinst = svinst;
+
+ /* Setup storage for extension contexts */
+ p_array_init(&gentr->ext_contexts, pool,
+ sieve_extensions_get_count(svinst));
+
+ return gentr;
+}
+
+void sieve_generator_free(struct sieve_generator **gentr)
+{
+ sieve_ast_unref(&(*gentr)->genenv.ast);
+
+ sieve_error_handler_unref(&(*gentr)->ehandler);
+ sieve_binary_debug_writer_deinit(&(*gentr)->dwriter);
+
+ sieve_binary_unref(&(*gentr)->genenv.sbin);
+
+ pool_unref(&((*gentr)->pool));
+
+ *gentr = NULL;
+}
+
+/*
+ * Accessors
+ */
+
+struct sieve_error_handler *
+sieve_generator_error_handler(struct sieve_generator *gentr)
+{
+ return gentr->ehandler;
+}
+
+pool_t sieve_generator_pool(struct sieve_generator *gentr)
+{
+ return gentr->pool;
+}
+
+struct sieve_script *sieve_generator_script(struct sieve_generator *gentr)
+{
+ return gentr->genenv.script;
+}
+
+struct sieve_binary *sieve_generator_get_binary(struct sieve_generator *gentr)
+{
+ return gentr->genenv.sbin;
+}
+
+struct sieve_binary_block *
+sieve_generator_get_block(struct sieve_generator *gentr)
+{
+ return gentr->genenv.sblock;
+}
+
+/*
+ * Extension support
+ */
+
+void sieve_generator_extension_set_context(struct sieve_generator *gentr,
+ const struct sieve_extension *ext,
+ void *context)
+{
+ if (ext->id < 0)
+ return;
+
+ array_idx_set(&gentr->ext_contexts, (unsigned int) ext->id, &context);
+}
+
+const void *
+sieve_generator_extension_get_context(struct sieve_generator *gentr,
+ const struct sieve_extension *ext)
+{
+ void * const *ctx;
+
+ if (ext->id < 0 || ext->id >= (int) array_count(&gentr->ext_contexts))
+ return NULL;
+
+ ctx = array_idx(&gentr->ext_contexts, (unsigned int) ext->id);
+
+ return *ctx;
+}
+
+/*
+ * Code generation API
+ */
+
+static void
+sieve_generate_debug_from_ast_node(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_node *ast_node)
+{
+ sieve_size_t address = sieve_binary_block_get_size(cgenv->sblock);
+ unsigned int line = sieve_ast_node_line(ast_node);
+
+ sieve_binary_debug_emit(cgenv->gentr->dwriter, address, line, 0);
+}
+
+static void
+sieve_generate_debug_from_ast_argument(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_argument *ast_arg)
+{
+ sieve_size_t address = sieve_binary_block_get_size(cgenv->sblock);
+ unsigned int line = sieve_ast_argument_line(ast_arg);
+
+ sieve_binary_debug_emit(cgenv->gentr->dwriter, address, line, 0);
+}
+
+bool sieve_generate_argument(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_argument *arg,
+ struct sieve_command *cmd)
+{
+ const struct sieve_argument_def *arg_def;
+
+ if (arg->argument == NULL || arg->argument->def == NULL)
+ return FALSE;
+
+ arg_def = arg->argument->def;
+
+ if (arg_def->generate == NULL)
+ return TRUE;
+
+ sieve_generate_debug_from_ast_argument(cgenv, arg);
+
+ return arg_def->generate(cgenv, arg, cmd);
+}
+
+bool sieve_generate_arguments(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument **last_arg_r)
+{
+ enum { ARG_START, ARG_OPTIONAL, ARG_POSITIONAL } state = ARG_START;
+ struct sieve_ast_argument *arg =
+ sieve_ast_argument_first(cmd->ast_node);
+
+ /* Generate all arguments with assigned generator function */
+
+ while (arg != NULL) {
+ const struct sieve_argument *argument;
+ const struct sieve_argument_def *arg_def;
+
+ if (arg->argument == NULL || arg->argument->def == NULL)
+ return FALSE;
+
+ argument = arg->argument;
+ arg_def = argument->def;
+
+ switch (state) {
+ case ARG_START:
+ if (argument->id_code == 0)
+ state = ARG_POSITIONAL;
+ else {
+ /* Mark start of optional operands with 0
+ operand identifier */
+ sieve_binary_emit_byte(cgenv->sblock,
+ SIEVE_OPERAND_OPTIONAL);
+
+ /* Emit argument id for optional operand */
+ sieve_binary_emit_byte(
+ cgenv->sblock,
+ (unsigned char)argument->id_code);
+
+ state = ARG_OPTIONAL;
+ }
+ break;
+ case ARG_OPTIONAL:
+ if (argument->id_code == 0)
+ state = ARG_POSITIONAL;
+
+ /* Emit argument id for optional operand (0 marks the
+ end of the optionals) */
+ sieve_binary_emit_byte(
+ cgenv->sblock,
+ (unsigned char)argument->id_code);
+ break;
+ case ARG_POSITIONAL:
+ if (argument->id_code != 0)
+ return FALSE;
+ break;
+ }
+
+ /* Call the generation function for the argument */
+ if (arg_def->generate != NULL) {
+ sieve_generate_debug_from_ast_argument(cgenv, arg);
+
+ if (!arg_def->generate(cgenv, arg, cmd))
+ return FALSE;
+ } else if (state == ARG_POSITIONAL) {
+ break;
+ }
+
+ arg = sieve_ast_argument_next(arg);
+ }
+
+ /* Mark end of optional list if it is still open */
+ if (state == ARG_OPTIONAL)
+ sieve_binary_emit_byte(cgenv->sblock, 0);
+
+ if (last_arg_r != NULL)
+ *last_arg_r = arg;
+
+ return TRUE;
+}
+
+bool sieve_generate_argument_parameters(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument *arg)
+{
+ struct sieve_ast_argument *param = arg->parameters;
+
+ /* Generate all parameters with assigned generator function */
+
+ while (param != NULL) {
+ if (param->argument != NULL && param->argument->def != NULL) {
+ const struct sieve_argument_def *parameter =
+ param->argument->def;
+
+ /* Call the generation function for the parameter */
+ if (parameter->generate != NULL) {
+ sieve_generate_debug_from_ast_argument(
+ cgenv, param);
+
+ if (!parameter->generate(cgenv, param, cmd))
+ return FALSE;
+ }
+ }
+
+ param = sieve_ast_argument_next(param);
+ }
+
+ return TRUE;
+}
+
+bool sieve_generate_test(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_node *tst_node,
+ struct sieve_jumplist *jlist, bool jump_true)
+{
+ struct sieve_command *test;
+ const struct sieve_command_def *tst_def;
+
+ i_assert(tst_node->command != NULL && tst_node->command->def != NULL);
+
+ test = tst_node->command;
+ tst_def = test->def;
+
+ if (tst_def->control_generate != NULL) {
+ sieve_generate_debug_from_ast_node(cgenv, tst_node);
+
+ if (tst_def->control_generate(cgenv, test, jlist, jump_true))
+ return TRUE;
+
+ return FALSE;
+ }
+
+ if (tst_def->generate != NULL) {
+ sieve_generate_debug_from_ast_node(cgenv, tst_node);
+
+ if (tst_def->generate(cgenv, test)) {
+
+ if (jump_true) {
+ sieve_operation_emit(cgenv->sblock, NULL,
+ &sieve_jmptrue_operation);
+ } else {
+ sieve_operation_emit(cgenv->sblock, NULL,
+ &sieve_jmpfalse_operation);
+ }
+ sieve_jumplist_add(
+ jlist,
+ sieve_binary_emit_offset(cgenv->sblock, 0));
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool
+sieve_generate_command(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_node *cmd_node)
+{
+ struct sieve_command *command;
+ const struct sieve_command_def *cmd_def;
+
+ i_assert(cmd_node->command != NULL && cmd_node->command->def != NULL);
+
+ command = cmd_node->command;
+ cmd_def = command->def;
+
+ if (cmd_def->generate != NULL) {
+ sieve_generate_debug_from_ast_node(cgenv, cmd_node);
+
+ return cmd_def->generate(cgenv, command);
+ }
+
+ return TRUE;
+}
+
+bool sieve_generate_block(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_node *block)
+{
+ bool result = TRUE;
+ struct sieve_ast_node *cmd_node;
+
+ T_BEGIN {
+ cmd_node = sieve_ast_command_first(block);
+ while (result && cmd_node != NULL) {
+ result = sieve_generate_command(cgenv, cmd_node);
+ cmd_node = sieve_ast_command_next(cmd_node);
+ }
+ } T_END;
+
+ return result;
+}
+
+struct sieve_binary *
+sieve_generator_run(struct sieve_generator *gentr,
+ struct sieve_binary_block **sblock_r)
+{
+ bool topmost = (sblock_r == NULL || *sblock_r == NULL);
+ struct sieve_binary *sbin;
+ struct sieve_binary_block *sblock, *debug_block;
+ const struct sieve_extension *const *extensions;
+ unsigned int i, ext_count;
+ bool result = TRUE;
+
+ /* Initialize */
+
+ if (topmost) {
+ sbin = sieve_binary_create_new(
+ sieve_ast_script(gentr->genenv.ast));
+ sblock = sieve_binary_block_get(
+ sbin, SBIN_SYSBLOCK_MAIN_PROGRAM);
+ } else {
+ sblock = *sblock_r;
+ sbin = sieve_binary_block_get_binary(sblock);
+ }
+
+ i_assert(sbin != NULL);
+
+ gentr->genenv.sbin = sbin;
+ gentr->genenv.sblock = sblock;
+ sieve_binary_ref(gentr->genenv.sbin);
+
+ /* Create debug block */
+ debug_block = sieve_binary_block_create(sbin);
+ gentr->dwriter = sieve_binary_debug_writer_init(debug_block);
+ (void)sieve_binary_emit_unsigned(
+ sblock, sieve_binary_block_get_id(debug_block));
+
+ /* Load extensions linked to the AST and emit a list in code */
+ extensions = sieve_ast_extensions_get(gentr->genenv.ast, &ext_count);
+ (void) sieve_binary_emit_unsigned(sblock, ext_count);
+ for (i = 0; i < ext_count; i++) {
+ const struct sieve_extension *ext = extensions[i];
+ bool deferred;
+
+ /* Link to binary */
+ (void)sieve_binary_extension_link(sbin, ext);
+
+ /* Emit */
+ sieve_binary_emit_extension(sblock, ext, 0);
+
+ /* Emit deferred flag */
+ deferred = !sieve_ast_extension_is_required(
+ gentr->genenv.ast, ext);
+ sieve_binary_emit_byte(sblock, (deferred ? 1 : 0));
+
+ /* Load */
+ if (ext->def != NULL && ext->def->generator_load != NULL &&
+ !ext->def->generator_load(ext, &gentr->genenv))
+ result = FALSE;
+ }
+
+ /* Generate code */
+
+ if (result) {
+ if (!sieve_generate_block(&gentr->genenv,
+ sieve_ast_root(gentr->genenv.ast))) {
+ result = FALSE;
+ } else if (topmost) {
+ sieve_binary_activate(sbin);
+ }
+ }
+
+ /* Cleanup */
+
+ sieve_binary_unref(&gentr->genenv.sbin);
+ gentr->genenv.sblock = NULL;
+
+ if (!result) {
+ if (topmost) {
+ sieve_binary_unref(&sbin);
+ if (sblock_r != NULL)
+ *sblock_r = NULL;
+ }
+ sbin = NULL;
+ } else {
+ if (sblock_r != NULL)
+ *sblock_r = sblock;
+ }
+
+ return sbin;
+}
+
+/*
+ * Error handling
+ */
+
+#undef sieve_generator_error
+void sieve_generator_error(struct sieve_generator *gentr,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ unsigned int source_line, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_ERROR,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ params.location =
+ sieve_error_script_location(gentr->genenv.script, source_line);
+
+ va_start(args, fmt);
+ sieve_logv(gentr->ehandler, &params, fmt, args);
+ va_end(args);
+}
+
+#undef sieve_generator_warning
+void sieve_generator_warning(struct sieve_generator *gentr,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ unsigned int source_line, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_WARNING,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ params.location =
+ sieve_error_script_location(gentr->genenv.script, source_line);
+
+ va_start(args, fmt);
+ sieve_logv(gentr->ehandler, &params, fmt, args);
+ va_end(args);
+}
+
+#undef sieve_generator_critical
+void sieve_generator_critical(struct sieve_generator *gentr,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ unsigned int source_line, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_ERROR,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ params.location =
+ sieve_error_script_location(gentr->genenv.script, source_line);
+
+ va_start(args, fmt);
+ sieve_criticalv(gentr->genenv.svinst, gentr->ehandler, &params,
+ "Code generation failed", fmt, args);
+ va_end(args);
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-generator.h b/pigeonhole/src/lib-sieve/sieve-generator.h
new file mode 100644
index 0000000..fab2023
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-generator.h
@@ -0,0 +1,121 @@
+#ifndef SIEVE_GENERATOR_H
+#define SIEVE_GENERATOR_H
+
+#include "sieve-common.h"
+
+/*
+ * Code generator
+ */
+
+struct sieve_generator;
+
+struct sieve_codegen_env {
+ struct sieve_generator *gentr;
+
+ struct sieve_instance *svinst;
+ enum sieve_compile_flags flags;
+
+ struct sieve_script *script;
+ struct sieve_ast *ast;
+
+ struct sieve_binary *sbin;
+ struct sieve_binary_block *sblock;
+};
+
+struct sieve_generator *
+sieve_generator_create(struct sieve_ast *ast,
+ struct sieve_error_handler *ehandler,
+ enum sieve_compile_flags flags);
+void sieve_generator_free(struct sieve_generator **generator);
+
+/*
+ * Accessors
+ */
+
+struct sieve_error_handler *
+sieve_generator_error_handler(struct sieve_generator *gentr);
+pool_t sieve_generator_pool(struct sieve_generator *gentr);
+struct sieve_script *sieve_generator_script(struct sieve_generator *gentr);
+struct sieve_binary *sieve_generator_get_binary(struct sieve_generator *gentr);
+struct sieve_binary_block *
+sieve_generator_get_block(struct sieve_generator *gentr);
+
+/*
+ * Extension support
+ */
+
+void sieve_generator_extension_set_context(struct sieve_generator *gentr,
+ const struct sieve_extension *ext,
+ void *context);
+const void *
+sieve_generator_extension_get_context(struct sieve_generator *gentr,
+ const struct sieve_extension *ext);
+
+/*
+ * Jump list
+ */
+
+struct sieve_jumplist {
+ pool_t pool;
+ struct sieve_binary_block *block;
+ ARRAY(sieve_size_t) jumps;
+};
+
+struct sieve_jumplist *
+sieve_jumplist_create(pool_t pool, struct sieve_binary_block *sblock);
+void sieve_jumplist_init_temp(struct sieve_jumplist *jlist,
+ struct sieve_binary_block *sblock);
+void sieve_jumplist_reset(struct sieve_jumplist *jlist);
+void sieve_jumplist_add(struct sieve_jumplist *jlist, sieve_size_t jump);
+void sieve_jumplist_resolve(struct sieve_jumplist *jlist);
+
+/*
+ * Code generation API
+ */
+
+bool sieve_generate_argument(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_argument *arg,
+ struct sieve_command *cmd);
+bool sieve_generate_arguments(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument **last_arg_r);
+bool sieve_generate_argument_parameters(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument *arg);
+
+bool sieve_generate_block(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_node *block);
+bool sieve_generate_test(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_node *tst_node,
+ struct sieve_jumplist *jlist, bool jump_true);
+struct sieve_binary *
+sieve_generator_run(struct sieve_generator *gentr,
+ struct sieve_binary_block **sblock_r);
+
+/*
+ * Error handling
+ */
+
+void sieve_generator_error(struct sieve_generator *gentr,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ unsigned int source_line, const char *fmt, ...)
+ ATTR_FORMAT(5, 6);
+#define sieve_generator_error(gentr, ...) \
+ sieve_generator_error(gentr, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_generator_warning(struct sieve_generator *gentr,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ unsigned int source_line, const char *fmt, ...)
+ ATTR_FORMAT(5, 6);
+#define sieve_generator_warning(gentr, ...) \
+ sieve_generator_warning(gentr, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_generator_critical(struct sieve_generator *gentr,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ unsigned int source_line, const char *fmt, ...)
+ ATTR_FORMAT(5, 6);
+#define sieve_generator_critical(gentr, ...) \
+ sieve_generator_critical(gentr, __FILE__, __LINE__, __VA_ARGS__)
+
+#endif
+
diff --git a/pigeonhole/src/lib-sieve/sieve-interpreter.c b/pigeonhole/src/lib-sieve/sieve-interpreter.c
new file mode 100644
index 0000000..274e142
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-interpreter.c
@@ -0,0 +1,1196 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "ostream.h"
+#include "mempool.h"
+#include "array.h"
+#include "hash.h"
+#include "cpu-limit.h"
+#include "mail-storage.h"
+
+#include "sieve-common.h"
+#include "sieve-limits.h"
+#include "sieve-script.h"
+#include "sieve-error.h"
+#include "sieve-extensions.h"
+#include "sieve-message.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-actions.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-result.h"
+#include "sieve-comparators.h"
+#include "sieve-runtime-trace.h"
+
+#include "sieve-interpreter.h"
+
+#include <string.h>
+
+static struct event_category event_category_sieve_runtime = {
+ .parent = &event_category_sieve,
+ .name = "sieve-runtime",
+};
+
+/*
+ * Interpreter extension
+ */
+
+struct sieve_interpreter_extension_reg {
+ const struct sieve_interpreter_extension *intext;
+ const struct sieve_extension *ext;
+
+ void *context;
+
+ bool deferred:1;
+ bool started:1;
+};
+
+/*
+ * Code loop
+ */
+
+struct sieve_interpreter_loop {
+ unsigned int level;
+ sieve_size_t begin, end;
+ const struct sieve_extension_def *ext_def;
+ pool_t pool;
+ void *context;
+};
+
+/*
+ * Interpreter
+ */
+
+struct sieve_interpreter {
+ pool_t pool;
+ struct sieve_interpreter *parent;
+
+ /* Runtime data for extensions */
+ ARRAY(struct sieve_interpreter_extension_reg) extensions;
+
+ sieve_size_t reset_vector;
+
+ /* Execution status */
+ sieve_size_t pc; /* Program counter */
+
+ /* Loop stack */
+ ARRAY(struct sieve_interpreter_loop) loop_stack;
+ sieve_size_t loop_limit;
+ unsigned int parent_loop_level;
+
+ /* Runtime environment */
+ struct sieve_runtime_env runenv;
+ struct sieve_runtime_trace trace;
+ struct sieve_resource_usage rusage;
+
+ /* Current operation */
+ struct sieve_operation oprtn;
+
+ /* Location information */
+ struct sieve_binary_debug_reader *dreader;
+ unsigned int command_line;
+
+ bool running:1; /* Interpreter is running
+ (may be interrupted) */
+ bool interrupted:1; /* Interpreter interrupt requested */
+ bool test_result:1; /* Result of previous test command */
+};
+
+static struct sieve_interpreter *
+_sieve_interpreter_create(struct sieve_binary *sbin,
+ struct sieve_binary_block *sblock,
+ struct sieve_script *script,
+ struct sieve_interpreter *parent,
+ const struct sieve_execute_env *eenv,
+ struct sieve_error_handler *ehandler) ATTR_NULL(3, 4)
+{
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ unsigned int i, ext_count;
+ struct sieve_interpreter *interp;
+ pool_t pool;
+ struct sieve_instance *svinst;
+ const struct sieve_extension *const *ext_preloaded;
+ unsigned int debug_block_id;
+ sieve_size_t *address;
+ bool success = TRUE;
+
+ pool = pool_alloconly_create("sieve_interpreter", 4096);
+ interp = p_new(pool, struct sieve_interpreter, 1);
+ interp->parent = parent;
+ interp->pool = pool;
+
+ interp->runenv.ehandler = ehandler;
+ sieve_error_handler_ref(ehandler);
+
+ interp->runenv.exec_env = eenv;
+ interp->runenv.interp = interp;
+ interp->runenv.oprtn = &interp->oprtn;
+ interp->runenv.sbin = sbin;
+ interp->runenv.sblock = sblock;
+ sieve_binary_ref(sbin);
+
+ interp->runenv.event = event_create(eenv->event);
+ event_add_category(interp->runenv.event, &event_category_sieve_runtime);
+ event_add_str(interp->runenv.event, "script_name",
+ sieve_binary_script_name(sbin));
+ event_add_str(interp->runenv.event, "script_location",
+ sieve_binary_script_location(sbin));
+ event_add_str(interp->runenv.event, "binary_path",
+ sieve_binary_path(sbin));
+
+ svinst = sieve_binary_svinst(sbin);
+
+ if (senv->trace_log != NULL) {
+ interp->trace.log = senv->trace_log;
+ interp->trace.config = senv->trace_config;
+ interp->trace.indent = 0;
+ interp->runenv.trace = &interp->trace;
+ }
+
+ if (script == NULL)
+ interp->runenv.script = sieve_binary_script(sbin);
+ else
+ interp->runenv.script = script;
+
+ interp->runenv.pc = 0;
+ address = &(interp->runenv.pc);
+
+ sieve_runtime_trace_begin(&(interp->runenv));
+
+ p_array_init(&interp->extensions, pool,
+ sieve_extensions_get_count(svinst));
+
+ interp->parent_loop_level = 0;
+ if (parent != NULL && array_is_created(&parent->loop_stack)) {
+ interp->parent_loop_level = parent->parent_loop_level +
+ array_count(&parent->loop_stack);
+ }
+
+ /* Pre-load core language features implemented as 'extensions' */
+ ext_preloaded = sieve_extensions_get_preloaded(svinst, &ext_count);
+ for (i = 0; i < ext_count; i++) {
+ const struct sieve_extension_def *ext_def =
+ ext_preloaded[i]->def;
+
+ if (ext_def != NULL && ext_def->interpreter_load != NULL) {
+ (void)ext_def->interpreter_load(ext_preloaded[i],
+ &interp->runenv,
+ address);
+ }
+ }
+
+ /* Load debug block */
+ if (sieve_binary_read_unsigned(sblock, address, &debug_block_id)) {
+ struct sieve_binary_block *debug_block =
+ sieve_binary_block_get(sbin, debug_block_id);
+
+ if (debug_block == NULL) {
+ sieve_runtime_trace_error(&interp->runenv,
+ "invalid id for debug block");
+ success = FALSE;
+ } else {
+ /* Initialize debug reader */
+ interp->dreader =
+ sieve_binary_debug_reader_init(debug_block);
+ }
+ }
+
+ /* Load other extensions listed in code */
+ if (success && sieve_binary_read_unsigned(sblock, address,
+ &ext_count)) {
+
+ for (i = 0; i < ext_count; i++) {
+ unsigned int code = 0, deferred;
+ struct sieve_interpreter_extension_reg *reg;
+ const struct sieve_extension *ext;
+
+ if (!sieve_binary_read_extension(sblock, address,
+ &code, &ext) ||
+ !sieve_binary_read_byte(sblock, address,
+ &deferred)) {
+ success = FALSE;
+ break;
+ }
+
+ if (deferred > 0 && ext->id >= 0) {
+ reg = array_idx_get_space(
+ &interp->extensions,
+ (unsigned int)ext->id);
+ reg->deferred = TRUE;
+ }
+
+ if (ext->def != NULL) {
+ if (ext->global &&
+ (eenv->flags & SIEVE_EXECUTE_FLAG_NOGLOBAL) != 0) {
+ sieve_runtime_error(&interp->runenv, NULL,
+ "failed to enable extension `%s': "
+ "its use is restricted to global scripts",
+ sieve_extension_name(ext));
+ success = FALSE;
+ break;
+ }
+
+ if (ext->def->interpreter_load != NULL &&
+ !ext->def->interpreter_load(ext, &interp->runenv,
+ address)) {
+ success = FALSE;
+ break;
+ }
+ }
+ }
+ } else {
+ success = FALSE;
+ }
+
+ if (!success) {
+ sieve_interpreter_free(&interp);
+ interp = NULL;
+ } else {
+ interp->reset_vector = *address;
+ }
+
+ return interp;
+}
+
+struct sieve_interpreter *
+sieve_interpreter_create(struct sieve_binary *sbin,
+ struct sieve_interpreter *parent,
+ const struct sieve_execute_env *eenv,
+ struct sieve_error_handler *ehandler)
+{
+ struct sieve_binary_block *sblock;
+
+ if ((sblock = sieve_binary_block_get(
+ sbin, SBIN_SYSBLOCK_MAIN_PROGRAM)) == NULL)
+ return NULL;
+
+ return _sieve_interpreter_create(sbin, sblock, NULL, parent, eenv,
+ ehandler);
+}
+
+struct sieve_interpreter *
+sieve_interpreter_create_for_block(struct sieve_binary_block *sblock,
+ struct sieve_script *script,
+ struct sieve_interpreter *parent,
+ const struct sieve_execute_env *eenv,
+ struct sieve_error_handler *ehandler)
+{
+ if (sblock == NULL) return NULL;
+
+ return _sieve_interpreter_create(sieve_binary_block_get_binary(sblock),
+ sblock, script, parent, eenv,
+ ehandler);
+}
+
+void sieve_interpreter_free(struct sieve_interpreter **_interp)
+{
+ struct sieve_interpreter *interp = *_interp;
+ struct sieve_runtime_env *renv = &interp->runenv;
+ const struct sieve_interpreter_extension_reg *eregs;
+ struct sieve_interpreter_loop *loops;
+ unsigned int count, i;
+
+ if (interp->running) {
+ struct event_passthrough *e =
+ event_create_passthrough(interp->runenv.event)->
+ set_name("sieve_runtime_script_finished")->
+ add_str("error", "Aborted");
+ e_debug(e->event(), "Aborted running script `%s'",
+ sieve_binary_source(interp->runenv.sbin));
+
+ interp->running = FALSE;
+ }
+
+ if (array_is_created(&interp->loop_stack)) {
+ loops = array_get_modifiable(&interp->loop_stack, &count);
+ for (i = 0; i < count; i++)
+ pool_unref(&loops[i].pool);
+ }
+
+ interp->trace.indent = 0;
+ sieve_runtime_trace_end(renv);
+
+ /* Signal registered extensions that the interpreter is being destroyed */
+ eregs = array_get(&interp->extensions, &count);
+ for (i = 0; i < count; i++) {
+ if (eregs[i].intext != NULL && eregs[i].intext->free != NULL) {
+ eregs[i].intext->free(eregs[i].ext, interp,
+ eregs[i].context);
+ }
+ }
+
+ sieve_binary_debug_reader_deinit(&interp->dreader);
+ sieve_binary_unref(&renv->sbin);
+ sieve_error_handler_unref(&renv->ehandler);
+ event_unref(&renv->event);
+
+ pool_unref(&interp->pool);
+ *_interp = NULL;
+}
+
+/*
+ * Accessors
+ */
+
+pool_t sieve_interpreter_pool(struct sieve_interpreter *interp)
+{
+ return interp->pool;
+}
+
+struct sieve_interpreter *
+sieve_interpreter_get_parent(struct sieve_interpreter *interp)
+{
+ return interp->parent;
+}
+
+struct sieve_script *sieve_interpreter_script(struct sieve_interpreter *interp)
+{
+ return interp->runenv.script;
+}
+
+struct sieve_error_handler *
+sieve_interpreter_get_error_handler(struct sieve_interpreter *interp)
+{
+ return interp->runenv.ehandler;
+}
+
+struct sieve_instance *
+sieve_interpreter_svinst(struct sieve_interpreter *interp)
+{
+ return interp->runenv.exec_env->svinst;
+}
+
+/* Do not use this function for normal sieve extensions. This is intended for
+ * the testsuite only.
+ */
+void sieve_interpreter_set_result(struct sieve_interpreter *interp,
+ struct sieve_result *result)
+{
+ sieve_result_unref(&interp->runenv.result);
+ interp->runenv.result = result;
+ interp->runenv.msgctx = sieve_result_get_message_context(result);
+ sieve_result_ref(result);
+}
+
+/*
+ * Source location
+ */
+
+unsigned int
+sieve_runtime_get_source_location(const struct sieve_runtime_env *renv,
+ sieve_size_t code_address)
+{
+ struct sieve_interpreter *interp = renv->interp;
+
+ if (interp->dreader == NULL)
+ return 0;
+
+ if (interp->command_line == 0) {
+ interp->command_line =
+ sieve_binary_debug_read_line(interp->dreader,
+ renv->oprtn->address);
+ }
+
+ return sieve_binary_debug_read_line(interp->dreader, code_address);
+}
+
+unsigned int
+sieve_runtime_get_command_location(const struct sieve_runtime_env *renv)
+{
+ struct sieve_interpreter *interp = renv->interp;
+
+ if (interp->dreader == NULL)
+ return 0;
+
+ if (interp->command_line == 0) {
+ interp->command_line =
+ sieve_binary_debug_read_line(interp->dreader,
+ renv->oprtn->address);
+ }
+
+ return interp->command_line;
+}
+
+const char *
+sieve_runtime_get_full_command_location(const struct sieve_runtime_env *renv)
+{
+ return sieve_error_script_location(
+ renv->script, sieve_runtime_get_command_location(renv));
+}
+
+/*
+ * Extension support
+ */
+
+void sieve_interpreter_extension_register(
+ struct sieve_interpreter *interp, const struct sieve_extension *ext,
+ const struct sieve_interpreter_extension *intext, void *context)
+{
+ struct sieve_interpreter_extension_reg *reg;
+
+ if (ext->id < 0)
+ return;
+
+ reg = array_idx_get_space(&interp->extensions, (unsigned int) ext->id);
+ reg->intext = intext;
+ reg->ext = ext;
+ reg->context = context;
+}
+
+void sieve_interpreter_extension_set_context(struct sieve_interpreter *interp,
+ const struct sieve_extension *ext,
+ void *context)
+{
+ struct sieve_interpreter_extension_reg *reg;
+
+ if (ext->id < 0)
+ return;
+
+ reg = array_idx_get_space(&interp->extensions, (unsigned int) ext->id);
+ reg->context = context;
+}
+
+void *sieve_interpreter_extension_get_context(struct sieve_interpreter *interp,
+ const struct sieve_extension *ext)
+{
+ const struct sieve_interpreter_extension_reg *reg;
+
+ if (ext->id < 0 || ext->id >= (int) array_count(&interp->extensions))
+ return NULL;
+
+ reg = array_idx(&interp->extensions, (unsigned int) ext->id);
+
+ return reg->context;
+}
+
+int sieve_interpreter_extension_start(struct sieve_interpreter *interp,
+ const struct sieve_extension *ext)
+{
+ struct sieve_interpreter_extension_reg *reg;
+ int ret;
+
+ i_assert(ext->id >= 0);
+
+ if (ext->id >= (int) array_count(&interp->extensions))
+ return SIEVE_EXEC_OK;
+
+ reg = array_idx_modifiable(&interp->extensions, (unsigned int)ext->id);
+
+ if (!reg->deferred)
+ return SIEVE_EXEC_OK;
+ reg->deferred = FALSE;
+ reg->started = TRUE;
+
+ if (reg->intext != NULL && reg->intext->run != NULL &&
+ (ret = reg->intext->run(ext, &interp->runenv,
+ reg->context, TRUE)) <= 0)
+ return ret;
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Loop handling
+ */
+
+int sieve_interpreter_loop_start(struct sieve_interpreter *interp,
+ sieve_size_t loop_end,
+ const struct sieve_extension_def *ext_def,
+ struct sieve_interpreter_loop **loop_r)
+{
+ const struct sieve_runtime_env *renv = &interp->runenv;
+ struct sieve_interpreter_loop *loop;
+
+ i_assert(loop_end > interp->runenv.pc);
+
+ /* Check supplied end offset */
+ if (loop_end > sieve_binary_block_get_size(renv->sblock)) {
+ sieve_runtime_trace_error(renv, "loop end offset out of range");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ /* Trace */
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
+ unsigned int line =
+ sieve_runtime_get_source_location(renv, loop_end);
+
+ if (sieve_runtime_trace_hasflag(renv, SIEVE_TRFLG_ADDRESSES)) {
+ sieve_runtime_trace(renv, 0,
+ "loop ends at line %d [%08llx]",
+ line,
+ (long long unsigned int) loop_end);
+ } else {
+ sieve_runtime_trace(renv, 0,
+ "loop ends at line %d", line);
+ }
+ }
+
+ /* Check loop nesting limit */
+ if (!array_is_created(&interp->loop_stack))
+ p_array_init(&interp->loop_stack, interp->pool, 8);
+ if ((interp->parent_loop_level +
+ array_count(&interp->loop_stack)) >= SIEVE_MAX_LOOP_DEPTH) {
+ /* Should normally be caught at compile time */
+ sieve_runtime_error(renv, NULL,
+ "new program loop exceeds "
+ "the nesting limit (<= %u levels)",
+ SIEVE_MAX_LOOP_DEPTH);
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ /* Create new loop */
+ loop = array_append_space(&interp->loop_stack);
+ loop->level = array_count(&interp->loop_stack)-1;
+ loop->ext_def = ext_def;
+ loop->begin = interp->runenv.pc;
+ loop->end = loop_end;
+ loop->pool = pool_alloconly_create("sieve_interpreter", 128);
+
+ /* Set new loop limit */
+ interp->loop_limit = loop_end;
+
+ *loop_r = loop;
+ return SIEVE_EXEC_OK;
+}
+
+struct sieve_interpreter_loop *
+sieve_interpreter_loop_get(struct sieve_interpreter *interp,
+ sieve_size_t loop_end,
+ const struct sieve_extension_def *ext_def)
+{
+ struct sieve_interpreter_loop *loops;
+ unsigned int count, i;
+
+ if (!array_is_created(&interp->loop_stack))
+ return NULL;
+
+ loops = array_get_modifiable(&interp->loop_stack, &count);
+ for (i = count; i > 0; i--) {
+ /* We're really making sure our loop matches */
+ if (loops[i-1].end == loop_end &&
+ loops[i-1].ext_def == ext_def)
+ return &loops[i-1];
+ }
+ return NULL;
+}
+
+int sieve_interpreter_loop_next(struct sieve_interpreter *interp,
+ struct sieve_interpreter_loop *loop,
+ sieve_size_t loop_begin)
+{
+ const struct sieve_runtime_env *renv = &interp->runenv;
+ struct sieve_interpreter_loop *loops;
+ unsigned int count;
+
+ /* Trace */
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
+ unsigned int line =
+ sieve_runtime_get_source_location(renv, loop_begin);
+
+ if (sieve_runtime_trace_hasflag(renv, SIEVE_TRFLG_ADDRESSES)) {
+ sieve_runtime_trace(renv, 0,
+ "looping back to line %d [%08llx]",
+ line,
+ (long long unsigned int) loop_begin);
+ } else {
+ sieve_runtime_trace(renv, 0,
+ "looping back to line %d", line);
+ }
+ }
+
+ /* Check the code for corruption */
+ if (loop->begin != loop_begin) {
+ sieve_runtime_trace_error(renv, "loop begin offset invalid");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ /* Check invariants */
+ i_assert(array_is_created(&interp->loop_stack));
+ loops = array_get_modifiable(&interp->loop_stack, &count);
+ i_assert(&loops[count-1] == loop);
+
+ /* Return to beginning */
+ interp->runenv.pc = loop_begin;
+ return SIEVE_EXEC_OK;
+}
+
+int sieve_interpreter_loop_break(struct sieve_interpreter *interp,
+ struct sieve_interpreter_loop *loop)
+{
+ const struct sieve_runtime_env *renv = &interp->runenv;
+ struct sieve_interpreter_loop *loops;
+ sieve_size_t loop_end = loop->end;
+ unsigned int count, i;
+
+ /* Find the loop */
+ i_assert(array_is_created(&interp->loop_stack));
+ loops = array_get_modifiable(&interp->loop_stack, &count);
+ i_assert(count > 0);
+
+ i = count;
+ do {
+ pool_unref(&loops[i-1].pool);
+ i--;
+ } while (i > 0 && &loops[i] != loop);
+ i_assert(&loops[i] == loop);
+
+ /* Set new loop limit */
+ if (i > 0)
+ interp->loop_limit = loops[i].end;
+ else
+ interp->loop_limit = 0;
+
+ /* Delete it and all deeper loops */
+ array_delete(&interp->loop_stack, i, count - i);
+
+ /* Trace */
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
+ unsigned int jmp_line =
+ sieve_runtime_get_source_location(renv, loop_end);
+
+ if (sieve_runtime_trace_hasflag(renv, SIEVE_TRFLG_ADDRESSES)) {
+ sieve_runtime_trace(renv, 0,
+ "exiting loops at line %d [%08llx]",
+ jmp_line,
+ (long long unsigned int) loop_end);
+ } else {
+ sieve_runtime_trace(renv, 0,
+ "exiting loops at line %d",
+ jmp_line);
+ }
+ }
+
+ /* Exit loop */
+ interp->runenv.pc = loop->end;
+ return SIEVE_EXEC_OK;
+}
+
+static int
+sieve_interpreter_loop_break_out(struct sieve_interpreter *interp,
+ sieve_size_t target)
+{
+ struct sieve_interpreter_loop *loops;
+ unsigned int count, i;
+
+ if (!array_is_created(&interp->loop_stack))
+ return SIEVE_EXEC_OK;
+
+ loops = array_get_modifiable(&interp->loop_stack, &count);
+ for (i = count; i > 0; i--) {
+ /* We're really making sure our loop matches */
+ if (loops[i-1].end > target)
+ break;
+ }
+ if (i == count)
+ return SIEVE_EXEC_OK;
+
+ return sieve_interpreter_loop_break(interp, &loops[i]);
+}
+
+struct sieve_interpreter_loop *
+sieve_interpreter_loop_get_local(struct sieve_interpreter *interp,
+ struct sieve_interpreter_loop *loop,
+ const struct sieve_extension_def *ext_def)
+{
+ struct sieve_interpreter_loop *loops;
+ unsigned int count, i;
+
+ if (!array_is_created(&interp->loop_stack))
+ return NULL;
+
+ loops = array_get_modifiable(&interp->loop_stack, &count);
+ i_assert(loop == NULL || loop->level < count);
+
+ for (i = (loop == NULL ? count : loop->level); i > 0; i--) {
+ if (ext_def == NULL || loops[i-1].ext_def == ext_def)
+ return &loops[i-1];
+ }
+ return NULL;
+}
+
+struct sieve_interpreter_loop *
+sieve_interpreter_loop_get_global(struct sieve_interpreter *interp,
+ struct sieve_interpreter_loop *loop,
+ const struct sieve_extension_def *ext_def)
+{
+ struct sieve_interpreter_loop *result;
+
+ while (interp != NULL) {
+ result = sieve_interpreter_loop_get_local(interp, loop,
+ ext_def);
+ if (result != NULL)
+ return result;
+ interp = interp->parent;
+ }
+ return NULL;
+}
+
+pool_t sieve_interpreter_loop_get_pool(struct sieve_interpreter_loop *loop)
+{
+ return loop->pool;
+}
+
+void *sieve_interpreter_loop_get_context(struct sieve_interpreter_loop *loop)
+{
+ return loop->context;
+}
+
+void sieve_interpreter_loop_set_context(struct sieve_interpreter_loop *loop,
+ void *context)
+{
+ loop->context = context;
+}
+
+/*
+ * Program flow
+ */
+
+void sieve_interpreter_reset(struct sieve_interpreter *interp)
+{
+ interp->runenv.pc = interp->reset_vector;
+ interp->interrupted = FALSE;
+ interp->test_result = FALSE;
+ interp->runenv.result = NULL;
+}
+
+void sieve_interpreter_interrupt(struct sieve_interpreter *interp)
+{
+ interp->interrupted = TRUE;
+}
+
+sieve_size_t sieve_interpreter_program_counter(struct sieve_interpreter *interp)
+{
+ return interp->runenv.pc;
+}
+
+static int
+sieve_interpreter_check_program_jump(struct sieve_interpreter *interp,
+ sieve_size_t jmp_target, bool break_loops)
+{
+ const struct sieve_runtime_env *renv = &interp->runenv;
+ sieve_size_t loop_limit = (break_loops ? 0 : interp->loop_limit);
+
+ if (jmp_target == 0 ||
+ jmp_target > sieve_binary_block_get_size(renv->sblock) ||
+ (loop_limit > 0 && jmp_target >= loop_limit)) {
+ if (interp->loop_limit != 0) {
+ sieve_runtime_trace_error(
+ renv, "jump target crosses loop boundary");
+ } else {
+ sieve_runtime_trace_error(
+ renv, "jump target out of range");
+ }
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ return SIEVE_EXEC_OK;
+}
+
+static int
+sieve_interpreter_do_program_jump(struct sieve_interpreter *interp,
+ sieve_size_t jmp_target, bool break_loops)
+{
+ const struct sieve_runtime_env *renv = &interp->runenv;
+ sieve_size_t *address = &(interp->runenv.pc);
+ int ret;
+
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
+ unsigned int jmp_line =
+ sieve_runtime_get_source_location(renv, jmp_target);
+
+ if (sieve_runtime_trace_hasflag(renv, SIEVE_TRFLG_ADDRESSES)) {
+ sieve_runtime_trace(renv, 0, "jumping to line %d [%08llx]",
+ jmp_line,
+ (long long unsigned int)jmp_target);
+ } else {
+ sieve_runtime_trace(renv, 0, "jumping to line %d",
+ jmp_line);
+ }
+ }
+
+ if (break_loops &&
+ (ret = sieve_interpreter_loop_break_out(interp,
+ jmp_target)) <= 0)
+ return ret;
+
+ *address = jmp_target;
+ return SIEVE_EXEC_OK;
+}
+
+int sieve_interpreter_program_jump_to(struct sieve_interpreter *interp,
+ sieve_size_t jmp_target,
+ bool break_loops)
+{
+ int ret;
+
+ ret = sieve_interpreter_check_program_jump(interp, jmp_target,
+ break_loops);
+ if (ret <= 0)
+ return ret;
+
+ return sieve_interpreter_do_program_jump(
+ interp, jmp_target, break_loops);
+}
+
+int sieve_interpreter_program_jump(struct sieve_interpreter *interp,
+ bool jump, bool break_loops)
+{
+ const struct sieve_runtime_env *renv = &interp->runenv;
+ sieve_size_t *address = &(interp->runenv.pc);
+ sieve_size_t jmp_start = *address, jmp_target;
+ sieve_offset_t jmp_offset;
+ int ret;
+
+ if (!sieve_binary_read_offset(renv->sblock, address, &jmp_offset)) {
+ sieve_runtime_trace_error(renv, "invalid jump offset");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ jmp_target = jmp_start + jmp_offset;
+
+ ret = sieve_interpreter_check_program_jump(interp, jmp_target,
+ break_loops);
+ if (ret <= 0)
+ return ret;
+
+ if (!jump) {
+ sieve_runtime_trace(renv, 0, "not jumping");
+ return SIEVE_EXEC_OK;
+ }
+
+ return sieve_interpreter_do_program_jump(
+ interp, jmp_target, break_loops);
+}
+
+/*
+ * Test results
+ */
+
+void sieve_interpreter_set_test_result(struct sieve_interpreter *interp,
+ bool result)
+{
+ interp->test_result = result;
+}
+
+bool sieve_interpreter_get_test_result(struct sieve_interpreter *interp)
+{
+ return interp->test_result;
+}
+
+/*
+ * Code execute
+ */
+
+static int sieve_interpreter_operation_execute(struct sieve_interpreter *interp)
+{
+ struct sieve_operation *oprtn = &(interp->oprtn);
+ sieve_size_t *address = &(interp->runenv.pc);
+
+ sieve_runtime_trace_toplevel(&interp->runenv);
+
+ /* Read the operation */
+ if (sieve_operation_read(interp->runenv.sblock, address, oprtn)) {
+ const struct sieve_operation_def *op = oprtn->def;
+ int result = SIEVE_EXEC_OK;
+
+ /* Reset cached command location */
+ interp->command_line = 0;
+
+ /* Execute the operation */
+ if (op->execute != NULL) { /* Noop ? */
+ T_BEGIN {
+ result = op->execute(&(interp->runenv),
+ address);
+ } T_END;
+ } else {
+ sieve_runtime_trace(&interp->runenv,
+ SIEVE_TRLVL_COMMANDS,
+ "OP: %s (NOOP)",
+ sieve_operation_mnemonic(oprtn));
+ }
+
+ return result;
+ }
+
+ /* Binary corrupt */
+ sieve_runtime_trace_error(&interp->runenv,
+ "Encountered invalid operation");
+ return SIEVE_EXEC_BIN_CORRUPT;
+}
+
+int sieve_interpreter_continue(struct sieve_interpreter *interp,
+ bool *interrupted)
+{
+ const struct sieve_runtime_env *renv = &interp->runenv;
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ struct cpu_limit *climit = NULL;
+ sieve_size_t *address = &(interp->runenv.pc);
+ struct sieve_instance *svinst = eenv->svinst;
+ struct sieve_exec_status *exec_status = eenv->exec_status;
+ struct sieve_resource_usage rusage;
+ int ret = SIEVE_EXEC_OK;
+
+ sieve_result_ref(renv->result);
+ interp->interrupted = FALSE;
+
+ if (interrupted != NULL)
+ *interrupted = FALSE;
+
+ if (svinst->max_cpu_time_secs > 0) {
+ climit = cpu_limit_init(svinst->max_cpu_time_secs,
+ CPU_LIMIT_TYPE_USER);
+ }
+
+ while (ret == SIEVE_EXEC_OK && !interp->interrupted &&
+ *address < sieve_binary_block_get_size(renv->sblock)) {
+ if (climit != NULL && cpu_limit_exceeded(climit)) {
+ sieve_runtime_error(
+ renv, NULL,
+ "execution exceeded CPU time limit");
+ ret = SIEVE_EXEC_RESOURCE_LIMIT;
+ break;
+ }
+ if (interp->loop_limit != 0 && *address > interp->loop_limit) {
+ sieve_runtime_trace_error(
+ renv, "program crossed loop boundary");
+ ret = SIEVE_EXEC_BIN_CORRUPT;
+ break;
+ }
+
+ ret = sieve_interpreter_operation_execute(interp);
+ }
+
+ if (climit != NULL) {
+ sieve_resource_usage_init(&rusage);
+ rusage.cpu_time_msecs =
+ cpu_limit_get_usage_msecs(climit, CPU_LIMIT_TYPE_USER);
+ sieve_resource_usage_add(&interp->rusage, &rusage);
+
+ cpu_limit_deinit(&climit);
+ }
+
+ if (ret != SIEVE_EXEC_OK) {
+ sieve_runtime_trace(&interp->runenv, SIEVE_TRLVL_NONE,
+ "[[EXECUTION ABORTED]]");
+ }
+
+ if (interrupted != NULL)
+ *interrupted = interp->interrupted;
+
+ if (!interp->interrupted) {
+ exec_status->resource_usage = interp->rusage;
+
+ struct event_passthrough *e =
+ event_create_passthrough(interp->runenv.event)->
+ set_name("sieve_runtime_script_finished");
+ switch (ret) {
+ case SIEVE_EXEC_OK:
+ break;
+ case SIEVE_EXEC_FAILURE:
+ e->add_str("error", "Failed");
+ break;
+ case SIEVE_EXEC_TEMP_FAILURE:
+ e->add_str("error", "Failed temporarily");
+ break;
+ case SIEVE_EXEC_BIN_CORRUPT:
+ e->add_str("error", "Binary corrupt");
+ break;
+ case SIEVE_EXEC_RESOURCE_LIMIT:
+ e->add_str("error", "Resource limit exceeded");
+ break;
+ case SIEVE_EXEC_KEEP_FAILED:
+ /* Not supposed to occur at runtime */
+ i_unreached();
+ }
+ e_debug(e->event(), "Finished running script `%s' "
+ "(status=%s, resource usage: %s)",
+ sieve_binary_source(interp->runenv.sbin),
+ sieve_execution_exitcode_to_str(ret),
+ sieve_resource_usage_get_summary(&interp->rusage));
+ interp->running = FALSE;
+ }
+
+ sieve_result_unref(&interp->runenv.result);
+ return ret;
+}
+
+int sieve_interpreter_start(struct sieve_interpreter *interp,
+ struct sieve_result *result, bool *interrupted)
+{
+ struct sieve_interpreter_extension_reg *eregs;
+ unsigned int ext_count, i;
+ int ret;
+
+ struct event_passthrough *e =
+ event_create_passthrough(interp->runenv.event)->
+ set_name("sieve_runtime_script_started");
+ e_debug(e->event(), "Started running script `%s'",
+ sieve_binary_source(interp->runenv.sbin));
+
+ interp->running = TRUE;
+ interp->runenv.result = result;
+ interp->runenv.msgctx = sieve_result_get_message_context(result);
+
+ sieve_resource_usage_init(&interp->rusage);
+
+ /* Signal registered extensions that the interpreter is being run */
+ eregs = array_get_modifiable(&interp->extensions, &ext_count);
+ for (i = 0; i < ext_count; i++) {
+ if (!eregs[i].deferred) {
+ eregs[i].started = TRUE;
+ if (eregs[i].intext != NULL &&
+ eregs[i].intext->run != NULL &&
+ (ret = eregs[i].intext->run(
+ eregs[i].ext, &interp->runenv,
+ eregs[i].context, FALSE)) <= 0)
+ return ret;
+ }
+ }
+
+ return sieve_interpreter_continue(interp, interrupted);
+}
+
+int sieve_interpreter_run(struct sieve_interpreter *interp,
+ struct sieve_result *result)
+{
+ sieve_interpreter_reset(interp);
+
+ return sieve_interpreter_start(interp, result, NULL);
+}
+
+/*
+ * Error handling
+ */
+
+static inline void ATTR_FORMAT(3, 0)
+sieve_runtime_logv(const struct sieve_runtime_env *renv,
+ const struct sieve_error_params *params,
+ const char *fmt, va_list args)
+{
+ struct sieve_error_params new_params = *params;
+
+ new_params.event = renv->event;
+ T_BEGIN {
+ if (new_params.location == NULL) {
+ new_params.location =
+ sieve_runtime_get_full_command_location(renv);
+ }
+
+ sieve_logv(renv->ehandler, params, fmt, args);
+ } T_END;
+}
+
+#undef sieve_runtime_error
+void sieve_runtime_error(const struct sieve_runtime_env *renv,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_ERROR,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .location = location,
+ };
+ va_list args;
+
+ va_start(args, fmt);
+ sieve_runtime_logv(renv, &params, fmt, args);
+ va_end(args);
+}
+
+#undef sieve_runtime_warning
+void sieve_runtime_warning(const struct sieve_runtime_env *renv,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_WARNING,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .location = location,
+ };
+ va_list args;
+
+ va_start(args, fmt);
+ sieve_runtime_logv(renv, &params, fmt, args);
+ va_end(args);
+}
+
+#undef sieve_runtime_log
+void sieve_runtime_log(const struct sieve_runtime_env *renv,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_INFO,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .location = location,
+ };
+ va_list args;
+
+ va_start(args, fmt);
+ sieve_runtime_logv(renv, &params, fmt, args);
+ va_end(args);
+}
+
+#undef sieve_runtime_critical
+void sieve_runtime_critical(const struct sieve_runtime_env *renv,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *location, const char *user_prefix,
+ const char *fmt, ...)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_ERROR,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ .location = location,
+ };
+ va_list args;
+
+ va_start(args, fmt);
+
+ params.event = renv->event;
+ T_BEGIN {
+ if (params.location == NULL) {
+ params.location =
+ sieve_runtime_get_full_command_location(renv);
+ }
+
+ sieve_criticalv(eenv->svinst, renv->ehandler, &params,
+ user_prefix, fmt, args);
+ } T_END;
+
+ va_end(args);
+}
+
+#undef sieve_runtime_mail_error
+int sieve_runtime_mail_error(const struct sieve_runtime_env *renv,
+ struct mail *mail,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *fmt, ...)
+{
+ const char *error_msg, *user_prefix;
+ va_list args;
+
+ error_msg = mailbox_get_last_internal_error(mail->box, NULL);
+
+ va_start(args, fmt);
+ user_prefix = t_strdup_vprintf(fmt, args);
+ sieve_runtime_critical(renv, csrc_filename, csrc_linenum,
+ NULL, user_prefix, "%s: %s",
+ user_prefix, error_msg);
+ va_end(args);
+
+ return SIEVE_EXEC_TEMP_FAILURE;
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-interpreter.h b/pigeonhole/src/lib-sieve/sieve-interpreter.h
new file mode 100644
index 0000000..ec38029
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-interpreter.h
@@ -0,0 +1,204 @@
+#ifndef SIEVE_INTERPRETER_H
+#define SIEVE_INTERPRETER_H
+
+#include "lib.h"
+#include "array.h"
+#include "buffer.h"
+
+#include "sieve-common.h"
+#include "sieve-runtime.h"
+
+/*
+ * Interpreter
+ */
+
+struct sieve_interpreter *
+sieve_interpreter_create(struct sieve_binary *sbin,
+ struct sieve_interpreter *parent,
+ const struct sieve_execute_env *eenv,
+ struct sieve_error_handler *ehandler) ATTR_NULL(2);
+struct sieve_interpreter *
+sieve_interpreter_create_for_block(struct sieve_binary_block *sblock,
+ struct sieve_script *script,
+ struct sieve_interpreter *parent,
+ const struct sieve_execute_env *eenv,
+ struct sieve_error_handler *ehandler)
+ ATTR_NULL(3);
+void sieve_interpreter_free(struct sieve_interpreter **_interp);
+
+/*
+ * Accessors
+ */
+
+pool_t sieve_interpreter_pool(struct sieve_interpreter *interp);
+struct sieve_interpreter *
+sieve_interpreter_get_parent(struct sieve_interpreter *interp);
+struct sieve_script *sieve_interpreter_script(struct sieve_interpreter *interp);
+struct sieve_error_handler *
+sieve_interpreter_get_error_handler(struct sieve_interpreter *interp);
+struct sieve_instance *
+sieve_interpreter_svinst(struct sieve_interpreter *interp);
+
+/* Do not use this function for normal sieve extensions. This is intended for
+ * the testsuite only.
+ */
+void sieve_interpreter_set_result(struct sieve_interpreter *interp,
+ struct sieve_result *result);
+
+/*
+ * Loop handling
+ */
+
+struct sieve_interpreter_loop;
+
+int sieve_interpreter_loop_start(struct sieve_interpreter *interp,
+ sieve_size_t loop_end,
+ const struct sieve_extension_def *ext_def,
+ struct sieve_interpreter_loop **loop_r);
+struct sieve_interpreter_loop *
+sieve_interpreter_loop_get(struct sieve_interpreter *interp,
+ sieve_size_t loop_end,
+ const struct sieve_extension_def *ext_def);
+int sieve_interpreter_loop_next(struct sieve_interpreter *interp,
+ struct sieve_interpreter_loop *loop,
+ sieve_size_t loop_begin);
+int sieve_interpreter_loop_break(struct sieve_interpreter *interp,
+ struct sieve_interpreter_loop *loop);
+
+struct sieve_interpreter_loop *
+sieve_interpreter_loop_get_local(struct sieve_interpreter *interp,
+ struct sieve_interpreter_loop *loop,
+ const struct sieve_extension_def *ext_def)
+ ATTR_NULL(2, 3);
+struct sieve_interpreter_loop *
+sieve_interpreter_loop_get_global(struct sieve_interpreter *interp,
+ struct sieve_interpreter_loop *loop,
+ const struct sieve_extension_def *ext_def)
+ ATTR_NULL(2, 3);
+
+pool_t sieve_interpreter_loop_get_pool(struct sieve_interpreter_loop *loop)
+ ATTR_PURE;
+void *sieve_interpreter_loop_get_context(struct sieve_interpreter_loop *loop)
+ ATTR_PURE;
+void sieve_interpreter_loop_set_context(struct sieve_interpreter_loop *loop,
+ void *context);
+
+/*
+ * Program flow
+ */
+
+void sieve_interpreter_reset(struct sieve_interpreter *interp);
+void sieve_interpreter_interrupt(struct sieve_interpreter *interp);
+sieve_size_t
+sieve_interpreter_program_counter(struct sieve_interpreter *interp);
+
+int sieve_interpreter_program_jump_to(struct sieve_interpreter *interp,
+ sieve_size_t jmp_target,
+ bool break_loops);
+int sieve_interpreter_program_jump(struct sieve_interpreter *interp, bool jump,
+ bool break_loops);
+
+/*
+ * Test results
+ */
+
+void sieve_interpreter_set_test_result(struct sieve_interpreter *interp,
+ bool result);
+bool sieve_interpreter_get_test_result(struct sieve_interpreter *interp);
+
+/*
+ * Source location
+ */
+
+unsigned int
+sieve_runtime_get_source_location(const struct sieve_runtime_env *renv,
+ sieve_size_t code_address);
+
+unsigned int
+sieve_runtime_get_command_location(const struct sieve_runtime_env *renv);
+const char *
+sieve_runtime_get_full_command_location(const struct sieve_runtime_env *renv);
+
+/*
+ * Extension support
+ */
+
+struct sieve_interpreter_extension {
+ const struct sieve_extension_def *ext_def;
+
+ int (*run)(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ void *context, bool deferred);
+ void (*free)(const struct sieve_extension *ext,
+ struct sieve_interpreter *interp, void *context);
+};
+
+void sieve_interpreter_extension_register(
+ struct sieve_interpreter *interp, const struct sieve_extension *ext,
+ const struct sieve_interpreter_extension *intext, void *context);
+void sieve_interpreter_extension_set_context(
+ struct sieve_interpreter *interp, const struct sieve_extension *ext,
+ void *context);
+void *sieve_interpreter_extension_get_context(
+ struct sieve_interpreter *interp, const struct sieve_extension *ext);
+
+int sieve_interpreter_extension_start(struct sieve_interpreter *interp,
+ const struct sieve_extension *ext);
+
+/*
+ * Opcodes and operands
+ */
+
+int sieve_interpreter_handle_optional_operands(
+ const struct sieve_runtime_env *renv, sieve_size_t *address,
+ struct sieve_side_effects_list **list);
+
+/*
+ * Code execute
+ */
+
+int sieve_interpreter_continue(struct sieve_interpreter *interp,
+ bool *interrupted);
+int sieve_interpreter_start(struct sieve_interpreter *interp,
+ struct sieve_result *result, bool *interrupted);
+int sieve_interpreter_run(struct sieve_interpreter *interp,
+ struct sieve_result *result);
+
+/*
+ * Error handling
+ */
+
+void sieve_runtime_error(const struct sieve_runtime_env *renv,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+ ATTR_FORMAT(5, 6);
+#define sieve_runtime_error(renv, ...) \
+ sieve_runtime_error(renv, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_runtime_warning(const struct sieve_runtime_env *renv,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+ ATTR_FORMAT(5, 6);
+#define sieve_runtime_warning(renv, ...) \
+ sieve_runtime_warning(renv, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_runtime_log(const struct sieve_runtime_env *renv,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *location, const char *fmt, ...)
+ ATTR_FORMAT(5, 6);
+#define sieve_runtime_log(renv, ...) \
+ sieve_runtime_log(renv, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_runtime_critical(const struct sieve_runtime_env *renv,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *location, const char *user_prefix,
+ const char *fmt, ...) ATTR_FORMAT(6, 7);
+#define sieve_runtime_critical(renv, ...) \
+ sieve_runtime_critical(renv, __FILE__, __LINE__, __VA_ARGS__)
+int sieve_runtime_mail_error(const struct sieve_runtime_env *renv,
+ struct mail *mail,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *fmt, ...) ATTR_FORMAT(5, 6);
+#define sieve_runtime_mail_error(renv, mail, ...) \
+ sieve_runtime_mail_error(renv, mail, __FILE__, __LINE__, __VA_ARGS__)
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-lexer.c b/pigeonhole/src/lib-sieve/sieve-lexer.c
new file mode 100644
index 0000000..a6968a9
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-lexer.c
@@ -0,0 +1,930 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "compat.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "istream.h"
+
+#include "sieve-common.h"
+#include "sieve-limits.h"
+#include "sieve-error.h"
+#include "sieve-script.h"
+
+#include "sieve-lexer.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+
+/*
+ * Useful macros
+ */
+
+#define DIGIT_VAL(c) (c - '0')
+
+/*
+ * Lexer object
+ */
+
+struct sieve_lexical_scanner {
+ pool_t pool;
+ struct sieve_instance *svinst;
+
+ struct sieve_script *script;
+ struct istream *input;
+
+ struct sieve_error_handler *ehandler;
+
+ /* Currently scanned data */
+ const unsigned char *buffer;
+ size_t buffer_size;
+ size_t buffer_pos;
+
+ struct sieve_lexer lexer;
+
+ int current_line;
+};
+
+const struct sieve_lexer *
+sieve_lexer_create(struct sieve_script *script,
+ struct sieve_error_handler *ehandler,
+ enum sieve_error *error_r)
+{
+ struct sieve_lexical_scanner *scanner;
+ struct sieve_instance *svinst = sieve_script_svinst(script);
+ struct istream *stream;
+ const struct stat *st;
+
+ /* Open script as stream */
+ if (sieve_script_get_stream(script, &stream, error_r) < 0)
+ return NULL;
+
+ /* Check script size */
+ if (i_stream_stat(stream, TRUE, &st) >= 0 && st->st_size > 0 &&
+ svinst->max_script_size > 0 &&
+ (uoff_t)st->st_size > svinst->max_script_size) {
+ sieve_error(ehandler, sieve_script_name(script),
+ "sieve script is too large (max %zu bytes)",
+ svinst->max_script_size);
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NOT_POSSIBLE;
+ return NULL;
+ }
+
+ scanner = i_new(struct sieve_lexical_scanner, 1);
+ scanner->lexer.scanner = scanner;
+
+ scanner->ehandler = ehandler;
+ sieve_error_handler_ref(ehandler);
+
+ scanner->input = stream;
+ i_stream_ref(scanner->input);
+
+ scanner->script = script;
+ sieve_script_ref(script);
+
+ scanner->buffer = NULL;
+ scanner->buffer_size = 0;
+ scanner->buffer_pos = 0;
+
+ scanner->lexer.token_type = STT_NONE;
+ scanner->lexer.token_str_value = str_new(default_pool, 256);
+ scanner->lexer.token_int_value = 0;
+ scanner->lexer.token_line = 1;
+
+ scanner->current_line = 1;
+
+ return &scanner->lexer;
+}
+
+void sieve_lexer_free(const struct sieve_lexer **_lexer)
+{
+ const struct sieve_lexer *lexer = *_lexer;
+ struct sieve_lexical_scanner *scanner = lexer->scanner;
+
+ i_stream_unref(&scanner->input);
+ sieve_script_unref(&scanner->script);
+ sieve_error_handler_unref(&scanner->ehandler);
+ str_free(&scanner->lexer.token_str_value);
+
+ i_free(scanner);
+ *_lexer = NULL;
+}
+
+/*
+ * Internal error handling
+ */
+
+inline static void ATTR_FORMAT(4, 5)
+sieve_lexer_error(const struct sieve_lexer *lexer,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *fmt, ...)
+{
+ struct sieve_lexical_scanner *scanner = lexer->scanner;
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_ERROR,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ va_start(args, fmt);
+
+ T_BEGIN {
+ params.location =
+ sieve_error_script_location(scanner->script,
+ scanner->current_line);
+ sieve_logv(scanner->ehandler, &params, fmt, args);
+ } T_END;
+
+ va_end(args);
+}
+#define sieve_lexer_error(lexer, ...) \
+ sieve_lexer_error(lexer, __FILE__, __LINE__, __VA_ARGS__)
+
+inline static void ATTR_FORMAT(4, 5)
+sieve_lexer_warning(const struct sieve_lexer *lexer,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *fmt, ...)
+{
+ struct sieve_lexical_scanner *scanner = lexer->scanner;
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_WARNING,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ va_start(args, fmt);
+
+ T_BEGIN {
+ params.location =
+ sieve_error_script_location(scanner->script,
+ scanner->current_line);
+ sieve_logv(scanner->ehandler, &params, fmt, args);
+ } T_END;
+
+ va_end(args);
+}
+#define sieve_lexer_warning(lexer, ...) \
+ sieve_lexer_warning(lexer, __FILE__, __LINE__, __VA_ARGS__)
+
+const char *sieve_lexer_token_description(const struct sieve_lexer *lexer)
+{
+ switch (lexer->token_type) {
+ case STT_NONE:
+ return "no token (bug)";
+ case STT_WHITESPACE:
+ return "whitespace (bug)";
+ case STT_EOF:
+ return "end of file";
+
+ case STT_NUMBER:
+ return "number";
+ case STT_IDENTIFIER:
+ return "identifier";
+ case STT_TAG:
+ return "tag";
+ case STT_STRING:
+ return "string";
+
+ case STT_RBRACKET:
+ return "')'";
+ case STT_LBRACKET:
+ return "'('";
+ case STT_RCURLY:
+ return "'}'";
+ case STT_LCURLY:
+ return "'{'";
+ case STT_RSQUARE:
+ return "']'";
+ case STT_LSQUARE:
+ return "'['";
+ case STT_SEMICOLON:
+ return "';'";
+ case STT_COMMA:
+ return "','";
+
+ case STT_SLASH:
+ return "'/'";
+ case STT_COLON:
+ return "':'";
+
+ case STT_GARBAGE:
+ return "unknown characters";
+ case STT_ERROR:
+ return "error token (bug)";
+ }
+
+ return "unknown token (bug)";
+}
+
+/*
+ * Debug
+ */
+
+void sieve_lexer_token_print(const struct sieve_lexer *lexer)
+{
+ switch (lexer->token_type) {
+ case STT_NONE:
+ printf("??NONE?? ");
+ break;
+ case STT_WHITESPACE:
+ printf("??WHITESPACE?? ");
+ break;
+ case STT_EOF:
+ printf("EOF\n");
+ break;
+
+ case STT_NUMBER:
+ printf("NUMBER ");
+ break;
+ case STT_IDENTIFIER:
+ printf("IDENTIFIER ");
+ break;
+ case STT_TAG:
+ printf("TAG ");
+ break;
+ case STT_STRING:
+ printf("STRING ");
+ break;
+
+ case STT_RBRACKET:
+ printf(") ");
+ break;
+ case STT_LBRACKET:
+ printf("( ");
+ break;
+ case STT_RCURLY:
+ printf("}\n");
+ break;
+ case STT_LCURLY:
+ printf("{\n");
+ break;
+ case STT_RSQUARE:
+ printf("] ");
+ break;
+ case STT_LSQUARE:
+ printf("[ ");
+ break;
+ case STT_SEMICOLON:
+ printf(";\n");
+ break;
+ case STT_COMMA:
+ printf(", ");
+ break;
+
+ case STT_SLASH:
+ printf("/ ");
+ break;
+ case STT_COLON:
+ printf(": ");
+ break;
+
+ case STT_GARBAGE:
+ printf(">>GARBAGE<<");
+ break;
+ case STT_ERROR:
+ printf(">>ERROR<<");
+ break;
+ default:
+ printf("UNKNOWN ");
+ break;
+ }
+}
+
+/*
+ * Lexical scanning
+ */
+
+static void sieve_lexer_shift(struct sieve_lexical_scanner *scanner)
+{
+ if (scanner->buffer_size > 0 &&
+ scanner->buffer[scanner->buffer_pos] == '\n')
+ scanner->current_line++;
+
+ if (scanner->buffer_size > 0 &&
+ scanner->buffer_pos + 1 < scanner->buffer_size)
+ scanner->buffer_pos++;
+ else {
+ if (scanner->buffer_size > 0)
+ i_stream_skip(scanner->input, scanner->buffer_size);
+
+ scanner->buffer = i_stream_get_data(scanner->input,
+ &scanner->buffer_size);
+
+ if (scanner->buffer_size == 0 &&
+ i_stream_read(scanner->input) > 0) {
+ scanner->buffer = i_stream_get_data(
+ scanner->input, &scanner->buffer_size);
+ }
+
+ scanner->buffer_pos = 0;
+ }
+}
+
+static inline int sieve_lexer_curchar(struct sieve_lexical_scanner *scanner)
+{
+ if (scanner->buffer_size == 0)
+ return -1;
+
+ return scanner->buffer[scanner->buffer_pos];
+}
+
+static inline const char *_char_sanitize(int ch)
+{
+ if (ch > 31 && ch < 127)
+ return t_strdup_printf("'%c'", ch);
+
+ return t_strdup_printf("0x%02x", ch);
+}
+
+static bool sieve_lexer_scan_number(struct sieve_lexical_scanner *scanner)
+{
+ struct sieve_lexer *lexer = &scanner->lexer;
+ uintmax_t value;
+ string_t *str;
+ bool overflow = FALSE;
+
+ str_truncate(lexer->token_str_value,0);
+ str = lexer->token_str_value;
+
+ while (i_isdigit(sieve_lexer_curchar(scanner))) {
+ str_append_c(str, sieve_lexer_curchar(scanner));
+ sieve_lexer_shift(scanner);
+ }
+
+ if (str_to_uintmax(str_c(str), &value) < 0 ||
+ value > (sieve_number_t)-1) {
+ overflow = TRUE;
+ } else {
+ switch (sieve_lexer_curchar(scanner)) {
+ case 'k':
+ case 'K': /* Kilo */
+ if (value > (SIEVE_MAX_NUMBER >> 10))
+ overflow = TRUE;
+ else
+ value = value << 10;
+ sieve_lexer_shift(scanner);
+ break;
+ case 'm':
+ case 'M': /* Mega */
+ if (value > (SIEVE_MAX_NUMBER >> 20))
+ overflow = TRUE;
+ else
+ value = value << 20;
+ sieve_lexer_shift(scanner);
+ break;
+ case 'g':
+ case 'G': /* Giga */
+ if (value > (SIEVE_MAX_NUMBER >> 30))
+ overflow = TRUE;
+ else
+ value = value << 30;
+ sieve_lexer_shift(scanner);
+ break;
+ default:
+ /* Next token */
+ break;
+ }
+ }
+
+ /* Check for integer overflow */
+ if (overflow) {
+ sieve_lexer_error(lexer,
+ "number exceeds integer limits (max %llu)",
+ (long long) SIEVE_MAX_NUMBER);
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ }
+
+ lexer->token_type = STT_NUMBER;
+ lexer->token_int_value = (sieve_number_t)value;
+ return TRUE;
+
+}
+
+static bool
+sieve_lexer_scan_hash_comment(struct sieve_lexical_scanner *scanner)
+{
+ struct sieve_lexer *lexer = &scanner->lexer;
+
+ while (sieve_lexer_curchar(scanner) != '\n') {
+ switch(sieve_lexer_curchar(scanner)) {
+ case -1:
+ if (!scanner->input->eof) {
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ }
+ sieve_lexer_warning(lexer,
+ "no newline (CRLF) at end of hash comment at end of file");
+ lexer->token_type = STT_WHITESPACE;
+ return TRUE;
+ case '\0':
+ sieve_lexer_error(lexer,
+ "encountered NUL character in hash comment");
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ default:
+ break;
+ }
+
+ /* Stray CR is ignored */
+ sieve_lexer_shift(scanner);
+ }
+
+ sieve_lexer_shift(scanner);
+
+ lexer->token_type = STT_WHITESPACE;
+ return TRUE;
+}
+
+/* sieve_lexer_scan_raw_token:
+ * Scans valid tokens and whitespace
+ */
+static bool
+sieve_lexer_scan_raw_token(struct sieve_lexical_scanner *scanner)
+{
+ struct sieve_lexer *lexer = &scanner->lexer;
+ string_t *str;
+ int ret;
+
+ /* Read first character */
+ if (lexer->token_type == STT_NONE) {
+ if ((ret = i_stream_read(scanner->input)) < 0) {
+ i_assert(ret != -2);
+ if (!scanner->input->eof) {
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ }
+ }
+ sieve_lexer_shift(scanner);
+ }
+
+ lexer->token_line = scanner->current_line;
+
+ switch (sieve_lexer_curchar(scanner)) {
+
+ /* whitespace */
+
+ // hash-comment = ( "#" *CHAR-NOT-CRLF CRLF )
+ case '#':
+ sieve_lexer_shift(scanner);
+ return sieve_lexer_scan_hash_comment(scanner);
+
+ // bracket-comment = "/*" *(CHAR-NOT-STAR / ("*" CHAR-NOT-SLASH)) "*/"
+ // ;; No */ allowed inside a comment.
+ // ;; (No * is allowed unless it is the last character,
+ // ;; or unless it is followed by a character that isn't a
+ // ;; slash.)
+ case '/':
+ sieve_lexer_shift(scanner);
+
+ if (sieve_lexer_curchar(scanner) == '*') {
+ sieve_lexer_shift(scanner);
+
+ while (TRUE) {
+ switch (sieve_lexer_curchar(scanner)) {
+ case -1:
+ if (scanner->input->eof) {
+ sieve_lexer_error(lexer,
+ "end of file before end of bracket comment "
+ "('/* ... */') "
+ "started at line %d",
+ lexer->token_line);
+ }
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ case '*':
+ sieve_lexer_shift(scanner);
+
+ if (sieve_lexer_curchar(scanner) == '/') {
+ sieve_lexer_shift(scanner);
+
+ lexer->token_type = STT_WHITESPACE;
+ return TRUE;
+
+ } else if (sieve_lexer_curchar(scanner) == -1) {
+ sieve_lexer_error(lexer,
+ "end of file before end of bracket comment "
+ "('/* ... */') "
+ "started at line %d",
+ lexer->token_line);
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ }
+ break;
+ case '\0':
+ sieve_lexer_error(lexer,
+ "encountered NUL character in bracket comment");
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ default:
+ sieve_lexer_shift(scanner);
+ }
+ }
+
+ i_unreached();
+ return FALSE;
+ }
+
+ lexer->token_type = STT_SLASH;
+ return TRUE;
+
+ // comment = bracket-comment / hash-comment
+ // white-space = 1*(SP / CRLF / HTAB) / comment
+ case '\t':
+ case '\r':
+ case '\n':
+ case ' ':
+ sieve_lexer_shift(scanner);
+
+ while (sieve_lexer_curchar(scanner) == '\t' ||
+ sieve_lexer_curchar(scanner) == '\r' ||
+ sieve_lexer_curchar(scanner) == '\n' ||
+ sieve_lexer_curchar(scanner) == ' ') {
+
+ sieve_lexer_shift(scanner);
+ }
+
+ lexer->token_type = STT_WHITESPACE;
+ return TRUE;
+
+ /* quoted-string */
+ case '"':
+ sieve_lexer_shift(scanner);
+
+ str_truncate(lexer->token_str_value, 0);
+ str = lexer->token_str_value;
+
+ while (sieve_lexer_curchar(scanner) != '"') {
+ if (sieve_lexer_curchar(scanner) == '\\')
+ sieve_lexer_shift(scanner);
+
+ switch (sieve_lexer_curchar(scanner)) {
+
+ /* End of file */
+ case -1:
+ if (scanner->input->eof) {
+ sieve_lexer_error(lexer,
+ "end of file before end of quoted string "
+ "started at line %d", lexer->token_line);
+ }
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+
+ /* NUL character */
+ case '\0':
+ sieve_lexer_error(lexer,
+ "encountered NUL character in quoted string "
+ "started at line %d", lexer->token_line);
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+
+ /* CR .. check for LF */
+ case '\r':
+ sieve_lexer_shift(scanner);
+
+ if (sieve_lexer_curchar(scanner) != '\n') {
+ sieve_lexer_error(lexer,
+ "found stray carriage-return (CR) character "
+ "in quoted string started at line %d",
+ lexer->token_line);
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ }
+
+ if (str_len(str) <= SIEVE_MAX_STRING_LEN)
+ str_append(str, "\r\n");
+ break;
+
+ /* Loose LF is allowed (non-standard) and converted to CRLF */
+ case '\n':
+ if (str_len(str) <= SIEVE_MAX_STRING_LEN)
+ str_append(str, "\r\n");
+ break;
+
+ /* Other characters */
+ default:
+ if (str_len(str) <= SIEVE_MAX_STRING_LEN)
+ str_append_c(str, sieve_lexer_curchar(scanner));
+ }
+
+ sieve_lexer_shift(scanner);
+ }
+
+ sieve_lexer_shift(scanner);
+
+ if (str_len(str) > SIEVE_MAX_STRING_LEN) {
+ sieve_lexer_error(lexer,
+ "quoted string started at line %d is too long "
+ "(longer than %llu bytes)", lexer->token_line,
+ (long long) SIEVE_MAX_STRING_LEN);
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ }
+
+ lexer->token_type = STT_STRING;
+ return TRUE;
+
+ /* single character tokens */
+ case ']':
+ sieve_lexer_shift(scanner);
+ lexer->token_type = STT_RSQUARE;
+ return TRUE;
+ case '[':
+ sieve_lexer_shift(scanner);
+ lexer->token_type = STT_LSQUARE;
+ return TRUE;
+ case '}':
+ sieve_lexer_shift(scanner);
+ lexer->token_type = STT_RCURLY;
+ return TRUE;
+ case '{':
+ sieve_lexer_shift(scanner);
+ lexer->token_type = STT_LCURLY;
+ return TRUE;
+ case ')':
+ sieve_lexer_shift(scanner);
+ lexer->token_type = STT_RBRACKET;
+ return TRUE;
+ case '(':
+ sieve_lexer_shift(scanner);
+ lexer->token_type = STT_LBRACKET;
+ return TRUE;
+ case ';':
+ sieve_lexer_shift(scanner);
+ lexer->token_type = STT_SEMICOLON;
+ return TRUE;
+ case ',':
+ sieve_lexer_shift(scanner);
+ lexer->token_type = STT_COMMA;
+ return TRUE;
+
+ /* EOF */
+ case -1:
+ if (!scanner->input->eof) {
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ }
+ lexer->token_type = STT_EOF;
+ return TRUE;
+
+ default:
+ /* number */
+ if (i_isdigit(sieve_lexer_curchar(scanner))) {
+ return sieve_lexer_scan_number(scanner);
+
+ /* identifier / tag */
+ } else if (i_isalpha(sieve_lexer_curchar(scanner)) ||
+ sieve_lexer_curchar(scanner) == '_' ||
+ sieve_lexer_curchar(scanner) == ':') {
+
+ enum sieve_token_type type = STT_IDENTIFIER;
+ str_truncate(lexer->token_str_value,0);
+ str = lexer->token_str_value;
+
+ /* If it starts with a ':' it is a tag and not an
+ identifier */
+ if (sieve_lexer_curchar(scanner) == ':') {
+ sieve_lexer_shift(scanner); // discard colon
+ type = STT_TAG;
+
+ /* First character still can't be a DIGIT */
+ if (i_isalpha(sieve_lexer_curchar(scanner)) ||
+ sieve_lexer_curchar(scanner) == '_') {
+ str_append_c(str, sieve_lexer_curchar(scanner));
+ sieve_lexer_shift(scanner);
+ } else {
+ /* Hmm, otherwise it is just a spurious
+ colon */
+ lexer->token_type = STT_COLON;
+ return TRUE;
+ }
+ } else {
+ str_append_c(str, sieve_lexer_curchar(scanner));
+ sieve_lexer_shift(scanner);
+ }
+
+ /* Scan the rest of the identifier */
+ while (i_isalnum(sieve_lexer_curchar(scanner)) ||
+ sieve_lexer_curchar(scanner) == '_') {
+
+ if (str_len(str) <= SIEVE_MAX_IDENTIFIER_LEN) {
+ str_append_c(str, sieve_lexer_curchar(scanner));
+ }
+ sieve_lexer_shift(scanner);
+ }
+
+ /* Is this in fact a multiline text string ? */
+ if (sieve_lexer_curchar(scanner) == ':' &&
+ type == STT_IDENTIFIER && str_len(str) == 4 &&
+ strncasecmp(str_c(str), "text", 4) == 0) {
+ sieve_lexer_shift(scanner); // discard colon
+
+ /* Discard SP and HTAB whitespace */
+ while (sieve_lexer_curchar(scanner) == ' ' ||
+ sieve_lexer_curchar(scanner) == '\t')
+ sieve_lexer_shift(scanner);
+
+ /* Discard hash comment or handle single CRLF */
+ if (sieve_lexer_curchar(scanner) == '\r')
+ sieve_lexer_shift(scanner);
+ switch (sieve_lexer_curchar(scanner)) {
+ case '#':
+ if (!sieve_lexer_scan_hash_comment(scanner))
+ return FALSE;
+ if (scanner->input->eof) {
+ sieve_lexer_error(lexer,
+ "end of file before end of multi-line string");
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ } else if (scanner->input->stream_errno != 0) {
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ }
+ break;
+ case '\n':
+ sieve_lexer_shift(scanner);
+ break;
+ case -1:
+ if (scanner->input->eof) {
+ sieve_lexer_error(lexer,
+ "end of file before end of multi-line string");
+ }
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ default:
+ sieve_lexer_error(lexer,
+ "invalid character %s after 'text:' in multiline string",
+ _char_sanitize(sieve_lexer_curchar(scanner)));
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ }
+
+ /* Start over */
+ str_truncate(str, 0);
+
+ /* Parse literal lines */
+ while (TRUE) {
+ bool cr_shifted = FALSE;
+
+ /* Remove dot-stuffing or detect end of text */
+ if (sieve_lexer_curchar(scanner) == '.') {
+ sieve_lexer_shift(scanner);
+
+ /* Check for CR.. */
+ if (sieve_lexer_curchar(scanner) == '\r') {
+ sieve_lexer_shift(scanner);
+ cr_shifted = TRUE;
+ }
+
+ /* ..LF */
+ if (sieve_lexer_curchar(scanner) == '\n') {
+ sieve_lexer_shift(scanner);
+
+ /* End of multi-line string */
+
+ /* Check whether length limit was violated */
+ if (str_len(str) > SIEVE_MAX_STRING_LEN) {
+ sieve_lexer_error(lexer,
+ "multi-line string started at line %d is too long "
+ "(longer than %llu bytes)", lexer->token_line,
+ (long long) SIEVE_MAX_STRING_LEN);
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ }
+
+ lexer->token_type = STT_STRING;
+ return TRUE;
+ } else if (cr_shifted) {
+ /* Seen CR, but no LF */
+ if (sieve_lexer_curchar(scanner) != -1 ||
+ !scanner->input->eof) {
+ sieve_lexer_error(lexer,
+ "found stray carriage-return (CR) character "
+ "in multi-line string started at line %d",
+ lexer->token_line);
+ }
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ }
+
+ /* Handle dot-stuffing */
+ if (str_len(str) <= SIEVE_MAX_STRING_LEN)
+ str_append_c(str, '.');
+ if (sieve_lexer_curchar(scanner) == '.')
+ sieve_lexer_shift(scanner);
+ }
+
+ /* Scan the rest of the line */
+ while (sieve_lexer_curchar(scanner) != '\n' &&
+ sieve_lexer_curchar(scanner) != '\r') {
+
+ switch (sieve_lexer_curchar(scanner)) {
+ case -1:
+ if (scanner->input->eof) {
+ sieve_lexer_error(lexer,
+ "end of file before end of multi-line string");
+ }
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ case '\0':
+ sieve_lexer_error(lexer,
+ "encountered NUL character in quoted string "
+ "started at line %d", lexer->token_line);
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ default:
+ if (str_len(str) <= SIEVE_MAX_STRING_LEN)
+ str_append_c(str, sieve_lexer_curchar(scanner));
+ }
+
+ sieve_lexer_shift(scanner);
+ }
+
+ /* If exited loop due to CR, skip it */
+ if (sieve_lexer_curchar(scanner) == '\r')
+ sieve_lexer_shift(scanner);
+
+ /* Now we must see an LF */
+ if (sieve_lexer_curchar(scanner) != '\n') {
+ if (sieve_lexer_curchar(scanner) != -1 ||
+ !scanner->input->eof) {
+ sieve_lexer_error(lexer,
+ "found stray carriage-return (CR) character "
+ "in multi-line string started at line %d",
+ lexer->token_line);
+ }
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ }
+
+ if (str_len(str) <= SIEVE_MAX_STRING_LEN)
+ str_append(str, "\r\n");
+
+ sieve_lexer_shift(scanner);
+ }
+
+ i_unreached();
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ }
+
+ if (str_len(str) > SIEVE_MAX_IDENTIFIER_LEN) {
+ sieve_lexer_error(lexer,
+ "encountered impossibly long %s%s'",
+ (type == STT_TAG ? "tag identifier ':" :
+ "identifier '"),
+ str_sanitize(str_c(str),
+ SIEVE_MAX_IDENTIFIER_LEN));
+ lexer->token_type = STT_ERROR;
+ return FALSE;
+ }
+
+ lexer->token_type = type;
+ return TRUE;
+ }
+
+ /* Error (unknown character and EOF handled already) */
+ if (lexer->token_type != STT_GARBAGE) {
+ sieve_lexer_error(lexer,
+ "unexpected character(s) starting with %s",
+ _char_sanitize(sieve_lexer_curchar(scanner)));
+ }
+ sieve_lexer_shift(scanner);
+ lexer->token_type = STT_GARBAGE;
+ return FALSE;
+ }
+}
+
+void sieve_lexer_skip_token(const struct sieve_lexer *lexer)
+{
+ /* Scan token while skipping whitespace */
+ do {
+ struct sieve_lexical_scanner *scanner = lexer->scanner;
+
+ if (!sieve_lexer_scan_raw_token(scanner)) {
+ if (!scanner->input->eof &&
+ scanner->input->stream_errno != 0) {
+ sieve_critical(scanner->svinst, scanner->ehandler,
+ sieve_error_script_location(scanner->script,
+ scanner->current_line),
+ "error reading script",
+ "error reading script during lexical analysis: %s",
+ i_stream_get_error(scanner->input));
+ }
+ return;
+ }
+ } while (lexer->token_type == STT_WHITESPACE);
+}
+
diff --git a/pigeonhole/src/lib-sieve/sieve-lexer.h b/pigeonhole/src/lib-sieve/sieve-lexer.h
new file mode 100644
index 0000000..95451cc
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-lexer.h
@@ -0,0 +1,119 @@
+#ifndef SIEVE_LEXER_H
+#define SIEVE_LEXER_H
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve-common.h"
+
+enum sieve_token_type {
+ STT_NONE,
+ STT_WHITESPACE,
+ STT_EOF,
+
+ STT_NUMBER,
+ STT_IDENTIFIER,
+ STT_TAG,
+ STT_STRING,
+
+ STT_RBRACKET,
+ STT_LBRACKET,
+ STT_RCURLY,
+ STT_LCURLY,
+ STT_RSQUARE,
+ STT_LSQUARE,
+ STT_SEMICOLON,
+ STT_COMMA,
+
+ /* These are currently not used in the lexical specification, but a
+ token is assigned to these to generate proper error messages (these
+ are technically not garbage and possibly part of mistyped but
+ otherwise valid tokens).
+ */
+ STT_SLASH,
+ STT_COLON,
+
+ /* Error tokens */
+ STT_GARBAGE, /* Error reporting deferred to parser */
+ STT_ERROR /* Lexer is responsible for error, parser won't report
+ additional errors */
+};
+
+/*
+ * Lexer object
+ */
+
+struct sieve_lexical_scanner;
+
+struct sieve_lexer {
+ struct sieve_lexical_scanner *scanner;
+
+ enum sieve_token_type token_type;
+ string_t *token_str_value;
+ sieve_number_t token_int_value;
+
+ int token_line;
+};
+
+const struct sieve_lexer *
+sieve_lexer_create(struct sieve_script *script,
+ struct sieve_error_handler *ehandler,
+ enum sieve_error *error_r);
+void sieve_lexer_free(const struct sieve_lexer **lexer);
+
+/*
+ * Scanning
+ */
+
+void sieve_lexer_skip_token(const struct sieve_lexer *lexer);
+
+/*
+ * Token access
+ */
+
+static inline enum sieve_token_type
+sieve_lexer_token_type(const struct sieve_lexer *lexer)
+{
+ return lexer->token_type;
+}
+
+static inline const string_t *
+sieve_lexer_token_str(const struct sieve_lexer *lexer)
+{
+ i_assert(lexer->token_type == STT_STRING);
+
+ return lexer->token_str_value;
+}
+
+static inline const char *
+sieve_lexer_token_ident(const struct sieve_lexer *lexer)
+{
+ i_assert(lexer->token_type == STT_TAG ||
+ lexer->token_type == STT_IDENTIFIER);
+
+ return str_c(lexer->token_str_value);
+}
+
+static inline sieve_number_t
+sieve_lexer_token_int(const struct sieve_lexer *lexer)
+{
+ i_assert(lexer->token_type == STT_NUMBER);
+
+ return lexer->token_int_value;
+}
+
+static inline bool sieve_lexer_eof(const struct sieve_lexer *lexer)
+{
+ return lexer->token_type == STT_EOF;
+}
+
+static inline int sieve_lexer_token_line(const struct sieve_lexer *lexer)
+{
+ return lexer->token_line;
+}
+
+const char *sieve_lexer_token_description(const struct sieve_lexer *lexer);
+
+void sieve_lexer_token_print(const struct sieve_lexer *lexer);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-limits.h b/pigeonhole/src/lib-sieve/sieve-limits.h
new file mode 100644
index 0000000..1adbaa6
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-limits.h
@@ -0,0 +1,45 @@
+#ifndef SIEVE_LIMITS_H
+#define SIEVE_LIMITS_H
+
+/*
+ * Scripts
+ */
+
+#define SIEVE_MAX_SCRIPT_NAME_LEN 256
+
+#define SIEVE_DEFAULT_MAX_SCRIPT_SIZE (1 << 20)
+
+#define SIEVE_MAX_LOOP_DEPTH 4
+
+/*
+ * Lexer
+ */
+
+#define SIEVE_MAX_STRING_LEN (1 << 20)
+#define SIEVE_MAX_IDENTIFIER_LEN 32
+
+/*
+ * AST
+ */
+
+#define SIEVE_MAX_COMMAND_ARGUMENTS 32
+#define SIEVE_MAX_BLOCK_NESTING 32
+#define SIEVE_MAX_TEST_NESTING 32
+
+/*
+ * Runtime
+ */
+
+#define SIEVE_MAX_MATCH_VALUES 32
+#define SIEVE_HIGH_CPU_TIME_MSECS 1500
+#define SIEVE_DEFAULT_MAX_CPU_TIME_SECS 30
+#define SIEVE_DEFAULT_RESOURCE_USAGE_TIMEOUT_SECS (60 * 60)
+
+/*
+ * Actions
+ */
+
+#define SIEVE_DEFAULT_MAX_ACTIONS 32
+#define SIEVE_DEFAULT_MAX_REDIRECTS 4
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-match-types.c b/pigeonhole/src/lib-sieve/sieve-match-types.c
new file mode 100644
index 0000000..a61737e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-match-types.c
@@ -0,0 +1,569 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "compat.h"
+#include "mempool.h"
+#include "hash.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-limits.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-comparators.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "sieve-match-types.h"
+
+#include <string.h>
+
+/*
+ * Types
+ */
+
+struct sieve_match_values {
+ pool_t pool;
+ ARRAY(string_t *) values;
+ unsigned count;
+};
+
+/*
+ * Default match types
+ */
+
+const struct sieve_match_type_def *sieve_core_match_types[] = {
+ &is_match_type, &contains_match_type, &matches_match_type
+};
+
+const unsigned int sieve_core_match_types_count =
+ N_ELEMENTS(sieve_core_match_types);
+
+/*
+ * Match-type 'extension'
+ */
+
+static bool mtch_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def match_type_extension = {
+ .name = "@match-types",
+ .validator_load = mtch_validator_load
+};
+
+/*
+ * Validator context:
+ * name-based match-type registry.
+ */
+
+static struct sieve_validator_object_registry *_get_object_registry
+(struct sieve_validator *valdtr)
+{
+ struct sieve_instance *svinst;
+ const struct sieve_extension *mcht_ext;
+
+ svinst = sieve_validator_svinst(valdtr);
+ mcht_ext = sieve_get_match_type_extension(svinst);
+ return sieve_validator_object_registry_get(valdtr, mcht_ext);
+}
+
+void sieve_match_type_register
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ const struct sieve_match_type_def *mcht_def)
+{
+ struct sieve_validator_object_registry *regs = _get_object_registry(valdtr);
+
+ sieve_validator_object_registry_add(regs, ext, &mcht_def->obj_def);
+}
+
+static bool sieve_match_type_exists
+(struct sieve_validator *valdtr, const char *identifier)
+{
+ struct sieve_validator_object_registry *regs = _get_object_registry(valdtr);
+
+ return sieve_validator_object_registry_find(regs, identifier, NULL);
+}
+
+static const struct sieve_match_type *sieve_match_type_create_instance
+(struct sieve_validator *valdtr, struct sieve_command *cmd,
+ const char *identifier)
+{
+ struct sieve_validator_object_registry *regs = _get_object_registry(valdtr);
+ struct sieve_object object;
+ struct sieve_match_type *mcht;
+
+ if ( !sieve_validator_object_registry_find(regs, identifier, &object) )
+ return NULL;
+
+ mcht = p_new(sieve_command_pool(cmd), struct sieve_match_type, 1);
+ mcht->object = object;
+ mcht->def = (const struct sieve_match_type_def *) object.def;
+
+ return mcht;
+}
+
+bool mtch_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ struct sieve_validator_object_registry *regs =
+ sieve_validator_object_registry_init(valdtr, ext);
+ unsigned int i;
+
+ /* Register core match-types */
+ for ( i = 0; i < sieve_core_match_types_count; i++ ) {
+ sieve_validator_object_registry_add
+ (regs, NULL, &(sieve_core_match_types[i]->obj_def));
+ }
+
+ return TRUE;
+}
+
+/*
+ * Interpreter context
+ */
+
+struct mtch_interpreter_context {
+ struct sieve_match_values *match_values;
+ bool match_values_enabled;
+};
+
+static void mtch_interpreter_free
+(const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_interpreter *interp ATTR_UNUSED, void *context)
+{
+ struct mtch_interpreter_context *mctx =
+ (struct mtch_interpreter_context *) context;
+
+ if ( mctx->match_values != NULL ) {
+ pool_unref(&mctx->match_values->pool);
+ }
+}
+
+struct sieve_interpreter_extension
+mtch_interpreter_extension = {
+ .ext_def = &match_type_extension,
+ .free = mtch_interpreter_free
+};
+
+static inline struct mtch_interpreter_context *get_interpreter_context
+(struct sieve_interpreter *interp, bool create)
+{
+ struct sieve_instance *svinst;
+ const struct sieve_extension *mcht_ext;
+ struct mtch_interpreter_context *ctx;
+
+ svinst = sieve_interpreter_svinst(interp);
+ mcht_ext = sieve_get_match_type_extension(svinst);
+
+ ctx = (struct mtch_interpreter_context *)
+ sieve_interpreter_extension_get_context(interp, mcht_ext);
+
+ if ( ctx == NULL && create ) {
+ pool_t pool = sieve_interpreter_pool(interp);
+ ctx = p_new(pool, struct mtch_interpreter_context, 1);
+
+ sieve_interpreter_extension_register
+ (interp, mcht_ext, &mtch_interpreter_extension, (void *) ctx);
+ }
+
+ return ctx;
+}
+
+/*
+ * Match values
+ */
+
+bool sieve_match_values_set_enabled
+(const struct sieve_runtime_env *renv, bool enable)
+{
+ struct mtch_interpreter_context *ctx =
+ get_interpreter_context(renv->interp, enable);
+
+ if ( ctx != NULL ) {
+ bool previous = ctx->match_values_enabled;
+
+ ctx->match_values_enabled = enable;
+ return previous;
+ }
+
+ return FALSE;
+}
+
+bool sieve_match_values_are_enabled
+(const struct sieve_runtime_env *renv)
+{
+ struct mtch_interpreter_context *ctx =
+ get_interpreter_context(renv->interp, FALSE);
+
+ return ( ctx == NULL ? FALSE : ctx->match_values_enabled );
+}
+
+struct sieve_match_values *sieve_match_values_start
+(const struct sieve_runtime_env *renv)
+{
+ struct mtch_interpreter_context *ctx =
+ get_interpreter_context(renv->interp, FALSE);
+ struct sieve_match_values *match_values;
+
+ if ( ctx == NULL || !ctx->match_values_enabled )
+ return NULL;
+
+ pool_t pool = pool_alloconly_create("sieve_match_values", 1024);
+
+ match_values = p_new(pool, struct sieve_match_values, 1);
+ match_values->pool = pool;
+ match_values->count = 0;
+
+ p_array_init(&match_values->values, pool, 4);
+
+ return match_values;
+}
+
+static string_t *sieve_match_values_add_entry
+(struct sieve_match_values *mvalues)
+{
+ string_t *entry;
+
+ if ( mvalues == NULL ) return NULL;
+
+ if ( mvalues->count >= SIEVE_MAX_MATCH_VALUES ) return NULL;
+
+ if ( mvalues->count >= array_count(&mvalues->values) ) {
+ entry = str_new(mvalues->pool, 64);
+ array_append(&mvalues->values, &entry, 1); } else {
+ string_t * const *ep = array_idx(&mvalues->values, mvalues->count);
+ entry = *ep;
+ str_truncate(entry, 0);
+ }
+
+ mvalues->count++;
+
+ return entry;
+}
+
+void sieve_match_values_set
+(struct sieve_match_values *mvalues, unsigned int index, string_t *value)
+{
+ if ( mvalues != NULL && index < array_count(&mvalues->values) ) {
+ string_t * const *ep = array_idx(&mvalues->values, index);
+ string_t *entry = *ep;
+
+ if ( entry != NULL && value != NULL ) {
+ str_truncate(entry, 0);
+ str_append_str(entry, value);
+ }
+ }
+}
+
+void sieve_match_values_add
+(struct sieve_match_values *mvalues, string_t *value)
+{
+ string_t *entry = sieve_match_values_add_entry(mvalues);
+
+ if ( entry != NULL && value != NULL )
+ str_append_str(entry, value);
+}
+
+void sieve_match_values_add_char
+(struct sieve_match_values *mvalues, char c)
+{
+ string_t *entry = sieve_match_values_add_entry(mvalues);
+
+ if ( entry != NULL )
+ str_append_c(entry, c);
+}
+
+void sieve_match_values_skip
+(struct sieve_match_values *mvalues, int num)
+{
+ int i;
+
+ for ( i = 0; i < num; i++ )
+ (void) sieve_match_values_add_entry(mvalues);
+}
+
+void sieve_match_values_commit
+(const struct sieve_runtime_env *renv, struct sieve_match_values **mvalues)
+{
+ struct mtch_interpreter_context *ctx;
+
+ if ( (*mvalues) == NULL ) return;
+
+ ctx = get_interpreter_context(renv->interp, FALSE);
+ if ( ctx == NULL || !ctx->match_values_enabled )
+ return;
+
+ if ( ctx->match_values != NULL ) {
+ pool_unref(&ctx->match_values->pool);
+ ctx->match_values = NULL;
+ }
+
+ ctx->match_values = *mvalues;
+ *mvalues = NULL;
+}
+
+void sieve_match_values_abort
+(struct sieve_match_values **mvalues)
+{
+ if ( (*mvalues) == NULL ) return;
+
+ pool_unref(&(*mvalues)->pool);
+ *mvalues = NULL;
+}
+
+void sieve_match_values_get
+(const struct sieve_runtime_env *renv, unsigned int index, string_t **value_r)
+{
+ struct mtch_interpreter_context *ctx =
+ get_interpreter_context(renv->interp, FALSE);
+ struct sieve_match_values *mvalues;
+
+ if ( ctx == NULL || ctx->match_values == NULL ) {
+ *value_r = NULL;
+ return;
+ }
+
+ mvalues = ctx->match_values;
+ if ( index < array_count(&mvalues->values) && index < mvalues->count ) {
+ string_t * const *entry = array_idx(&mvalues->values, index);
+
+ *value_r = *entry;
+ return;
+ }
+
+ *value_r = NULL;
+}
+
+/*
+ * Match-type tagged argument
+ */
+
+/* Forward declarations */
+
+static bool tag_match_type_is_instance_of
+ (struct sieve_validator *valdtr, struct sieve_command *cmd,
+ const struct sieve_extension *ext, const char *identifier, void **data);
+static bool tag_match_type_validate
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool tag_match_type_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd);
+
+/* Argument object */
+
+const struct sieve_argument_def match_type_tag = {
+ .identifier = "MATCH-TYPE",
+ .is_instance_of = tag_match_type_is_instance_of,
+ .validate = tag_match_type_validate,
+ .generate = tag_match_type_generate
+};
+
+/* Argument implementation */
+
+static bool tag_match_type_is_instance_of
+(struct sieve_validator *valdtr, struct sieve_command *cmd,
+ const struct sieve_extension *ext ATTR_UNUSED, const char *identifier,
+ void **data)
+{
+ const struct sieve_match_type *mcht;
+
+ if ( data == NULL )
+ return sieve_match_type_exists(valdtr, identifier);
+
+ if ( (mcht=sieve_match_type_create_instance
+ (valdtr, cmd, identifier)) == NULL )
+ return FALSE;
+
+ *data = (void *) mcht;
+ return TRUE;
+}
+
+static bool tag_match_type_validate
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ const struct sieve_match_type *mcht =
+ (const struct sieve_match_type *) (*arg)->argument->data;
+ struct sieve_match_type_context *mtctx;
+
+ mtctx = p_new(sieve_command_pool(cmd), struct sieve_match_type_context, 1);
+ mtctx->match_type = mcht;
+ mtctx->argument = *arg;
+ mtctx->comparator = NULL; /* Can be filled in later */
+
+ (*arg)->argument->data = mtctx;
+
+ /* Syntax:
+ * ":is" / ":contains" / ":matches" (subject to extension)
+ */
+
+ /* Skip tag */
+ *arg = sieve_ast_argument_next(*arg);
+
+ /* Check whether this match type requires additional validation.
+ * Additional validation can override the match type recorded in the context
+ * for later code generation.
+ */
+ if ( mcht->def != NULL && mcht->def->validate != NULL ) {
+ return mcht->def->validate(valdtr, arg, mtctx);
+ }
+
+ return TRUE;
+}
+
+static bool tag_match_type_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ struct sieve_match_type_context *mtctx =
+ (struct sieve_match_type_context *) arg->argument->data;
+
+ (void) sieve_opr_match_type_emit(cgenv->sblock, mtctx->match_type);
+
+ return TRUE;
+}
+
+void sieve_match_types_link_tags
+(struct sieve_validator *valdtr,
+ struct sieve_command_registration *cmd_reg, int id_code)
+{
+ struct sieve_instance *svinst;
+ const struct sieve_extension *mcht_ext;
+
+ svinst = sieve_validator_svinst(valdtr);
+ mcht_ext = sieve_get_comparator_extension(svinst);
+
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, mcht_ext, &match_type_tag, id_code);
+}
+
+/*
+ * Validation
+ */
+
+bool sieve_match_type_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd,
+ struct sieve_ast_argument *key_arg,
+ const struct sieve_match_type *mcht_default,
+ const struct sieve_comparator *cmp_default)
+{
+ struct sieve_ast_argument *arg = sieve_command_first_argument(cmd);
+ struct sieve_ast_argument *mt_arg = NULL;
+ struct sieve_match_type_context *mtctx;
+ const struct sieve_match_type *mcht = NULL;
+ const struct sieve_comparator *cmp = NULL;
+
+ /* Find match type and comparator among the arguments */
+ while ( arg != NULL && arg != cmd->first_positional ) {
+ if ( sieve_argument_is_comparator(arg) ) {
+ cmp = sieve_comparator_tag_get(arg);
+ if ( mt_arg != NULL ) break;
+ }
+
+ if ( sieve_argument_is_match_type(arg) ) {
+ mt_arg = arg;
+ if ( cmp != NULL ) break;
+ }
+ arg = sieve_ast_argument_next(arg);
+ }
+
+ /* Verify using the default comparator if none is specified explicitly */
+ if ( cmp == NULL ) {
+ cmp = sieve_comparator_copy(sieve_command_pool(cmd), cmp_default);
+ }
+
+ /* Verify the default match type if none is specified explicitly */
+ if ( mt_arg == NULL || mt_arg->argument == NULL ||
+ mt_arg->argument->data == NULL ) {
+ mcht = sieve_match_type_copy(sieve_command_pool(cmd), mcht_default);
+ mtctx = t_new(struct sieve_match_type_context, 1);
+ mtctx->command = cmd;
+ mtctx->match_type = mcht;
+ } else {
+ mtctx = (struct sieve_match_type_context *) mt_arg->argument->data;
+ mcht = mtctx->match_type;
+ }
+ mtctx->comparator = cmp;
+
+ /* Check whether this match type requires additional validation.
+ * Additional validation can override the match type recorded in the context
+ * for later code generation.
+ */
+ if ( mcht != NULL && mcht->def != NULL &&
+ mcht->def->validate_context != NULL ) {
+ return mcht->def->validate_context(valdtr, mt_arg, mtctx, key_arg);
+ }
+
+ return TRUE;
+}
+
+void sieve_match_type_arguments_remove
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = sieve_command_first_argument(cmd);
+
+ /* Remove any comparator and match type arguments */
+ while ( arg != NULL && arg != cmd->first_positional ) {
+ if ( sieve_argument_is_comparator(arg) ) {
+ arg = sieve_ast_arguments_detach(arg, 1);
+ continue;
+ }
+
+ if ( sieve_argument_is_match_type(arg) ) {
+ arg = sieve_ast_arguments_detach(arg, 1);
+ continue;
+ }
+
+ arg = sieve_ast_argument_next(arg);
+ }
+}
+
+
+/*
+ * Match-type operand
+ */
+
+const struct sieve_operand_class sieve_match_type_operand_class =
+ { "match type" };
+
+static const struct sieve_extension_objects core_match_types =
+ SIEVE_EXT_DEFINE_MATCH_TYPES(sieve_core_match_types);
+
+const struct sieve_operand_def match_type_operand = {
+ .name = "match-type",
+ .code = SIEVE_OPERAND_MATCH_TYPE,
+ .class = &sieve_match_type_operand_class,
+ .interface = &core_match_types
+};
+
+/*
+ * Common validation implementation
+ */
+
+bool sieve_match_substring_validate_context
+(struct sieve_validator *valdtr, struct sieve_ast_argument *arg,
+ struct sieve_match_type_context *ctx,
+ struct sieve_ast_argument *key_arg ATTR_UNUSED)
+{
+ const struct sieve_comparator *cmp = ctx->comparator;
+
+ if ( cmp == NULL || cmp->def == NULL )
+ return TRUE;
+
+ if ( (cmp->def->flags & SIEVE_COMPARATOR_FLAG_SUBSTRING_MATCH) == 0 ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "the specified %s comparator does not support "
+ "sub-string matching as required by the :%s match type",
+ cmp->object.def->identifier, ctx->match_type->object.def->identifier );
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-match-types.h b/pigeonhole/src/lib-sieve/sieve-match-types.h
new file mode 100644
index 0000000..0417e2c
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-match-types.h
@@ -0,0 +1,233 @@
+#ifndef SIEVE_MATCH_TYPES_H
+#define SIEVE_MATCH_TYPES_H
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-objects.h"
+
+/*
+ * Types
+ */
+
+struct sieve_match_type_context;
+
+/*
+ * Core match types
+ */
+
+enum sieve_match_type_code {
+ SIEVE_MATCH_TYPE_IS,
+ SIEVE_MATCH_TYPE_CONTAINS,
+ SIEVE_MATCH_TYPE_MATCHES,
+ SIEVE_MATCH_TYPE_CUSTOM
+};
+
+extern const struct sieve_match_type_def is_match_type;
+extern const struct sieve_match_type_def contains_match_type;
+extern const struct sieve_match_type_def matches_match_type;
+
+/*
+ * Match type definition
+ */
+
+struct sieve_match_type_def {
+ struct sieve_object_def obj_def;
+
+ bool (*validate)
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_match_type_context *ctx);
+ bool (*validate_context)
+ (struct sieve_validator *valdtr, struct sieve_ast_argument *arg,
+ struct sieve_match_type_context *ctx, struct sieve_ast_argument *key_arg);
+
+ /*
+ * Matching
+ */
+
+ /* Custom implementation */
+
+ int (*match)
+ (struct sieve_match_context *mctx, struct sieve_stringlist *value_list,
+ struct sieve_stringlist *key_list);
+
+ /* Default match loop */
+
+ void (*match_init)(struct sieve_match_context *mctx);
+
+ int (*match_keys)
+ (struct sieve_match_context *mctx, const char *val, size_t val_size,
+ struct sieve_stringlist *key_list);
+ int (*match_key)
+ (struct sieve_match_context *mctx, const char *val, size_t val_size,
+ const char *key, size_t key_size);
+
+ void (*match_deinit)(struct sieve_match_context *mctx);
+};
+
+/*
+ * Match type instance
+ */
+
+struct sieve_match_type {
+ struct sieve_object object;
+
+ const struct sieve_match_type_def *def;
+};
+
+#define SIEVE_MATCH_TYPE_DEFAULT(definition) \
+ { SIEVE_OBJECT_DEFAULT(definition), &(definition) }
+
+#define sieve_match_type_name(mcht) \
+ ( (mcht)->object.def->identifier )
+#define sieve_match_type_is(mcht, definition) \
+ ( (mcht)->def == &(definition) )
+
+static inline const struct sieve_match_type *sieve_match_type_copy
+(pool_t pool, const struct sieve_match_type *cmp_orig)
+{
+ struct sieve_match_type *cmp = p_new(pool, struct sieve_match_type, 1);
+
+ *cmp = *cmp_orig;
+
+ return cmp;
+}
+
+/*
+ * Match type context
+ */
+
+struct sieve_match_type_context {
+ struct sieve_command *command;
+ struct sieve_ast_argument *argument;
+
+ const struct sieve_match_type *match_type;
+
+ /* Only filled in when match_type->validate_context() is called */
+ const struct sieve_comparator *comparator;
+
+ /* Context data could be used in the future to pass data between validator and
+ * generator in match types that use extra parameters. Currently not
+ * necessary, not even for the relational extension.
+ */
+ void *ctx_data;
+};
+
+/*
+ * Match type registration
+ */
+
+void sieve_match_type_register
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ const struct sieve_match_type_def *mcht);
+
+/*
+ * Match values
+ */
+
+struct sieve_match_values;
+
+bool sieve_match_values_set_enabled
+ (const struct sieve_runtime_env *renv, bool enable);
+bool sieve_match_values_are_enabled
+ (const struct sieve_runtime_env *renv);
+
+struct sieve_match_values *sieve_match_values_start
+ (const struct sieve_runtime_env *renv);
+void sieve_match_values_set
+ (struct sieve_match_values *mvalues, unsigned int index, string_t *value);
+void sieve_match_values_add
+ (struct sieve_match_values *mvalues, string_t *value);
+void sieve_match_values_add_char
+ (struct sieve_match_values *mvalues, char c);
+void sieve_match_values_skip
+ (struct sieve_match_values *mvalues, int num);
+
+void sieve_match_values_commit
+ (const struct sieve_runtime_env *renv, struct sieve_match_values **mvalues);
+void sieve_match_values_abort
+ (struct sieve_match_values **mvalues);
+
+void sieve_match_values_get
+ (const struct sieve_runtime_env *renv, unsigned int index, string_t **value_r);
+
+/*
+ * Match type tagged argument
+ */
+
+extern const struct sieve_argument_def match_type_tag;
+
+static inline bool sieve_argument_is_match_type
+ (struct sieve_ast_argument *arg)
+{
+ return ( arg->argument->def == &match_type_tag );
+}
+
+void sieve_match_types_link_tags
+ (struct sieve_validator *valdtr,
+ struct sieve_command_registration *cmd_reg, int id_code);
+
+/*
+ * Validation
+ */
+
+bool sieve_match_type_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd,
+ struct sieve_ast_argument *key_arg,
+ const struct sieve_match_type *mcht_default,
+ const struct sieve_comparator *cmp_default);
+
+void sieve_match_type_arguments_remove
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+
+/*
+ * Match type operand
+ */
+
+extern const struct sieve_operand_def match_type_operand;
+extern const struct sieve_operand_class sieve_match_type_operand_class;
+
+#define SIEVE_EXT_DEFINE_MATCH_TYPE(OP) SIEVE_EXT_DEFINE_OBJECT(OP)
+#define SIEVE_EXT_DEFINE_MATCH_TYPES(OPS) SIEVE_EXT_DEFINE_OBJECTS(OPS)
+
+static inline bool sieve_operand_is_match_type
+(const struct sieve_operand *operand)
+{
+ return ( operand != NULL && operand->def != NULL &&
+ operand->def->class == &sieve_match_type_operand_class );
+}
+
+static inline void sieve_opr_match_type_emit
+(struct sieve_binary_block *sblock, const struct sieve_match_type *mcht)
+{
+ sieve_opr_object_emit(sblock, mcht->object.ext, mcht->object.def);
+}
+
+static inline bool sieve_opr_match_type_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ return sieve_opr_object_dump
+ (denv, &sieve_match_type_operand_class, address, NULL);
+}
+
+static inline int sieve_opr_match_type_read
+(const struct sieve_runtime_env *renv, sieve_size_t *address,
+ struct sieve_match_type *mcht)
+{
+ if ( !sieve_opr_object_read
+ (renv, &sieve_match_type_operand_class, address, &mcht->object) )
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ mcht->def = (const struct sieve_match_type_def *) mcht->object.def;
+ return SIEVE_EXEC_OK;
+}
+
+/* Common validation implementation */
+
+bool sieve_match_substring_validate_context
+ (struct sieve_validator *valdtr, struct sieve_ast_argument *arg,
+ struct sieve_match_type_context *ctx,
+ struct sieve_ast_argument *key_arg);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-match.c b/pigeonhole/src/lib-sieve/sieve-match.c
new file mode 100644
index 0000000..37d37fe
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-match.c
@@ -0,0 +1,293 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "mempool.h"
+#include "hash.h"
+#include "array.h"
+#include "str-sanitize.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-runtime-trace.h"
+
+#include "sieve-match.h"
+
+/*
+ * Matching implementation
+ */
+
+struct sieve_match_context *sieve_match_begin
+(const struct sieve_runtime_env *renv,
+ const struct sieve_match_type *mcht,
+ const struct sieve_comparator *cmp)
+{
+ struct sieve_match_context *mctx;
+ pool_t pool;
+
+ /* Reject unimplemented match-type */
+ if ( mcht->def == NULL || (mcht->def->match == NULL &&
+ mcht->def->match_keys == NULL && mcht->def->match_key == NULL) )
+ return NULL;
+
+ /* Create match context */
+ pool = pool_alloconly_create("sieve_match_context", 1024);
+ mctx = p_new(pool, struct sieve_match_context, 1);
+ mctx->pool = pool;
+ mctx->runenv = renv;
+ mctx->match_type = mcht;
+ mctx->comparator = cmp;
+ mctx->exec_status = SIEVE_EXEC_OK;
+ mctx->trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING);
+
+ /* Trace */
+ if ( mctx->trace ) {
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(renv, 0,
+ "starting `:%s' match with `%s' comparator:",
+ sieve_match_type_name(mcht), sieve_comparator_name(cmp));
+ }
+
+ /* Initialize match type */
+ if ( mcht->def != NULL && mcht->def->match_init != NULL ) {
+ mcht->def->match_init(mctx);
+ }
+
+ return mctx;
+}
+
+int sieve_match_value
+(struct sieve_match_context *mctx, const char *value, size_t value_size,
+ struct sieve_stringlist *key_list)
+{
+ const struct sieve_match_type *mcht = mctx->match_type;
+ const struct sieve_runtime_env *renv = mctx->runenv;
+ int match, ret;
+
+ if ( mctx->trace ) {
+ sieve_runtime_trace(renv, 0,
+ "matching value `%s'", str_sanitize(value, 80));
+ }
+
+ /* Match to key values */
+
+ sieve_stringlist_reset(key_list);
+
+ if ( mctx->trace )
+ sieve_stringlist_set_trace(key_list, TRUE);
+
+ sieve_runtime_trace_descend(renv);
+
+ if ( mcht->def->match_keys != NULL ) {
+ /* Call match-type's own key match handler */
+ match = mcht->def->match_keys(mctx, value, value_size, key_list);
+ } else {
+ string_t *key_item = NULL;
+
+ /* Default key match loop */
+ match = 0;
+ while ( match == 0 &&
+ (ret=sieve_stringlist_next_item(key_list, &key_item)) > 0 ) {
+ T_BEGIN {
+ match = mcht->def->match_key
+ (mctx, value, value_size, str_c(key_item), str_len(key_item));
+
+ if ( mctx->trace ) {
+ sieve_runtime_trace(renv, 0,
+ "with key `%s' => %d", str_sanitize(str_c(key_item), 80),
+ match);
+ }
+ } T_END;
+ }
+
+ if ( ret < 0 ) {
+ mctx->exec_status = key_list->exec_status;
+ match = -1;
+ }
+ }
+
+ sieve_runtime_trace_ascend(renv);
+
+ if ( mctx->match_status < 0 || match < 0 )
+ mctx->match_status = -1;
+ else
+ mctx->match_status =
+ ( mctx->match_status > match ? mctx->match_status : match );
+ return match;
+}
+
+int sieve_match_end(struct sieve_match_context **mctx, int *exec_status)
+{
+ const struct sieve_match_type *mcht = (*mctx)->match_type;
+ const struct sieve_runtime_env *renv = (*mctx)->runenv;
+ int match = (*mctx)->match_status;
+
+ if ( mcht->def != NULL && mcht->def->match_deinit != NULL )
+ mcht->def->match_deinit(*mctx);
+
+ if ( exec_status != NULL )
+ *exec_status = (*mctx)->exec_status;
+
+ pool_unref(&(*mctx)->pool);
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
+ "finishing match with result: %s",
+ ( match > 0 ? "matched" : ( match < 0 ? "error" : "not matched" ) ));
+ sieve_runtime_trace_ascend(renv);
+
+ return match;
+}
+
+int sieve_match
+(const struct sieve_runtime_env *renv,
+ const struct sieve_match_type *mcht,
+ const struct sieve_comparator *cmp,
+ struct sieve_stringlist *value_list,
+ struct sieve_stringlist *key_list,
+ int *exec_status)
+{
+ struct sieve_match_context *mctx;
+ string_t *value_item = NULL;
+ int match, ret;
+
+ if ( (mctx=sieve_match_begin(renv, mcht, cmp)) == NULL )
+ return 0;
+
+ /* Match value to keys */
+
+ sieve_stringlist_reset(value_list);
+
+ if ( mctx->trace )
+ sieve_stringlist_set_trace(value_list, TRUE);
+
+ if ( mcht->def->match != NULL ) {
+ /* Call match-type's match handler */
+ match = mctx->match_status =
+ mcht->def->match(mctx, value_list, key_list);
+
+ } else {
+ /* Default value match loop */
+
+ match = 0;
+ while ( match == 0 &&
+ (ret=sieve_stringlist_next_item(value_list, &value_item)) > 0 ) {
+
+ match = sieve_match_value
+ (mctx, str_c(value_item), str_len(value_item), key_list);
+ }
+
+ if ( ret < 0 ) {
+ mctx->exec_status = value_list->exec_status;
+ match = -1;
+ }
+ }
+
+ (void)sieve_match_end(&mctx, exec_status);
+ return match;
+}
+
+/*
+ * Reading match operands
+ */
+
+int sieve_match_opr_optional_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address, int *opt_code)
+{
+ int _opt_code = 0;
+ bool final = FALSE, opok = TRUE;
+
+ if ( opt_code == NULL ) {
+ opt_code = &_opt_code;
+ final = TRUE;
+ }
+
+ while ( opok ) {
+ int opt;
+
+ if ( (opt=sieve_opr_optional_dump(denv, address, opt_code)) <= 0 )
+ return opt;
+
+ switch ( *opt_code ) {
+ case SIEVE_MATCH_OPT_COMPARATOR:
+ opok = sieve_opr_comparator_dump(denv, address);
+ break;
+ case SIEVE_MATCH_OPT_MATCH_TYPE:
+ opok = sieve_opr_match_type_dump(denv, address);
+ break;
+ default:
+ return ( final ? -1 : 1 );
+ }
+ }
+
+ return -1;
+}
+
+int sieve_match_opr_optional_read
+(const struct sieve_runtime_env *renv, sieve_size_t *address, int *opt_code,
+ int *exec_status, struct sieve_comparator *cmp, struct sieve_match_type *mcht)
+{
+ int _opt_code = 0;
+ bool final = FALSE;
+ int status = SIEVE_EXEC_OK;
+
+ if ( opt_code == NULL ) {
+ opt_code = &_opt_code;
+ final = TRUE;
+ }
+
+ if ( exec_status != NULL )
+ *exec_status = SIEVE_EXEC_OK;
+
+ while ( status == SIEVE_EXEC_OK ) {
+ int opt;
+
+ if ( (opt=sieve_opr_optional_read(renv, address, opt_code)) <= 0 ){
+ if ( opt < 0 && exec_status != NULL )
+ *exec_status = SIEVE_EXEC_BIN_CORRUPT;
+ return opt;
+ }
+
+ switch ( *opt_code ) {
+ case SIEVE_MATCH_OPT_COMPARATOR:
+ if (cmp == NULL) {
+ sieve_runtime_trace_error(renv, "unexpected comparator operand");
+ if ( exec_status != NULL )
+ *exec_status = SIEVE_EXEC_BIN_CORRUPT;
+ return -1;
+ }
+ status = sieve_opr_comparator_read(renv, address, cmp);
+ break;
+ case SIEVE_MATCH_OPT_MATCH_TYPE:
+ if (mcht == NULL) {
+ sieve_runtime_trace_error(renv, "unexpected match-type operand");
+ if ( exec_status != NULL )
+ *exec_status = SIEVE_EXEC_BIN_CORRUPT;
+ return -1;
+ }
+ status = sieve_opr_match_type_read(renv, address, mcht);
+ break;
+ default:
+ if ( final ) {
+ sieve_runtime_trace_error(renv, "invalid optional operand");
+ if ( exec_status != NULL )
+ *exec_status = SIEVE_EXEC_BIN_CORRUPT;
+ return -1;
+ }
+ return 1;
+ }
+ }
+
+ if ( exec_status != NULL )
+ *exec_status = status;
+ return -1;
+}
+
diff --git a/pigeonhole/src/lib-sieve/sieve-match.h b/pigeonhole/src/lib-sieve/sieve-match.h
new file mode 100644
index 0000000..d4d726f
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-match.h
@@ -0,0 +1,68 @@
+#ifndef SIEVE_MATCH_H
+#define SIEVE_MATCH_H
+
+#include "sieve-common.h"
+
+/*
+ * Matching context
+ */
+
+struct sieve_match_context {
+ pool_t pool;
+
+ const struct sieve_runtime_env *runenv;
+
+ const struct sieve_match_type *match_type;
+ const struct sieve_comparator *comparator;
+
+ void *data;
+
+ int match_status;
+ int exec_status;
+
+ bool trace:1;
+};
+
+/*
+ * Matching implementation
+ */
+
+/* Manual value iteration (for when multiple matches are allowed) */
+struct sieve_match_context *sieve_match_begin
+ (const struct sieve_runtime_env *renv,
+ const struct sieve_match_type *mcht,
+ const struct sieve_comparator *cmp);
+int sieve_match_value
+ (struct sieve_match_context *mctx, const char *value, size_t value_size,
+ struct sieve_stringlist *key_list);
+int sieve_match_end(struct sieve_match_context **mctx, int *exec_status);
+
+/* Default matching operation */
+int sieve_match
+ (const struct sieve_runtime_env *renv,
+ const struct sieve_match_type *mcht,
+ const struct sieve_comparator *cmp,
+ struct sieve_stringlist *value_list,
+ struct sieve_stringlist *key_list,
+ int *exec_status);
+
+/*
+ * Read matching operands
+ */
+
+enum sieve_match_opt_operand {
+ SIEVE_MATCH_OPT_END,
+ SIEVE_MATCH_OPT_COMPARATOR,
+ SIEVE_MATCH_OPT_MATCH_TYPE,
+ SIEVE_MATCH_OPT_LAST
+};
+
+int sieve_match_opr_optional_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address, int *opt_code);
+
+int sieve_match_opr_optional_read
+ (const struct sieve_runtime_env *renv, sieve_size_t *address, int *opt_code,
+ int *exec_status, struct sieve_comparator *cmp,
+ struct sieve_match_type *mcht);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-message.c b/pigeonhole/src/lib-sieve/sieve-message.c
new file mode 100644
index 0000000..d086883
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-message.c
@@ -0,0 +1,1845 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "mempool.h"
+#include "array.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "istream.h"
+#include "time-util.h"
+#include "rfc822-parser.h"
+#include "message-date.h"
+#include "message-parser.h"
+#include "message-decoder.h"
+#include "message-header-decode.h"
+#include "mail-html2text.h"
+#include "mail-storage.h"
+#include "mail-user.h"
+#include "smtp-params.h"
+#include "master-service.h"
+#include "master-service-settings.h"
+#include "raw-storage.h"
+
+#include "edit-mail.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+#include "sieve-error.h"
+#include "sieve-extensions.h"
+#include "sieve-code.h"
+#include "sieve-address.h"
+#include "sieve-address-parts.h"
+#include "sieve-runtime.h"
+#include "sieve-runtime-trace.h"
+#include "sieve-match.h"
+#include "sieve-interpreter.h"
+
+#include "sieve-message.h"
+
+/*
+ * Message transmission
+ */
+
+const char *sieve_message_get_new_id(const struct sieve_instance *svinst)
+{
+ static int count = 0;
+
+ return t_strdup_printf("<dovecot-sieve-%s-%s-%d@%s>",
+ dec2str(ioloop_timeval.tv_sec), dec2str(ioloop_timeval.tv_usec),
+ count++, svinst->hostname);
+}
+
+/*
+ * Message context
+ */
+
+struct sieve_message_header {
+ const char *name;
+
+ const unsigned char *value, *utf8_value;
+ size_t value_len, utf8_value_len;
+};
+
+struct sieve_message_part {
+ struct sieve_message_part *parent, *next, *children;
+
+ ARRAY(struct sieve_message_header) headers;
+
+ const char *content_type;
+ const char *content_disposition;
+
+ const char *decoded_body;
+ const char *text_body;
+ size_t decoded_body_size;
+ size_t text_body_size;
+
+ bool have_body:1; /* there's the empty end-of-headers line */
+ bool epilogue:1; /* this is a multipart epilogue */
+};
+
+struct sieve_message_version {
+ struct mail *mail;
+ struct mailbox *box;
+ struct mailbox_transaction_context *trans;
+ struct edit_mail *edit_mail;
+};
+
+struct sieve_message_context {
+ pool_t pool;
+ pool_t context_pool;
+ int refcount;
+
+ struct sieve_instance *svinst;
+ struct timeval time;
+
+ struct mail_user *mail_user;
+ const struct sieve_message_data *msgdata;
+
+ /* Message versioning */
+
+ struct mail_user *raw_mail_user;
+ ARRAY(struct sieve_message_version) versions;
+
+ /* Context data for extensions */
+
+ ARRAY(void *) ext_contexts;
+
+ /* Body */
+
+ ARRAY(struct sieve_message_part *) cached_body_parts;
+ ARRAY(struct sieve_message_part_data) return_body_parts;
+ buffer_t *raw_body;
+
+ bool edit_snapshot:1;
+ bool substitute_snapshot:1;
+};
+
+/*
+ * Message versions
+ */
+
+static inline struct sieve_message_version *sieve_message_version_new
+(struct sieve_message_context *msgctx)
+{
+ return array_append_space(&msgctx->versions);
+}
+
+static inline struct sieve_message_version *sieve_message_version_get
+(struct sieve_message_context *msgctx)
+{
+ struct sieve_message_version *versions;
+ unsigned int count;
+
+ versions = array_get_modifiable(&msgctx->versions, &count);
+ if ( count == 0 )
+ return array_append_space(&msgctx->versions);
+
+ return &versions[count-1];
+}
+
+static inline void sieve_message_version_free
+(struct sieve_message_version *version)
+{
+ if ( version->edit_mail != NULL ) {
+ edit_mail_unwrap(&version->edit_mail);
+ version->edit_mail = NULL;
+ }
+
+ if ( version->mail != NULL ) {
+ mail_free(&version->mail);
+ mailbox_transaction_rollback(&version->trans);
+ mailbox_free(&version->box);
+ version->mail = NULL;
+ }
+}
+
+/*
+ * Message context object
+ */
+
+struct sieve_message_context *sieve_message_context_create
+(struct sieve_instance *svinst, struct mail_user *mail_user,
+ const struct sieve_message_data *msgdata)
+{
+ struct sieve_message_context *msgctx;
+
+ msgctx = i_new(struct sieve_message_context, 1);
+ msgctx->refcount = 1;
+ msgctx->svinst = svinst;
+
+ msgctx->mail_user = mail_user;
+ msgctx->msgdata = msgdata;
+
+ i_gettimeofday(&msgctx->time);
+
+ sieve_message_context_reset(msgctx);
+
+ return msgctx;
+}
+
+void sieve_message_context_ref(struct sieve_message_context *msgctx)
+{
+ msgctx->refcount++;
+}
+
+static void sieve_message_context_clear(struct sieve_message_context *msgctx)
+{
+ struct sieve_message_version *versions;
+ unsigned int count, i;
+
+ if ( msgctx->pool != NULL ) {
+ versions = array_get_modifiable(&msgctx->versions, &count);
+
+ for ( i = 0; i < count; i++ ) {
+ sieve_message_version_free(&versions[i]);
+ }
+
+ pool_unref(&(msgctx->pool));
+ }
+}
+
+void sieve_message_context_unref(struct sieve_message_context **msgctx)
+{
+ i_assert((*msgctx)->refcount > 0);
+
+ if (--(*msgctx)->refcount != 0)
+ return;
+
+ if ( (*msgctx)->raw_mail_user != NULL )
+ mail_user_unref(&(*msgctx)->raw_mail_user);
+
+ sieve_message_context_clear(*msgctx);
+
+ if ( (*msgctx)->context_pool != NULL )
+ pool_unref(&((*msgctx)->context_pool));
+
+ i_free(*msgctx);
+ *msgctx = NULL;
+}
+
+static void sieve_message_context_flush(struct sieve_message_context *msgctx)
+{
+ pool_t pool;
+
+ if ( msgctx->context_pool != NULL )
+ pool_unref(&(msgctx->context_pool));
+
+ msgctx->context_pool = pool =
+ pool_alloconly_create("sieve_message_context_data", 2048);
+
+ p_array_init(&msgctx->ext_contexts, pool,
+ sieve_extensions_get_count(msgctx->svinst));
+
+ p_array_init(&msgctx->cached_body_parts, pool, 8);
+ p_array_init(&msgctx->return_body_parts, pool, 8);
+ msgctx->raw_body = NULL;
+}
+
+void sieve_message_context_reset(struct sieve_message_context *msgctx)
+{
+ sieve_message_context_clear(msgctx);
+
+ msgctx->pool = pool_alloconly_create("sieve_message_context", 1024);
+
+ p_array_init(&msgctx->versions, msgctx->pool, 4);
+
+ sieve_message_context_flush(msgctx);
+}
+
+pool_t sieve_message_context_pool(struct sieve_message_context *msgctx)
+{
+ return msgctx->context_pool;
+}
+
+void sieve_message_context_time(struct sieve_message_context *msgctx,
+ struct timeval *time)
+{
+ *time = msgctx->time;
+}
+
+/* Extension support */
+
+void sieve_message_context_extension_set
+(struct sieve_message_context *msgctx, const struct sieve_extension *ext,
+ void *context)
+{
+ if ( ext->id < 0 ) return;
+
+ array_idx_set(&msgctx->ext_contexts, (unsigned int) ext->id, &context);
+}
+
+const void *sieve_message_context_extension_get
+(struct sieve_message_context *msgctx, const struct sieve_extension *ext)
+{
+ void * const *ctx;
+
+ if ( ext->id < 0 || ext->id >= (int) array_count(&msgctx->ext_contexts) )
+ return NULL;
+
+ ctx = array_idx(&msgctx->ext_contexts, (unsigned int) ext->id);
+
+ return *ctx;
+}
+
+/* Envelope */
+
+const struct smtp_address *sieve_message_get_orig_recipient
+(struct sieve_message_context *msgctx)
+{
+ const struct sieve_message_data *msgdata = msgctx->msgdata;
+ const struct smtp_address *orcpt_to = NULL;
+
+ if ( msgdata->envelope.rcpt_params != NULL ) {
+ orcpt_to = msgdata->envelope.rcpt_params->orcpt.addr;
+ if ( !smtp_address_isnull(orcpt_to) )
+ return orcpt_to;
+ }
+
+ orcpt_to = msgdata->envelope.rcpt_to;
+ return ( !smtp_address_isnull(orcpt_to) ? orcpt_to : NULL );
+}
+
+const struct smtp_address *sieve_message_get_final_recipient
+(struct sieve_message_context *msgctx)
+{
+ const struct sieve_message_data *msgdata = msgctx->msgdata;
+ const struct smtp_address *rcpt_to = msgdata->envelope.rcpt_to;
+
+ return ( !smtp_address_isnull(rcpt_to) ? rcpt_to : NULL);
+}
+
+const struct smtp_address *sieve_message_get_sender
+(struct sieve_message_context *msgctx)
+{
+ const struct sieve_message_data *msgdata = msgctx->msgdata;
+ const struct smtp_address *mail_from = msgdata->envelope.mail_from;
+
+ return ( !smtp_address_isnull(mail_from) ? mail_from : NULL);
+}
+
+/*
+ * Mail
+ */
+
+int sieve_message_substitute
+(struct sieve_message_context *msgctx, struct istream *input)
+{
+ static const char *wanted_headers[] = {
+ "From", "Message-ID", "Subject", "Return-Path", NULL
+ };
+ static const struct smtp_address default_sender = {
+ .localpart = DEFAULT_ENVELOPE_SENDER,
+ .domain = NULL,
+ };
+ struct mail_user *mail_user = msgctx->mail_user;
+ struct sieve_message_version *version;
+ struct mailbox_header_lookup_ctx *headers_ctx;
+ struct mailbox *box = NULL;
+ const struct smtp_address *sender;
+ int ret;
+
+ i_assert(input->blocking);
+
+ if ( msgctx->raw_mail_user == NULL ) {
+ void **sets = master_service_settings_get_others(master_service);
+
+ msgctx->raw_mail_user =
+ raw_storage_create_from_set(mail_user->set_info, sets[0]);
+ }
+
+ i_stream_seek(input, 0);
+ sender = sieve_message_get_sender(msgctx);
+ sender = (sender == NULL ? &default_sender : sender);
+ ret = raw_mailbox_alloc_stream(msgctx->raw_mail_user, input, (time_t)-1,
+ smtp_address_encode(sender), &box);
+
+ if ( ret < 0 ) {
+ e_error(msgctx->svinst->event,
+ "can't open substituted mail as raw: %s",
+ mailbox_get_last_internal_error(box, NULL));
+ return -1;
+ }
+
+ if ( msgctx->substitute_snapshot ) {
+ version = sieve_message_version_new(msgctx);
+ } else {
+ version = sieve_message_version_get(msgctx);
+ sieve_message_version_free(version);
+ }
+
+ version->box = box;
+ version->trans = mailbox_transaction_begin(box, 0, __func__);
+ headers_ctx = mailbox_header_lookup_init(box, wanted_headers);
+ version->mail = mail_alloc(version->trans, 0, headers_ctx);
+ mailbox_header_lookup_unref(&headers_ctx);
+ mail_set_seq(version->mail, 1);
+
+ sieve_message_context_flush(msgctx);
+
+ msgctx->substitute_snapshot = FALSE;
+ msgctx->edit_snapshot = FALSE;
+
+ return 1;
+}
+
+struct mail *sieve_message_get_mail
+(struct sieve_message_context *msgctx)
+{
+ const struct sieve_message_version *versions;
+ unsigned int count;
+
+ versions = array_get(&msgctx->versions, &count);
+ if ( count == 0 )
+ return msgctx->msgdata->mail;
+
+ if ( versions[count-1].edit_mail != NULL )
+ return edit_mail_get_mail(versions[count-1].edit_mail);
+
+ return versions[count-1].mail;
+}
+
+struct edit_mail *sieve_message_edit
+(struct sieve_message_context *msgctx)
+{
+ struct sieve_message_version *version;
+
+ version = sieve_message_version_get(msgctx);
+
+ if ( version->edit_mail == NULL ) {
+ version->edit_mail = edit_mail_wrap
+ (( version->mail == NULL ? msgctx->msgdata->mail : version->mail ));
+ } else if ( msgctx->edit_snapshot ) {
+ version->edit_mail = edit_mail_snapshot(version->edit_mail);
+ }
+
+ msgctx->edit_snapshot = FALSE;
+
+ return version->edit_mail;
+}
+
+void sieve_message_snapshot
+(struct sieve_message_context *msgctx)
+{
+ msgctx->edit_snapshot = TRUE;
+ msgctx->substitute_snapshot = TRUE;
+}
+
+/*
+ * Message header list
+ */
+
+/* Forward declarations */
+
+static int sieve_message_header_list_next_item
+ (struct sieve_header_list *_hdrlist, const char **name_r,
+ string_t **value_r);
+static int sieve_message_header_list_next_value
+ (struct sieve_stringlist *_strlist, string_t **value_r);
+static void sieve_message_header_list_reset
+ (struct sieve_stringlist *_strlist);
+
+/* String list object */
+
+struct sieve_message_header_list {
+ struct sieve_header_list hdrlist;
+
+ struct sieve_stringlist *field_names;
+
+ const char *header_name;
+ const char *const *headers;
+ int headers_index;
+
+ bool mime_decode:1;
+};
+
+struct sieve_header_list *sieve_message_header_list_create
+(const struct sieve_runtime_env *renv,
+ struct sieve_stringlist *field_names,
+ bool mime_decode)
+{
+ struct sieve_message_header_list *hdrlist;
+
+ hdrlist = t_new(struct sieve_message_header_list, 1);
+ hdrlist->hdrlist.strlist.runenv = renv;
+ hdrlist->hdrlist.strlist.exec_status = SIEVE_EXEC_OK;
+ hdrlist->hdrlist.strlist.next_item = sieve_message_header_list_next_value;
+ hdrlist->hdrlist.strlist.reset = sieve_message_header_list_reset;
+ hdrlist->hdrlist.next_item = sieve_message_header_list_next_item;
+ hdrlist->field_names = field_names;
+ hdrlist->mime_decode = mime_decode;
+
+ return &hdrlist->hdrlist;
+}
+
+// NOTE: get rid of this once we have a proper Sieve string type
+static inline string_t *_header_right_trim(const char *raw)
+{
+ string_t *result;
+ const char *p, *pend;
+
+ pend = raw + strlen(raw);
+ if (raw == pend) {
+ result = t_str_new(1);
+ } else {
+ for ( p = pend-1; p >= raw; p-- ) {
+ if ( *p != ' ' && *p != '\t' ) break;
+ }
+ result = t_str_new(p - raw + 1);
+ str_append_data(result, raw, p - raw + 1);
+ }
+ return result;
+}
+
+/* String list implementation */
+
+static int sieve_message_header_list_next_item
+(struct sieve_header_list *_hdrlist, const char **name_r,
+ string_t **value_r)
+{
+ struct sieve_message_header_list *hdrlist =
+ (struct sieve_message_header_list *) _hdrlist;
+ const struct sieve_runtime_env *renv = _hdrlist->strlist.runenv;
+ struct mail *mail = sieve_message_get_mail(renv->msgctx);
+
+ if ( name_r != NULL )
+ *name_r = NULL;
+ *value_r = NULL;
+
+ /* Check for end of current header list */
+ if ( hdrlist->headers == NULL ) {
+ hdrlist->headers_index = 0;
+ } else if ( hdrlist->headers[hdrlist->headers_index] == NULL ) {
+ hdrlist->headers = NULL;
+ hdrlist->headers_index = 0;
+ }
+
+ /* Fetch next header */
+ while ( hdrlist->headers == NULL ) {
+ string_t *hdr_item = NULL;
+ int ret;
+
+ /* Read next header name from source list */
+ if ( (ret=sieve_stringlist_next_item
+ (hdrlist->field_names, &hdr_item)) <= 0 )
+ return ret;
+
+ hdrlist->header_name = str_c(hdr_item);
+
+ if ( _hdrlist->strlist.trace ) {
+ sieve_runtime_trace(renv, 0,
+ "extracting `%s' headers from message",
+ str_sanitize(str_c(hdr_item), 80));
+ }
+
+ /* Fetch all matching headers from the e-mail */
+ if ( hdrlist->mime_decode ) {
+ ret = mail_get_headers_utf8(mail,
+ str_c(hdr_item), &hdrlist->headers);
+ } else {
+ ret = mail_get_headers(mail,
+ str_c(hdr_item), &hdrlist->headers);
+ }
+
+ if (ret < 0) {
+ _hdrlist->strlist.exec_status =
+ sieve_runtime_mail_error(renv, mail,
+ "failed to read header field `%s'", str_c(hdr_item));
+ return -1;
+ }
+
+ if ( ret == 0 || hdrlist->headers[0] == NULL ) {
+ /* Try next item when no headers found */
+ hdrlist->headers = NULL;
+ }
+ }
+
+ /* Return next item */
+ if ( name_r != NULL )
+ *name_r = hdrlist->header_name;
+ *value_r = _header_right_trim(hdrlist->headers[hdrlist->headers_index++]);
+ return 1;
+}
+
+static int sieve_message_header_list_next_value
+(struct sieve_stringlist *_strlist, string_t **value_r)
+{
+ struct sieve_header_list *hdrlist =
+ (struct sieve_header_list *) _strlist;
+
+ return sieve_message_header_list_next_item
+ (hdrlist, NULL, value_r);
+}
+
+static void sieve_message_header_list_reset
+(struct sieve_stringlist *strlist)
+{
+ struct sieve_message_header_list *hdrlist =
+ (struct sieve_message_header_list *) strlist;
+
+ hdrlist->headers = NULL;
+ hdrlist->headers_index = 0;
+ sieve_stringlist_reset(hdrlist->field_names);
+}
+
+/*
+ * Header override operand
+ */
+
+const struct sieve_operand_class sieve_message_override_operand_class =
+ { "header-override" };
+
+bool sieve_opr_message_override_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ struct sieve_message_override svmo;
+ const struct sieve_message_override_def *hodef;
+
+ if ( !sieve_opr_object_dump
+ (denv, &sieve_message_override_operand_class, address, &svmo.object) )
+ return FALSE;
+
+ hodef = svmo.def =
+ (const struct sieve_message_override_def *) svmo.object.def;
+
+ if ( hodef->dump_context != NULL ) {
+ sieve_code_descend(denv);
+ if ( !hodef->dump_context(&svmo, denv, address) ) {
+ return FALSE;
+ }
+ sieve_code_ascend(denv);
+ }
+
+ return TRUE;
+}
+
+int sieve_opr_message_override_read
+(const struct sieve_runtime_env *renv, sieve_size_t *address,
+ struct sieve_message_override *svmo)
+{
+ const struct sieve_message_override_def *hodef;
+ int ret;
+
+ svmo->context = NULL;
+
+ if ( !sieve_opr_object_read
+ (renv, &sieve_message_override_operand_class, address, &svmo->object) )
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ hodef = svmo->def =
+ (const struct sieve_message_override_def *) svmo->object.def;
+
+ if ( hodef->read_context != NULL &&
+ (ret=hodef->read_context(svmo, renv, address, &svmo->context)) <= 0 )
+ return ret;
+
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Optional operands
+ */
+
+int sieve_message_opr_optional_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address,
+ signed int *opt_code)
+{
+ signed int _opt_code = 0;
+ bool final = FALSE, opok = TRUE;
+
+ if ( opt_code == NULL ) {
+ opt_code = &_opt_code;
+ final = TRUE;
+ }
+
+ while ( opok ) {
+ int opt;
+
+ if ( (opt=sieve_addrmatch_opr_optional_dump
+ (denv, address, opt_code)) <= 0 )
+ return opt;
+
+ if ( *opt_code == SIEVE_OPT_MESSAGE_OVERRIDE ) {
+ opok = sieve_opr_message_override_dump(denv, address);
+ } else {
+ return ( final ? -1 : 1 );
+ }
+ }
+
+ return -1;
+}
+
+int sieve_message_opr_optional_read
+(const struct sieve_runtime_env *renv, sieve_size_t *address,
+ signed int *opt_code, int *exec_status,
+ struct sieve_address_part *addrp, struct sieve_match_type *mcht,
+ struct sieve_comparator *cmp,
+ ARRAY_TYPE(sieve_message_override) *svmos)
+{
+ signed int _opt_code = 0;
+ bool final = FALSE;
+ int ret;
+
+ if ( opt_code == NULL ) {
+ opt_code = &_opt_code;
+ final = TRUE;
+ }
+
+ if ( exec_status != NULL )
+ *exec_status = SIEVE_EXEC_OK;
+
+ for ( ;; ) {
+ int opt;
+
+ if ( (opt=sieve_addrmatch_opr_optional_read
+ (renv, address, opt_code, exec_status, addrp, mcht, cmp)) <= 0 )
+ return opt;
+
+ if ( *opt_code == SIEVE_OPT_MESSAGE_OVERRIDE ) {
+ struct sieve_message_override svmo;
+ const struct sieve_message_override *svmo_idx;
+ unsigned int count, i;
+
+ if ( (ret=sieve_opr_message_override_read
+ (renv, address, &svmo)) <= 0 ) {
+ if ( exec_status != NULL )
+ *exec_status = ret;
+ return -1;
+ }
+
+ if ( !array_is_created(svmos) )
+ t_array_init(svmos, 8);
+ /* insert in sorted sequence */
+ svmo_idx = array_get(svmos, &count);
+ for (i = 0; i < count; i++) {
+ if (svmo.def->sequence < svmo_idx[i].def->sequence) {
+ array_insert(svmos, i, &svmo, 1);
+ break;
+ }
+ }
+ if (count == i)
+ array_append(svmos, &svmo, 1);
+ } else {
+ if ( final ) {
+ sieve_runtime_trace_error(renv, "invalid optional operand");
+ if ( exec_status != NULL )
+ *exec_status = SIEVE_EXEC_BIN_CORRUPT;
+ return -1;
+ }
+ return 1;
+ }
+ }
+
+ i_unreached();
+ return -1;
+}
+
+/*
+ * Message header
+ */
+
+int sieve_message_get_header_fields
+(const struct sieve_runtime_env *renv,
+ struct sieve_stringlist *field_names,
+ ARRAY_TYPE(sieve_message_override) *svmos,
+ bool mime_decode, struct sieve_stringlist **fields_r)
+{
+ const struct sieve_message_override *svmo;
+ unsigned int count, i;
+ int ret;
+
+ if ( svmos == NULL || !array_is_created(svmos) ||
+ array_count(svmos) == 0 ) {
+ struct sieve_header_list *headers;
+ headers = sieve_message_header_list_create
+ (renv, field_names, mime_decode);
+ *fields_r = &headers->strlist;
+ return SIEVE_EXEC_OK;
+ }
+
+ svmo = array_get(svmos, &count);
+ if ( svmo[0].def->sequence == 0 &&
+ svmo[0].def->header_override != NULL ) {
+ *fields_r = field_names;
+ } else {
+ struct sieve_header_list *headers;
+ headers = sieve_message_header_list_create
+ (renv, field_names, mime_decode);
+ *fields_r = &headers->strlist;
+ }
+
+ for ( i = 0; i < count; i++ ) {
+ if ( svmo[i].def->header_override != NULL &&
+ (ret=svmo[i].def->header_override
+ (&svmo[i], renv, mime_decode, fields_r)) <= 0 )
+ return ret;
+ }
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Message part
+ */
+
+struct sieve_message_part *sieve_message_part_parent
+(struct sieve_message_part *mpart)
+{
+ return mpart->parent;
+}
+
+struct sieve_message_part *sieve_message_part_next
+(struct sieve_message_part *mpart)
+{
+ return mpart->next;
+}
+
+struct sieve_message_part *sieve_message_part_children
+(struct sieve_message_part *mpart)
+{
+ return mpart->children;
+}
+
+const char *sieve_message_part_content_type
+(struct sieve_message_part *mpart)
+{
+ return mpart->content_type;
+}
+
+const char *sieve_message_part_content_disposition
+(struct sieve_message_part *mpart)
+{
+ return mpart->content_disposition;
+}
+
+int sieve_message_part_get_first_header
+(struct sieve_message_part *mpart, const char *field,
+ const char **value_r)
+{
+ const struct sieve_message_header *headers;
+ unsigned int i, count;
+
+ headers = array_get(&mpart->headers, &count);
+ for ( i = 0; i < count; i++ ) {
+ if ( strcasecmp( headers[i].name, field) == 0 ) {
+ i_assert( headers[i].value[headers[i].value_len] == '\0' );
+ *value_r = (const char *)headers[i].value;
+ return 1;
+ }
+ }
+
+ *value_r = NULL;
+ return 0;
+}
+
+void sieve_message_part_get_data
+(struct sieve_message_part *mpart,
+ struct sieve_message_part_data *data, bool text)
+{
+ i_zero(data);
+ data->content_type = mpart->content_type;
+ data->content_disposition = mpart->content_disposition;
+
+ if ( !text ) {
+ data->content = mpart->decoded_body;
+ data->size = mpart->decoded_body_size;
+ } else if ( mpart->children != NULL ) {
+ data->content = "";
+ data->size = 0;
+ } else {
+ data->content = mpart->text_body;
+ data->size = mpart->text_body_size;
+ }
+}
+
+/*
+ * Message body
+ */
+
+static void str_replace_nuls(string_t *str)
+{
+ char *data = str_c_modifiable(str);
+ unsigned int i, len = str_len(str);
+
+ for (i = 0; i < len; i++) {
+ if (data[i] == '\0')
+ data[i] = ' ';
+ }
+}
+
+static bool _is_wanted_content_type
+(const char * const *wanted_types, const char *content_type)
+ATTR_NULL(1)
+{
+ const char *subtype;
+ size_t type_len;
+
+ if ( wanted_types == NULL )
+ return TRUE;
+
+ subtype = strchr(content_type, '/');
+ type_len = ( subtype == NULL ? strlen(content_type) :
+ (size_t)(subtype - content_type) );
+
+ i_assert( wanted_types != NULL );
+
+ for (; *wanted_types != NULL; wanted_types++) {
+ const char *wanted_subtype;
+
+ if (**wanted_types == '\0') {
+ /* empty string matches everything */
+ return TRUE;
+ }
+
+ wanted_subtype = strchr(*wanted_types, '/');
+ if (wanted_subtype == NULL) {
+ /* match only main type */
+ if (strlen(*wanted_types) == type_len &&
+ strncasecmp(*wanted_types, content_type, type_len) == 0)
+ return TRUE;
+ } else {
+ /* match whole type/subtype */
+ if (strcasecmp(*wanted_types, content_type) == 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static bool sieve_message_body_get_return_parts
+(const struct sieve_runtime_env *renv,
+ const char * const *wanted_types,
+ bool extract_text)
+{
+ struct sieve_message_context *msgctx = renv->msgctx;
+ struct sieve_message_part *const *body_parts;
+ unsigned int i, count;
+ struct sieve_message_part_data *return_part;
+
+ /* Check whether any body parts are cached already */
+ body_parts = array_get(&msgctx->cached_body_parts, &count);
+ if ( count == 0 )
+ return FALSE;
+
+ /* Clear result array */
+ array_clear(&msgctx->return_body_parts);
+
+ /* Fill result array with requested content_types */
+ for (i = 0; i < count; i++) {
+ if (!body_parts[i]->have_body) {
+ /* Part has no body; according to RFC this MUST not match to anything and
+ * therefore it is not included in the result.
+ */
+ continue;
+ }
+
+ /* Skip content types that are not requested */
+ if (!_is_wanted_content_type
+ (wanted_types, body_parts[i]->content_type))
+ continue;
+
+ /* Add new item to the result */
+ return_part = array_append_space(&msgctx->return_body_parts);
+ return_part->content_type = body_parts[i]->content_type;
+ return_part->content_disposition = body_parts[i]->content_disposition;
+
+ /* Depending on whether a decoded body part is requested, the appropriate
+ * cache item is read. If it is missing, this function fails and the cache
+ * needs to be completed by sieve_message_parts_add_missing().
+ */
+ if (extract_text) {
+ if (body_parts[i]->text_body == NULL)
+ return FALSE;
+ return_part->content = body_parts[i]->text_body;
+ return_part->size = body_parts[i]->text_body_size;
+ } else {
+ if (body_parts[i]->decoded_body == NULL)
+ return FALSE;
+ return_part->content = body_parts[i]->decoded_body;
+ return_part->size = body_parts[i]->decoded_body_size;
+ }
+ }
+
+ return TRUE;
+}
+
+static void sieve_message_part_save
+(const struct sieve_runtime_env *renv, buffer_t *buf,
+ struct sieve_message_part *body_part,
+ bool extract_text)
+{
+ struct sieve_message_context *msgctx = renv->msgctx;
+ pool_t pool = msgctx->context_pool;
+ buffer_t *result_buf, *text_buf = NULL;
+ char *part_data;
+ size_t part_size;
+
+ /* Extract text if requested */
+ result_buf = buf;
+ if ( extract_text && body_part->children == NULL &&
+ !body_part->epilogue ) {
+
+ if ( buf->used > 0 && mail_html2text_content_type_match
+ (body_part->content_type) ) {
+ struct mail_html2text *html2text;
+
+ text_buf = buffer_create_dynamic(default_pool, 4096);
+
+ /* Remove HTML markup */
+ html2text = mail_html2text_init(0);
+ mail_html2text_more(html2text, buf->data, buf->used, text_buf);
+ mail_html2text_deinit(&html2text);
+
+ result_buf = text_buf;
+ }
+ }
+
+ /* Add terminating NUL to the body part buffer */
+ buffer_append_c(result_buf, '\0');
+
+ /* Make copy of the buffer */
+ part_data = p_malloc(pool, result_buf->used);
+ memcpy(part_data, result_buf->data, result_buf->used);
+ part_size = result_buf->used - 1;
+
+ /* Free text buffer if used */
+ if ( text_buf != NULL)
+ buffer_free(&text_buf);
+
+ /* Depending on whether the part is processed into text, store message
+ * body in the appropriate cache location.
+ */
+ if ( !extract_text ) {
+ body_part->decoded_body = part_data;
+ body_part->decoded_body_size = part_size;
+ } else {
+ body_part->text_body = part_data;
+ body_part->text_body_size = part_size;
+ }
+
+ /* Clear buffer */
+ buffer_set_used_size(buf, 0);
+}
+
+static const char *
+_parse_content_type(const struct message_header_line *hdr)
+{
+ struct rfc822_parser_context parser;
+ string_t *content_type;
+
+ /* Initialize parsing */
+ rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
+ (void)rfc822_skip_lwsp(&parser);
+
+ /* Parse content type */
+ content_type = t_str_new(64);
+ if (rfc822_parse_content_type(&parser, content_type) < 0)
+ return "";
+
+ /* Content-type value must end here, otherwise it is invalid after all */
+ (void)rfc822_skip_lwsp(&parser);
+ if ( parser.data != parser.end && *parser.data != ';' )
+ return "";
+
+ /* Success */
+ return str_c(content_type);
+}
+
+static const char *
+_parse_content_disposition(const struct message_header_line *hdr)
+{
+ struct rfc822_parser_context parser;
+ string_t *content_disp;
+
+ /* Initialize parsing */
+ rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
+ (void)rfc822_skip_lwsp(&parser);
+
+ /* Parse content type */
+ content_disp = t_str_new(64);
+ if (rfc822_parse_mime_token(&parser, content_disp) < 0)
+ return "";
+
+ /* Content-type value must end here, otherwise it is invalid after all */
+ (void)rfc822_skip_lwsp(&parser);
+ if ( parser.data != parser.end && *parser.data != ';' )
+ return "";
+
+ /* Success */
+ return str_c(content_disp);
+}
+
+/* sieve_message_parts_add_missing():
+ * Add requested message body parts to the cache that are missing.
+ */
+static int sieve_message_parts_add_missing
+(const struct sieve_runtime_env *renv,
+ const char *const *content_types,
+ bool extract_text, bool iter_all)
+ ATTR_NULL(2)
+{
+ struct sieve_message_context *msgctx = renv->msgctx;
+ pool_t pool = msgctx->context_pool;
+ struct mail *mail = sieve_message_get_mail(renv->msgctx);
+ struct message_parser_settings mparser_set = {
+ .hdr_flags = MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP,
+ .flags = MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS,
+ };
+ ARRAY(struct sieve_message_header) headers;
+ struct sieve_message_part *body_part, *header_part, *last_part;
+ struct message_parser_ctx *parser;
+ struct message_decoder_context *decoder;
+ struct message_block block, decoded;
+ struct message_part *mparts, *prev_mpart = NULL;
+ buffer_t *buf;
+ struct istream *input;
+ unsigned int idx = 0;
+ bool save_body = FALSE, have_all;
+ string_t *hdr_content = NULL;
+
+ /* First check whether any are missing */
+ if ( !iter_all && sieve_message_body_get_return_parts
+ (renv, content_types, extract_text) ) {
+ /* Cache hit; all are present */
+ return SIEVE_EXEC_OK;
+ }
+
+ /* Get the message stream */
+ if ( mail_get_stream(mail, NULL, NULL, &input) < 0 ) {
+ return sieve_runtime_mail_error(renv, mail,
+ "failed to open input message");
+ }
+ if (mail_get_parts(mail, &mparts) < 0) {
+ return sieve_runtime_mail_error(renv, mail,
+ "failed to parse input message parts");
+ }
+
+ buf = buffer_create_dynamic(default_pool, 4096);
+ body_part = header_part = last_part = NULL;
+
+ if (iter_all) {
+ t_array_init(&headers, 64);
+ hdr_content = t_str_new(512);
+ mparser_set.hdr_flags |= MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE;
+ } else {
+ i_zero(&headers);
+ }
+
+ /* Initialize body decoder */
+ decoder = message_decoder_init(NULL, 0);
+
+ // FIXME: currently not tested with edit-mail.
+ //parser = message_parser_init_from_parts(parts, input,
+ // hparser_flags, mparser_flags);
+ parser = message_parser_init(pool_datastack_create(),
+ input, &mparser_set);
+ while ( message_parser_parse_next_block(parser, &block) > 0 ) {
+ struct sieve_message_part **body_part_idx;
+ struct message_header_line *hdr = block.hdr;
+ struct sieve_message_header *header;
+ unsigned char *data;
+
+ if ( block.part != prev_mpart ) {
+ bool message_rfc822 = FALSE;
+
+ /* Save previous body part */
+ if ( body_part != NULL ) {
+ /* Treat message/rfc822 separately; headers become content */
+ if ( block.part->parent == prev_mpart &&
+ strcmp(body_part->content_type, "message/rfc822") == 0 ) {
+ message_rfc822 = TRUE;
+ } else {
+ if ( save_body ) {
+ sieve_message_part_save
+ (renv, buf, body_part, extract_text);
+ }
+ }
+ if ( iter_all && !array_is_created(&body_part->headers) &&
+ array_count(&headers) > 0 ) {
+ p_array_init(&body_part->headers, pool, array_count(&headers));
+ array_copy(&body_part->headers.arr, 0,
+ &headers.arr, 0, array_count(&headers));
+ }
+ }
+
+ /* Start processing next part */
+ body_part_idx = array_idx_get_space
+ (&msgctx->cached_body_parts, idx);
+ if ( *body_part_idx == NULL )
+ *body_part_idx = p_new(pool, struct sieve_message_part, 1);
+ body_part = *body_part_idx;
+ body_part->content_type = "text/plain";
+ if ( iter_all )
+ array_clear(&headers);
+
+ /* Copy tree structure */
+ if ( block.part->context != NULL ) {
+ struct sieve_message_part *epipart =
+ (struct sieve_message_part *)block.part->context;
+ i_assert(epipart != NULL);
+
+ /* multipart epilogue */
+ body_part->content_type = epipart->content_type;
+ body_part->have_body = TRUE;
+ body_part->epilogue = TRUE;
+ save_body = iter_all || _is_wanted_content_type
+ (content_types, body_part->content_type);
+
+ } else {
+ struct sieve_message_part *parent = NULL;
+
+ if ( block.part->parent != NULL ) {
+ body_part->parent = parent =
+ (struct sieve_message_part *)
+ block.part->parent->context;
+ }
+
+ /* new part */
+ block.part->context = (void*)body_part;
+
+ if ( last_part != NULL ) {
+ i_assert( parent != NULL );
+ if ( last_part->parent == parent ) {
+ last_part->next = body_part;
+ } else if (parent->children == NULL) {
+ parent->children = body_part;
+ } else {
+ struct sieve_message_part *child = parent->children;
+ while (child->next != NULL && child != body_part)
+ child = child->next;
+ if (child != body_part)
+ child->next = body_part;
+ }
+ }
+ }
+ last_part = body_part;
+
+ /* If this is message/rfc822 content, retain the enveloping part for
+ * storing headers as content.
+ */
+ if ( message_rfc822 ) {
+ i_assert(idx > 0);
+ body_part_idx = array_idx_modifiable
+ (&msgctx->cached_body_parts, idx-1);
+ header_part = *body_part_idx;
+ } else {
+ header_part = NULL;
+ }
+
+ prev_mpart = block.part;
+ idx++;
+ }
+
+ if ( hdr != NULL || block.size == 0 ) {
+ enum {
+ _HDR_CONTENT_TYPE,
+ _HDR_CONTENT_DISPOSITION,
+ _HDR_OTHER
+ } hdr_field;
+
+ /* Reading headers */
+ i_assert( body_part != NULL );
+
+ /* Decode block */
+ (void)message_decoder_decode_next_block
+ (decoder, &block, &decoded);
+
+ /* Check for end of headers */
+ if ( hdr == NULL ) {
+ /* Save headers for message/rfc822 part */
+ if ( header_part != NULL ) {
+ sieve_message_part_save
+ (renv, buf, header_part, FALSE);
+ header_part = NULL;
+ }
+
+ /* Save bodies only if we have a wanted content-type */
+ save_body = iter_all || _is_wanted_content_type
+ (content_types, body_part->content_type);
+ continue;
+ }
+
+ /* Encountered the empty line that indicates the end of the headers and
+ * the start of the body
+ */
+ if ( hdr->eoh ) {
+ body_part->have_body = TRUE;
+ continue;
+ } else if ( header_part != NULL ) {
+ /* Save message/rfc822 header as part content */
+ if ( hdr->continued ) {
+ buffer_append(buf, hdr->value, hdr->value_len);
+ } else {
+ buffer_append(buf, hdr->name, hdr->name_len);
+ buffer_append(buf, hdr->middle, hdr->middle_len);
+ buffer_append(buf, hdr->value, hdr->value_len);
+ }
+ if ( !hdr->no_newline ) {
+ buffer_append(buf, "\r\n", 2);
+ }
+ }
+
+ if ( strcasecmp(hdr->name, "Content-Type" ) == 0 )
+ hdr_field = _HDR_CONTENT_TYPE;
+ else if ( strcasecmp(hdr->name, "Content-Disposition" ) == 0 )
+ hdr_field = _HDR_CONTENT_DISPOSITION;
+ else if ( iter_all && !array_is_created(&body_part->headers) )
+ hdr_field = _HDR_OTHER;
+ else {
+ /* Not interested in this header */
+ continue;
+ }
+
+ /* Header can have folding whitespace. Acquire the full value before
+ * continuing
+ */
+ if ( hdr->continues ) {
+ hdr->use_full_value = TRUE;
+ continue;
+ }
+
+ if ( iter_all && !array_is_created(&body_part->headers) ) {
+ const unsigned char *value, *vp;
+ size_t vlen;
+
+ /* Add header */
+ header = array_append_space(&headers);
+ header->name = p_strdup(pool, hdr->name);
+
+ /* Trim end of field value (not done by parser) */
+ value = hdr->full_value;
+ vp = value + hdr->full_value_len;
+ while ( vp > value &&
+ (vp[-1] == '\t' || vp[-1] == ' ') )
+ vp--;
+ vlen = (size_t)(vp - value);
+
+ /* Decode MIME encoded-words. */
+ str_truncate(hdr_content, 0);
+ message_header_decode_utf8
+ (value, vlen, hdr_content, NULL);
+ if ( vlen != str_len(hdr_content) ||
+ strncmp(str_c(hdr_content), (const char *)value,
+ vlen) != 0 ) {
+ if ( strlen(str_c(hdr_content)) != str_len(hdr_content) ) {
+ /* replace NULs with spaces */
+ str_replace_nuls(hdr_content);
+ }
+ /* store raw */
+ data = p_malloc(pool, vlen + 1);
+ data[vlen] = '\0';
+ header->value = memcpy(data, value, vlen);
+ header->value_len = vlen;
+ /* store decoded */
+ data = p_malloc(pool, str_len(hdr_content) + 1);
+ data[str_len(hdr_content)] = '\0';
+ header->utf8_value = memcpy(data,
+ str_data(hdr_content), str_len(hdr_content));
+ header->utf8_value_len = str_len(hdr_content);
+ } else {
+ /* raw == decoded */
+ data = p_malloc(pool, vlen + 1);
+ data[vlen] = '\0';
+ header->value = header->utf8_value =
+ memcpy(data, value, vlen);
+ header->value_len = header->utf8_value_len = vlen;
+ }
+
+ if ( hdr_field == _HDR_OTHER )
+ continue;
+ }
+
+ /* Parse the content type from the Content-type header */
+ T_BEGIN {
+ switch ( hdr_field ) {
+ case _HDR_CONTENT_TYPE:
+ body_part->content_type =
+ p_strdup(pool, _parse_content_type(block.hdr));
+ break;
+ case _HDR_CONTENT_DISPOSITION:
+ body_part->content_disposition =
+ p_strdup(pool, _parse_content_disposition(block.hdr));
+ break;
+ default:
+ i_unreached();
+ }
+ } T_END;
+
+ continue;
+ }
+
+ /* Reading body */
+ if ( save_body ) {
+ (void)message_decoder_decode_next_block
+ (decoder, &block, &decoded);
+ buffer_append(buf, decoded.data, decoded.size);
+ }
+ }
+
+ /* even with an empty message there was at least the "end of headers"
+ block, which set the body_part. */
+ i_assert( body_part != NULL );
+
+ /* Save last body part if necessary */
+ if ( header_part != NULL ) {
+ sieve_message_part_save
+ (renv, buf, header_part, FALSE);
+ } else if ( save_body ) {
+ sieve_message_part_save
+ (renv, buf, body_part, extract_text);
+ }
+ if ( iter_all && !array_is_created(&body_part->headers) &&
+ array_count(&headers) > 0 ) {
+ p_array_init(&body_part->headers, pool, array_count(&headers));
+ array_copy(&body_part->headers.arr, 0,
+ &headers.arr, 0, array_count(&headers));
+ }
+
+ /* Try to fill the return_body_parts array once more */
+ have_all = iter_all || sieve_message_body_get_return_parts
+ (renv, content_types, extract_text);
+
+ /* This time, failure is a bug */
+ i_assert(have_all);
+
+ /* Cleanup */
+ (void)message_parser_deinit(&parser, &mparts);
+ message_decoder_deinit(&decoder);
+ buffer_free(&buf);
+
+ /* Return status */
+ if ( input->stream_errno != 0 ) {
+ sieve_runtime_critical(renv, NULL,
+ "failed to read input message",
+ "read(%s) failed: %s",
+ i_stream_get_name(input),
+ i_stream_get_error(input));
+ return SIEVE_EXEC_TEMP_FAILURE;
+ }
+ return SIEVE_EXEC_OK;
+}
+
+int sieve_message_body_get_content
+(const struct sieve_runtime_env *renv,
+ const char * const *content_types,
+ struct sieve_message_part_data **parts_r)
+{
+ struct sieve_message_context *msgctx = renv->msgctx;
+ int status;
+
+ T_BEGIN {
+ /* Fill the return_body_parts array */
+ status = sieve_message_parts_add_missing
+ (renv, content_types, FALSE, FALSE);
+ } T_END;
+
+ /* Check status */
+ if ( status <= 0 )
+ return status;
+
+ /* Return the array of body items */
+ (void) array_append_space(&msgctx->return_body_parts); /* NULL-terminate */
+ *parts_r = array_idx_modifiable(&msgctx->return_body_parts, 0);
+
+ return status;
+}
+
+int sieve_message_body_get_text
+(const struct sieve_runtime_env *renv,
+ struct sieve_message_part_data **parts_r)
+{
+ static const char * const _text_content_types[] =
+ { "application/xhtml+xml", "text", NULL };
+ struct sieve_message_context *msgctx = renv->msgctx;
+ int status;
+
+ /* We currently only support extracting plain text from:
+
+ - text/html -> HTML
+ - application/xhtml+xml -> XHTML
+
+ Other text types are read as is. Any non-text types are skipped.
+ */
+
+ T_BEGIN {
+ /* Fill the return_body_parts array */
+ status = sieve_message_parts_add_missing
+ (renv, _text_content_types, TRUE, FALSE);
+ } T_END;
+
+ /* Check status */
+ if ( status <= 0 )
+ return status;
+
+ /* Return the array of body items */
+ (void) array_append_space(&msgctx->return_body_parts); /* NULL-terminate */
+ *parts_r = array_idx_modifiable(&msgctx->return_body_parts, 0);
+
+ return status;
+}
+
+int sieve_message_body_get_raw
+(const struct sieve_runtime_env *renv,
+ struct sieve_message_part_data **parts_r)
+{
+ struct sieve_message_context *msgctx = renv->msgctx;
+ struct sieve_message_part_data *return_part;
+ buffer_t *buf;
+
+ if ( msgctx->raw_body == NULL ) {
+ struct mail *mail = sieve_message_get_mail(renv->msgctx);
+ struct istream *input;
+ struct message_size hdr_size, body_size;
+ const unsigned char *data;
+ size_t size;
+ int ret;
+
+ msgctx->raw_body = buf = buffer_create_dynamic
+ (msgctx->context_pool, 1024*64);
+
+ /* Get stream for message */
+ if ( mail_get_stream(mail, &hdr_size, &body_size, &input) < 0 ) {
+ return sieve_runtime_mail_error(renv, mail,
+ "failed to open input message");
+ }
+
+ /* Skip stream to beginning of body */
+ i_stream_skip(input, hdr_size.physical_size);
+
+ /* Read raw message body */
+ while ( (ret=i_stream_read_more(input, &data, &size)) > 0 ) {
+ buffer_append(buf, data, size);
+
+ i_stream_skip(input, size);
+ }
+
+ if ( ret < 0 && input->stream_errno != 0 ) {
+ sieve_runtime_critical(renv, NULL,
+ "failed to read input message",
+ "read(%s) failed: %s",
+ i_stream_get_name(input),
+ i_stream_get_error(input));
+ return SIEVE_EXEC_TEMP_FAILURE;
+ }
+
+ /* Add terminating NUL to the body part buffer */
+ buffer_append_c(buf, '\0');
+
+ } else {
+ buf = msgctx->raw_body;
+ }
+
+ /* Clear result array */
+ array_clear(&msgctx->return_body_parts);
+
+ if ( buf->used > 1 ) {
+ const char *data = (const char *)buf->data;
+ size_t size = buf->used - 1;
+
+ i_assert( data[size] == '\0' );
+
+ /* Add single item to the result */
+ return_part = array_append_space(&msgctx->return_body_parts);
+ return_part->content = data;
+ return_part->size = size;
+ }
+
+ /* Return the array of body items */
+ (void) array_append_space(&msgctx->return_body_parts); /* NULL-terminate */
+ *parts_r = array_idx_modifiable(&msgctx->return_body_parts, 0);
+
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Message part iterator
+ */
+
+int sieve_message_part_iter_init
+(struct sieve_message_part_iter *iter,
+ const struct sieve_runtime_env *renv)
+{
+ struct sieve_message_context *msgctx = renv->msgctx;
+ struct sieve_message_part *const *parts;
+ unsigned int count;
+ int status;
+
+ T_BEGIN {
+ /* Fill the return_body_parts array */
+ status = sieve_message_parts_add_missing
+ (renv, NULL, TRUE, TRUE);
+ } T_END;
+
+ /* Check status */
+ if ( status <= 0 )
+ return status;
+
+ i_zero(iter);
+ iter->renv = renv;
+ iter->index = 0;
+ iter->offset = 0;
+
+ parts = array_get(&msgctx->cached_body_parts, &count);
+ if (count == 0)
+ iter->root = NULL;
+ else
+ iter->root = parts[0];
+
+ return SIEVE_EXEC_OK;
+}
+
+void sieve_message_part_iter_subtree(struct sieve_message_part_iter *iter,
+ struct sieve_message_part_iter *subtree)
+{
+ const struct sieve_runtime_env *renv = iter->renv;
+ struct sieve_message_context *msgctx = renv->msgctx;
+ struct sieve_message_part *const *parts;
+ unsigned int count;
+
+ *subtree = *iter;
+
+ parts = array_get(&msgctx->cached_body_parts, &count);
+ if ( subtree->index >= count)
+ subtree->root = NULL;
+ else
+ subtree->root = parts[subtree->index];
+ subtree->offset = subtree->index;
+}
+
+void sieve_message_part_iter_children(struct sieve_message_part_iter *iter,
+ struct sieve_message_part_iter *child)
+{
+ const struct sieve_runtime_env *renv = iter->renv;
+ struct sieve_message_context *msgctx = renv->msgctx;
+ struct sieve_message_part *const *parts;
+ unsigned int count;
+
+ *child = *iter;
+
+ parts = array_get(&msgctx->cached_body_parts, &count);
+ if ( (child->index+1) >= count || parts[child->index]->children == NULL)
+ child->root = NULL;
+ else
+ child->root = parts[child->index++];
+ child->offset = child->index;
+}
+
+struct sieve_message_part *sieve_message_part_iter_current
+(struct sieve_message_part_iter *iter)
+{
+ const struct sieve_runtime_env *renv = iter->renv;
+ struct sieve_message_context *msgctx = renv->msgctx;
+ struct sieve_message_part *const *parts;
+ unsigned int count;
+
+ if ( iter->root == NULL )
+ return NULL;
+
+ parts = array_get(&msgctx->cached_body_parts, &count);
+ if ( iter->index >= count )
+ return NULL;
+ do {
+ if ( parts[iter->index] == iter->root->next )
+ return NULL;
+ if ( parts[iter->index] == iter->root->parent )
+ return NULL;
+ } while ( parts[iter->index]->epilogue && ++iter->index < count );
+ if ( iter->index >= count )
+ return NULL;
+ return parts[iter->index];
+}
+
+struct sieve_message_part *sieve_message_part_iter_next
+(struct sieve_message_part_iter *iter)
+{
+ const struct sieve_runtime_env *renv = iter->renv;
+ struct sieve_message_context *msgctx = renv->msgctx;
+
+ if ( iter->index >= array_count(&msgctx->cached_body_parts) )
+ return NULL;
+ iter->index++;
+
+ return sieve_message_part_iter_current(iter);
+}
+
+void sieve_message_part_iter_reset
+(struct sieve_message_part_iter *iter)
+{
+ iter->index = iter->offset;
+}
+
+/*
+ * MIME header list
+ */
+
+/* Forward declarations */
+
+static int sieve_mime_header_list_next_item
+ (struct sieve_header_list *_hdrlist, const char **name_r,
+ string_t **value_r);
+static int sieve_mime_header_list_next_value
+ (struct sieve_stringlist *_strlist, string_t **value_r);
+static void sieve_mime_header_list_reset
+ (struct sieve_stringlist *_strlist);
+
+/* Header list object */
+
+struct sieve_mime_header_list {
+ struct sieve_header_list hdrlist;
+
+ struct sieve_stringlist *field_names;
+
+ struct sieve_message_part_iter part_iter;
+
+ const char *header_name;
+ const struct sieve_message_header *headers;
+ unsigned int headers_index, headers_count;
+
+ bool mime_decode:1;
+ bool children:1;
+};
+
+struct sieve_header_list *sieve_mime_header_list_create
+(const struct sieve_runtime_env *renv,
+ struct sieve_stringlist *field_names,
+ struct sieve_message_part_iter *part_iter,
+ bool mime_decode, bool children)
+{
+ struct sieve_mime_header_list *hdrlist;
+
+ hdrlist = t_new(struct sieve_mime_header_list, 1);
+ hdrlist->hdrlist.strlist.runenv = renv;
+ hdrlist->hdrlist.strlist.exec_status = SIEVE_EXEC_OK;
+ hdrlist->hdrlist.strlist.next_item = sieve_mime_header_list_next_value;
+ hdrlist->hdrlist.strlist.reset = sieve_mime_header_list_reset;
+ hdrlist->hdrlist.next_item = sieve_mime_header_list_next_item;
+ hdrlist->field_names = field_names;
+ hdrlist->mime_decode = mime_decode;
+ hdrlist->children = children;
+
+ sieve_message_part_iter_subtree(part_iter, &hdrlist->part_iter);
+
+ return &hdrlist->hdrlist;
+}
+
+/* MIME list implementation */
+
+static void sieve_mime_header_list_next_name
+(struct sieve_mime_header_list *hdrlist)
+{
+ struct sieve_message_part *mpart;
+
+ sieve_message_part_iter_reset(&hdrlist->part_iter);
+ mpart = sieve_message_part_iter_current(&hdrlist->part_iter);
+
+ if ( mpart != NULL && array_is_created(&mpart->headers) ) {
+ hdrlist->headers = array_get
+ (&mpart->headers, &hdrlist->headers_count);
+ hdrlist->headers_index = 0;
+ }
+}
+
+static int sieve_mime_header_list_next_item
+(struct sieve_header_list *_hdrlist, const char **name_r,
+ string_t **value_r)
+{
+ struct sieve_mime_header_list *hdrlist =
+ (struct sieve_mime_header_list *) _hdrlist;
+ const struct sieve_runtime_env *renv = _hdrlist->strlist.runenv;
+
+ if ( name_r != NULL )
+ *name_r = NULL;
+ *value_r = NULL;
+
+ for (;;) {
+ /* Check for end of current header list */
+ if ( hdrlist->headers_count == 0 ||
+ hdrlist->headers_index >= hdrlist->headers_count ) {
+ hdrlist->headers_count = 0;
+ hdrlist->headers_index = 0;
+ hdrlist->headers = NULL;
+ }
+
+ /* Fetch more headers */
+ while ( hdrlist->headers_count == 0 ) {
+ string_t *hdr_item = NULL;
+ int ret;
+
+ if ( hdrlist->header_name != NULL && hdrlist->children ) {
+ struct sieve_message_part *mpart;
+
+ mpart = sieve_message_part_iter_next(&hdrlist->part_iter);
+ if ( mpart != NULL && array_is_created(&mpart->headers) ) {
+ hdrlist->headers = array_get
+ (&mpart->headers, &hdrlist->headers_count);
+ hdrlist->headers_index = 0;
+ }
+ if ( hdrlist->headers_count > 0 ) {
+ if ( _hdrlist->strlist.trace ) {
+ sieve_runtime_trace(renv, 0,
+ "moving to next message part");
+ }
+ break;
+ }
+ }
+
+ /* Read next header name from source list */
+ if ( (ret=sieve_stringlist_next_item
+ (hdrlist->field_names, &hdr_item)) <= 0 )
+ return ret;
+
+ hdrlist->header_name = str_c(hdr_item);
+
+ if ( _hdrlist->strlist.trace ) {
+ sieve_runtime_trace(renv, 0,
+ "extracting `%s' headers from message part",
+ str_sanitize(str_c(hdr_item), 80));
+ }
+
+ sieve_mime_header_list_next_name(hdrlist);
+ }
+
+ for ( ; hdrlist->headers_index < hdrlist->headers_count;
+ hdrlist->headers_index++ ) {
+ const struct sieve_message_header *header =
+ &hdrlist->headers[hdrlist->headers_index];
+
+ if ( strcasecmp(header->name, hdrlist->header_name) == 0 ) {
+ if ( name_r != NULL )
+ *name_r = hdrlist->header_name;
+ if ( hdrlist->mime_decode ) {
+ *value_r = t_str_new_const
+ ((const char *)header->utf8_value, header->utf8_value_len);
+ } else {
+ *value_r = t_str_new_const
+ ((const char *)header->value, header->value_len);
+ }
+ hdrlist->headers_index++;
+ return 1;
+ }
+ }
+ }
+
+ i_unreached();
+ return -1;
+}
+
+static int sieve_mime_header_list_next_value
+(struct sieve_stringlist *_strlist, string_t **value_r)
+{
+ struct sieve_header_list *hdrlist =
+ (struct sieve_header_list *) _strlist;
+
+ return sieve_mime_header_list_next_item
+ (hdrlist, NULL, value_r);
+}
+
+static void sieve_mime_header_list_reset
+(struct sieve_stringlist *strlist)
+{
+ struct sieve_mime_header_list *hdrlist =
+ (struct sieve_mime_header_list *) strlist;
+
+ sieve_stringlist_reset(hdrlist->field_names);
+ hdrlist->header_name = NULL;
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-message.h b/pigeonhole/src/lib-sieve/sieve-message.h
new file mode 100644
index 0000000..4cb77cc
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-message.h
@@ -0,0 +1,280 @@
+#ifndef SIEVE_MESSAGE_H
+#define SIEVE_MESSAGE_H
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+#include "sieve-objects.h"
+
+/*
+ * Message transmission
+ */
+
+const char *sieve_message_get_new_id(const struct sieve_instance *svinst);
+
+/*
+ * Message context
+ */
+
+struct sieve_message_context;
+
+struct sieve_message_context *sieve_message_context_create
+ (struct sieve_instance *svinst, struct mail_user *mail_user,
+ const struct sieve_message_data *msgdata);
+void sieve_message_context_ref(struct sieve_message_context *msgctx);
+void sieve_message_context_unref(struct sieve_message_context **msgctx);
+
+void sieve_message_context_reset(struct sieve_message_context *msgctx);
+
+pool_t sieve_message_context_pool
+ (struct sieve_message_context *msgctx) ATTR_PURE;
+void sieve_message_context_time(struct sieve_message_context *msgctx,
+ struct timeval *time);
+
+/* Extension support */
+
+void sieve_message_context_extension_set
+ (struct sieve_message_context *msgctx, const struct sieve_extension *ext,
+ void *context);
+const void *sieve_message_context_extension_get
+ (struct sieve_message_context *msgctx, const struct sieve_extension *ext);
+
+/* Envelope */
+
+const struct smtp_address *sieve_message_get_final_recipient
+ (struct sieve_message_context *msgctx);
+const struct smtp_address *sieve_message_get_orig_recipient
+ (struct sieve_message_context *msgctx);
+
+const struct smtp_address *sieve_message_get_sender
+ (struct sieve_message_context *msgctx);
+
+/* Mail */
+
+struct mail *sieve_message_get_mail
+ (struct sieve_message_context *msgctx);
+
+int sieve_message_substitute
+ (struct sieve_message_context *msgctx, struct istream *input);
+struct edit_mail *sieve_message_edit
+ (struct sieve_message_context *msgctx);
+void sieve_message_snapshot
+ (struct sieve_message_context *msgctx);
+
+/*
+ * Header stringlist
+ */
+
+struct sieve_header_list {
+ struct sieve_stringlist strlist;
+
+ int (*next_item)
+ (struct sieve_header_list *_hdrlist, const char **name_r,
+ string_t **value_r) ATTR_NULL(2);
+};
+
+static inline int sieve_header_list_next_item
+(struct sieve_header_list *hdrlist, const char **name_r,
+ string_t **value_r) ATTR_NULL(2)
+{
+ return hdrlist->next_item(hdrlist, name_r, value_r);
+}
+
+static inline void sieve_header_list_reset
+(struct sieve_header_list *hdrlist)
+{
+ sieve_stringlist_reset(&hdrlist->strlist);
+}
+
+static inline int sieve_header_list_get_length
+(struct sieve_header_list *hdrlist)
+{
+ return sieve_stringlist_get_length(&hdrlist->strlist);
+}
+
+static inline void sieve_header_list_set_trace
+(struct sieve_header_list *hdrlist, bool trace)
+{
+ sieve_stringlist_set_trace(&hdrlist->strlist, trace);
+}
+
+struct sieve_header_list *sieve_message_header_list_create
+ (const struct sieve_runtime_env *renv,
+ struct sieve_stringlist *field_names,
+ bool mime_decode);
+
+/*
+ * Message override
+ */
+
+/* Header override object */
+
+struct sieve_message_override_def {
+ struct sieve_object_def obj_def;
+
+ unsigned int sequence;
+
+ /* Context coding */
+
+ bool (*dump_context)
+ (const struct sieve_message_override *svmo,
+ const struct sieve_dumptime_env *denv, sieve_size_t *address);
+ int (*read_context)
+ (const struct sieve_message_override *svmo,
+ const struct sieve_runtime_env *renv, sieve_size_t *address,
+ void **se_context);
+
+ /* Override */
+
+ int (*header_override)
+ (const struct sieve_message_override *svmo,
+ const struct sieve_runtime_env *renv,
+ bool mime_decode, struct sieve_stringlist **headers);
+};
+
+struct sieve_message_override {
+ struct sieve_object object;
+
+ const struct sieve_message_override_def *def;
+
+ void *context;
+};
+
+ARRAY_DEFINE_TYPE(sieve_message_override,
+ struct sieve_message_override);
+
+/*
+ * Message override operand
+ */
+
+#define SIEVE_EXT_DEFINE_MESSAGE_OVERRIDE(SVMO) SIEVE_EXT_DEFINE_OBJECT(SVMO)
+#define SIEVE_EXT_DEFINE_MESSAGE_OVERRIDES(SVMOS) SIEVE_EXT_DEFINE_OBJECTS(SMOS)
+
+#define SIEVE_OPT_MESSAGE_OVERRIDE (-2)
+
+extern const struct sieve_operand_class
+ sieve_message_override_operand_class;
+
+static inline void sieve_opr_message_override_emit
+(struct sieve_binary_block *sblock, const struct sieve_extension *ext,
+ const struct sieve_message_override_def *seff)
+{
+ sieve_opr_object_emit(sblock, ext, &seff->obj_def);
+}
+
+bool sieve_opr_message_override_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+int sieve_opr_message_override_read
+ (const struct sieve_runtime_env *renv, sieve_size_t *address,
+ struct sieve_message_override *svmo);
+
+/*
+ * Optional operands
+ */
+
+int sieve_message_opr_optional_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address,
+ signed int *opt_code);
+
+int sieve_message_opr_optional_read
+ (const struct sieve_runtime_env *renv, sieve_size_t *address,
+ signed int *opt_code, int *exec_status,
+ struct sieve_address_part *addrp, struct sieve_match_type *mcht,
+ struct sieve_comparator *cmp,
+ ARRAY_TYPE(sieve_message_override) *svmos);
+
+/*
+ * Message header
+ */
+
+int sieve_message_get_header_fields
+ (const struct sieve_runtime_env *renv,
+ struct sieve_stringlist *field_names,
+ ARRAY_TYPE(sieve_message_override) *svmos,
+ bool mime_decode, struct sieve_stringlist **fields_r);
+
+/*
+ * Message part
+ */
+
+struct sieve_message_part;
+
+struct sieve_message_part_data {
+ const char *content_type;
+ const char *content_disposition;
+
+ const char *content;
+ unsigned long size;
+};
+
+struct sieve_message_part *sieve_message_part_parent
+ (struct sieve_message_part *mpart) ATTR_PURE;
+struct sieve_message_part *sieve_message_part_next
+ (struct sieve_message_part *mpart) ATTR_PURE;
+struct sieve_message_part *sieve_message_part_children
+ (struct sieve_message_part *mpart) ATTR_PURE;
+
+const char *sieve_message_part_content_type
+ (struct sieve_message_part *mpart) ATTR_PURE;
+const char *sieve_message_part_content_disposition
+ (struct sieve_message_part *mpart) ATTR_PURE;
+
+int sieve_message_part_get_first_header
+ (struct sieve_message_part *mpart, const char *field,
+ const char **value_r);
+
+void sieve_message_part_get_data
+ (struct sieve_message_part *mpart,
+ struct sieve_message_part_data *data, bool text);
+
+/*
+ * Message body
+ */
+
+int sieve_message_body_get_content
+ (const struct sieve_runtime_env *renv,
+ const char * const *content_types,
+ struct sieve_message_part_data **parts_r);
+int sieve_message_body_get_text
+ (const struct sieve_runtime_env *renv,
+ struct sieve_message_part_data **parts_r);
+int sieve_message_body_get_raw
+ (const struct sieve_runtime_env *renv,
+ struct sieve_message_part_data **parts_r);
+
+/*
+ * Message part iterator
+ */
+
+struct sieve_message_part_iter {
+ const struct sieve_runtime_env *renv;
+ struct sieve_message_part *root;
+ unsigned int index, offset;
+};
+
+int sieve_message_part_iter_init
+(struct sieve_message_part_iter *iter,
+ const struct sieve_runtime_env *renv);
+void sieve_message_part_iter_subtree(struct sieve_message_part_iter *iter,
+ struct sieve_message_part_iter *subtree);
+void sieve_message_part_iter_children(struct sieve_message_part_iter *iter,
+ struct sieve_message_part_iter *child);
+
+struct sieve_message_part *sieve_message_part_iter_current
+(struct sieve_message_part_iter *iter);
+struct sieve_message_part *sieve_message_part_iter_next
+(struct sieve_message_part_iter *iter);
+
+void sieve_message_part_iter_reset
+(struct sieve_message_part_iter *iter);
+
+/*
+ * MIME header list
+ */
+
+struct sieve_header_list *sieve_mime_header_list_create
+(const struct sieve_runtime_env *renv,
+ struct sieve_stringlist *field_names,
+ struct sieve_message_part_iter *part_iter,
+ bool mime_decode, bool children);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-objects.c b/pigeonhole/src/lib-sieve/sieve-objects.c
new file mode 100644
index 0000000..66fc969
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-objects.c
@@ -0,0 +1,111 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+#include "sieve-interpreter.h"
+
+#include "sieve-objects.h"
+
+/*
+ * Object coding
+ */
+
+void sieve_opr_object_emit
+(struct sieve_binary_block *sblock, const struct sieve_extension *ext,
+ const struct sieve_object_def *obj_def)
+{
+ struct sieve_extension_objects *objs =
+ (struct sieve_extension_objects *) obj_def->operand->interface;
+
+ (void) sieve_operand_emit(sblock, ext, obj_def->operand);
+
+ if ( objs->count > 1 ) {
+ (void) sieve_binary_emit_byte(sblock, obj_def->code);
+ }
+}
+
+bool sieve_opr_object_read_data
+(struct sieve_binary_block *sblock, const struct sieve_operand *operand,
+ const struct sieve_operand_class *opclass, sieve_size_t *address,
+ struct sieve_object *obj)
+{
+ const struct sieve_extension_objects *objs;
+ unsigned int obj_code;
+
+ if ( operand == NULL || operand->def->class != opclass )
+ return FALSE;
+
+ objs = (struct sieve_extension_objects *) operand->def->interface;
+ if ( objs == NULL )
+ return FALSE;
+
+ if ( objs->count > 1 ) {
+ if ( !sieve_binary_read_byte(sblock, address, &obj_code) )
+ return FALSE;
+
+ if ( obj_code < objs->count ) {
+ const struct sieve_object_def *const *objects =
+ (const struct sieve_object_def *const *) objs->objects;
+
+ obj->def = objects[obj_code];
+ obj->ext = operand->ext;
+ return TRUE;
+ }
+ }
+
+ obj->def = (const struct sieve_object_def *) objs->objects;
+ obj->ext = operand->ext;
+ return TRUE;
+}
+
+bool sieve_opr_object_read
+(const struct sieve_runtime_env *renv,
+ const struct sieve_operand_class *opclass, sieve_size_t *address,
+ struct sieve_object *obj)
+{
+ struct sieve_operand operand;
+
+ if ( !sieve_operand_read(renv->sblock, address, NULL, &operand) ) {
+ return FALSE;
+ }
+
+ return sieve_opr_object_read_data
+ (renv->sblock, &operand, opclass, address, obj);
+}
+
+bool sieve_opr_object_dump
+(const struct sieve_dumptime_env *denv,
+ const struct sieve_operand_class *opclass, sieve_size_t *address,
+ struct sieve_object *obj)
+{
+ struct sieve_operand operand;
+ struct sieve_object obj_i;
+ const char *class;
+
+ if ( obj == NULL )
+ obj = &obj_i;
+
+ sieve_code_mark(denv);
+
+ if ( !sieve_operand_read(denv->sblock, address, NULL, &operand) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_opr_object_read_data
+ (denv->sblock, &operand, opclass, address, obj) )
+ return FALSE;
+
+ if ( operand.def->class == NULL )
+ class = "OBJECT";
+ else
+ class = operand.def->class->name;
+
+ sieve_code_dumpf(denv, "%s: %s", class, obj->def->identifier);
+
+ return TRUE;
+}
+
diff --git a/pigeonhole/src/lib-sieve/sieve-objects.h b/pigeonhole/src/lib-sieve/sieve-objects.h
new file mode 100644
index 0000000..e3f300f
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-objects.h
@@ -0,0 +1,67 @@
+#ifndef SIEVE_OBJECTS_H
+#define SIEVE_OBJECTS_H
+
+/*
+ * Object definition
+ */
+
+struct sieve_object_def {
+ const char *identifier;
+ const struct sieve_operand_def *operand;
+ unsigned int code;
+};
+
+#define SIEVE_OBJECT(_identifier, _operand, _code) \
+ .obj_def = { \
+ .identifier = (_identifier), \
+ .operand = (_operand), \
+ .code = (_code) \
+ }
+
+/*
+ * Object instance
+ */
+
+struct sieve_object {
+ const struct sieve_object_def *def;
+ const struct sieve_extension *ext;
+};
+
+#define SIEVE_OBJECT_DEFAULT(_obj) \
+ { &((_obj).obj_def), NULL }
+
+#define SIEVE_OBJECT_EXTENSION(_obj) \
+ (_obj->object.ext)
+
+#define SIEVE_OBJECT_SET_DEF(_obj, def_value) \
+ STMT_START { \
+ (_obj)->def = def_value; \
+ (_obj)->object.def = &(_obj)->def->obj_def; \
+ } STMT_END
+
+
+/*
+ * Object coding
+ */
+
+void sieve_opr_object_emit
+ (struct sieve_binary_block *sblock, const struct sieve_extension *ext,
+ const struct sieve_object_def *obj_def);
+
+bool sieve_opr_object_read_data
+ (struct sieve_binary_block *sblock, const struct sieve_operand *operand,
+ const struct sieve_operand_class *opclass, sieve_size_t *address,
+ struct sieve_object *obj);
+
+bool sieve_opr_object_read
+ (const struct sieve_runtime_env *renv,
+ const struct sieve_operand_class *opclass, sieve_size_t *address,
+ struct sieve_object *obj);
+
+bool sieve_opr_object_dump
+ (const struct sieve_dumptime_env *denv,
+ const struct sieve_operand_class *opclass, sieve_size_t *address,
+ struct sieve_object *obj);
+
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-parser.c b/pigeonhole/src/lib-sieve/sieve-parser.c
new file mode 100644
index 0000000..ee54994
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-parser.c
@@ -0,0 +1,670 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "istream.h"
+#include "failures.h"
+
+#include "sieve-common.h"
+#include "sieve-limits.h"
+#include "sieve-script.h"
+#include "sieve-lexer.h"
+#include "sieve-parser.h"
+#include "sieve-error.h"
+#include "sieve-ast.h"
+
+/*
+ * Forward declarations
+ */
+
+static int
+sieve_parser_recover(struct sieve_parser *parser,
+ enum sieve_token_type end_token);
+
+/*
+ * Parser object
+ */
+
+struct sieve_parser {
+ pool_t pool;
+
+ bool valid;
+
+ struct sieve_script *script;
+
+ struct sieve_error_handler *ehandler;
+
+ const struct sieve_lexer *lexer;
+ struct sieve_ast *ast;
+};
+
+struct sieve_parser *
+sieve_parser_create(struct sieve_script *script,
+ struct sieve_error_handler *ehandler,
+ enum sieve_error *error_r)
+{
+ struct sieve_parser *parser;
+ const struct sieve_lexer *lexer;
+
+ lexer = sieve_lexer_create(script, ehandler, error_r);
+ if (lexer != NULL) {
+ pool_t pool = pool_alloconly_create("sieve_parser", 4096);
+
+ parser = p_new(pool, struct sieve_parser, 1);
+ parser->pool = pool;
+ parser->valid = TRUE;
+
+ parser->ehandler = ehandler;
+ sieve_error_handler_ref(ehandler);
+
+ parser->script = script;
+ sieve_script_ref(script);
+
+ parser->lexer = lexer;
+ parser->ast = NULL;
+
+ return parser;
+ }
+
+ return NULL;
+}
+
+void sieve_parser_free(struct sieve_parser **parser)
+{
+ if ((*parser)->ast != NULL)
+ sieve_ast_unref(&(*parser)->ast);
+
+ sieve_lexer_free(&(*parser)->lexer);
+ sieve_script_unref(&(*parser)->script);
+
+ sieve_error_handler_unref(&(*parser)->ehandler);
+
+ pool_unref(&(*parser)->pool);
+
+ *parser = NULL;
+}
+
+/*
+ * Internal error handling
+ */
+
+inline static void ATTR_FORMAT(4, 5)
+sieve_parser_error(struct sieve_parser *parser,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_ERROR,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ va_start(args, fmt);
+
+ /* Don't report a parse error if the lexer complained already */
+ if (sieve_lexer_token_type(parser->lexer) != STT_ERROR) {
+ T_BEGIN {
+ params.location = sieve_error_script_location(
+ parser->script,
+ sieve_lexer_token_line(parser->lexer));
+ sieve_logv(parser->ehandler, &params, fmt, args);
+ } T_END;
+ }
+
+ parser->valid = FALSE;
+
+ va_end(args);
+}
+#define sieve_parser_error(parser, ...) \
+ sieve_parser_error(parser, __FILE__, __LINE__, __VA_ARGS__)
+
+/*
+ * Sieve grammar parsing
+ */
+
+/* sieve_parse_arguments():
+
+ Parses both command arguments and sub-tests:
+ arguments = *argument [test / test-list]
+ argument = string-list / number / tag
+ string = quoted-string / multi-line [[implicitly handled in lexer]]
+ string-list = "[" string *("," string) "]" / string ;; if
+ there is only a single string, the brackets are optional
+ test-list = "(" test *("," test) ")"
+ test = identifier arguments
+ */
+static int
+sieve_parse_arguments(struct sieve_parser *parser, struct sieve_ast_node *node,
+ unsigned int depth)
+{
+ const struct sieve_lexer *lexer = parser->lexer;
+ struct sieve_ast_node *test = NULL;
+ bool test_present = TRUE;
+ bool arg_present = TRUE;
+ int result = 1; /* Indicates whether the parser is in a defined, not
+ necessarily error-free state */
+
+ /* Parse arguments */
+ while (arg_present && result > 0) {
+ struct sieve_ast_argument *arg;
+
+ if (!parser->valid &&
+ !sieve_errors_more_allowed(parser->ehandler)) {
+ result = 0;
+ break;
+ }
+
+ switch (sieve_lexer_token_type(lexer)) {
+ /* String list */
+ case STT_LSQUARE:
+ /* Create stinglist object */
+ arg = sieve_ast_argument_stringlist_create(
+ node, sieve_lexer_token_line(parser->lexer));
+ if (arg == NULL) break;
+ sieve_lexer_skip_token(lexer);
+
+ if (sieve_lexer_token_type(lexer) == STT_STRING) {
+ bool add_failed = FALSE;
+
+ /* Add the string to the list */
+ if (!sieve_ast_stringlist_add(
+ arg, sieve_lexer_token_str(lexer),
+ sieve_lexer_token_line(parser->lexer)))
+ add_failed = TRUE;
+ sieve_lexer_skip_token(lexer);
+
+ while (!add_failed &&
+ sieve_lexer_token_type(lexer) == STT_COMMA) {
+ sieve_lexer_skip_token(lexer);
+
+ /* Check parser status */
+ if (!parser->valid &&
+ !sieve_errors_more_allowed(parser->ehandler)) {
+ result = sieve_parser_recover(parser, STT_RSQUARE);
+ break;
+ }
+
+ if (sieve_lexer_token_type(lexer) == STT_STRING) {
+ /* Add the string to the list */
+ if (!sieve_ast_stringlist_add(
+ arg, sieve_lexer_token_str(lexer),
+ sieve_lexer_token_line(parser->lexer)))
+ add_failed = TRUE;
+
+ sieve_lexer_skip_token(lexer);
+ } else {
+ sieve_parser_error(parser,
+ "expecting string after ',' in string list, "
+ "but found %s",
+ sieve_lexer_token_description(lexer));
+ result = sieve_parser_recover(parser, STT_RSQUARE);
+ break;
+ }
+ }
+
+ if (add_failed) {
+ sieve_parser_error(parser,
+ "failed to accept more items in string list");
+ return -1;
+ }
+ } else {
+ sieve_parser_error(parser,
+ "expecting string after '[' in string list, "
+ "but found %s",
+ sieve_lexer_token_description(lexer));
+ result = sieve_parser_recover(parser, STT_RSQUARE);
+ }
+
+ /* Finish the string list */
+ if (sieve_lexer_token_type(lexer) == STT_RSQUARE) {
+ sieve_lexer_skip_token(lexer);
+ } else {
+ sieve_parser_error(parser,
+ "expecting ',' or end of string list ']', "
+ "but found %s",
+ sieve_lexer_token_description(lexer));
+
+ if ((result = sieve_parser_recover(parser, STT_RSQUARE)) > 0)
+ sieve_lexer_skip_token(lexer);
+ }
+ break;
+ /* Single string */
+ case STT_STRING:
+ arg = sieve_ast_argument_string_create(
+ node, sieve_lexer_token_str(lexer),
+ sieve_lexer_token_line(parser->lexer));
+ sieve_lexer_skip_token(lexer);
+ break;
+ /* Number */
+ case STT_NUMBER:
+ arg = sieve_ast_argument_number_create(
+ node, sieve_lexer_token_int(lexer),
+ sieve_lexer_token_line(parser->lexer));
+ sieve_lexer_skip_token(lexer);
+ break;
+ /* Tag */
+ case STT_TAG:
+ arg = sieve_ast_argument_tag_create(
+ node, sieve_lexer_token_ident(lexer),
+ sieve_lexer_token_line(parser->lexer));
+ sieve_lexer_skip_token(lexer);
+ break;
+ /* End of argument list, continue with tests */
+ default:
+ arg_present = FALSE;
+ break;
+ }
+
+ if (arg_present && arg == NULL) {
+ sieve_parser_error(parser,
+ "failed to accept more arguments for command '%s'",
+ node->identifier);
+ return -1;
+ }
+
+ if (sieve_ast_argument_count(node) > SIEVE_MAX_COMMAND_ARGUMENTS) {
+ sieve_parser_error(parser,
+ "too many arguments for command '%s'",
+ node->identifier);
+ return 0;
+ }
+ }
+
+ if (result <= 0)
+ return result; /* Defer recovery to caller */
+
+ /* --> [ test / test-list ]
+ test-list = "(" test *("," test) ")"
+ test = identifier arguments
+ */
+ switch (sieve_lexer_token_type(lexer)) {
+ /* Single test */
+ case STT_IDENTIFIER:
+ if ((depth + 1) > SIEVE_MAX_TEST_NESTING) {
+ sieve_parser_error(parser,
+ "cannot nest tests deeper than %u levels",
+ SIEVE_MAX_TEST_NESTING);
+ return 0;
+ }
+
+ test = sieve_ast_test_create(
+ node, sieve_lexer_token_ident(lexer),
+ sieve_lexer_token_line(parser->lexer));
+ sieve_lexer_skip_token(lexer);
+
+ /* Theoretically, test can be NULL */
+ if (test == NULL)
+ break;
+
+ /* Parse test arguments, which may include more tests (recurse) */
+ if (sieve_parse_arguments(parser, test, depth + 1) <= 0) {
+ return 0; /* Defer recovery to caller */
+ }
+
+ break;
+
+ /* Test list */
+ case STT_LBRACKET:
+ sieve_lexer_skip_token(lexer);
+
+ if (depth+1 > SIEVE_MAX_TEST_NESTING) {
+ sieve_parser_error(parser,
+ "cannot nest tests deeper than %u levels",
+ SIEVE_MAX_TEST_NESTING);
+ result = sieve_parser_recover(parser, STT_RBRACKET);
+
+ if (result > 0)
+ sieve_lexer_skip_token(lexer);
+ return result;
+ }
+
+ node->test_list = TRUE;
+
+ /* Test starts with identifier */
+ if (sieve_lexer_token_type(lexer) == STT_IDENTIFIER) {
+ test = sieve_ast_test_create(
+ node, sieve_lexer_token_ident(lexer),
+ sieve_lexer_token_line(parser->lexer));
+ sieve_lexer_skip_token(lexer);
+
+ if (test == NULL)
+ break;
+
+ /* Parse test arguments, which may include more tests (recurse) */
+ if ((result = sieve_parse_arguments(parser, test, depth+1)) > 0) {
+
+ /* More tests ? */
+ while (sieve_lexer_token_type(lexer) == STT_COMMA) {
+ sieve_lexer_skip_token(lexer);
+
+ /* Check parser status */
+ if (!parser->valid &&
+ !sieve_errors_more_allowed(parser->ehandler)) {
+ result = sieve_parser_recover(parser, STT_RBRACKET);
+ break;
+ }
+
+ /* Test starts with identifier */
+ if (sieve_lexer_token_type(lexer) == STT_IDENTIFIER) {
+ test = sieve_ast_test_create(
+ node, sieve_lexer_token_ident(lexer),
+ sieve_lexer_token_line(parser->lexer));
+ sieve_lexer_skip_token(lexer);
+
+ if (test == NULL)
+ break;
+
+ /* Parse test arguments, which may include more tests (recurse) */
+ if ((result = sieve_parse_arguments(parser, test, depth+1)) <= 0) {
+ if (result < 0)
+ return result;
+ result = sieve_parser_recover(parser, STT_RBRACKET);
+ break;
+ }
+ } else {
+ sieve_parser_error(parser,
+ "expecting test identifier after ',' in test list, "
+ "but found %s",
+ sieve_lexer_token_description(lexer));
+ result = sieve_parser_recover(parser, STT_RBRACKET);
+ break;
+ }
+ }
+ if (test == NULL)
+ break;
+ } else {
+ if (result < 0)
+ return result;
+
+ result = sieve_parser_recover(parser, STT_RBRACKET);
+ }
+ } else {
+ sieve_parser_error(parser,
+ "expecting test identifier after '(' in test list, "
+ "but found %s",
+ sieve_lexer_token_description(lexer));
+
+ result = sieve_parser_recover(parser, STT_RBRACKET);
+ }
+
+ /* The next token should be a ')', indicating the end of the
+ test list
+ --> previous sieve_parser_recover calls try to restore this
+ situation after parse errors.
+ */
+ if (sieve_lexer_token_type(lexer) == STT_RBRACKET) {
+ sieve_lexer_skip_token(lexer);
+ } else {
+ sieve_parser_error(parser,
+ "expecting ',' or end of test list ')', "
+ "but found %s",
+ sieve_lexer_token_description(lexer));
+
+ /* Recover function tries to make next token equal to
+ ')'. If it succeeds we need to skip it.
+ */
+ if ((result = sieve_parser_recover(parser, STT_RBRACKET)) > 0)
+ sieve_lexer_skip_token(lexer);
+ }
+ break;
+
+ default:
+ /* Not an error: test / test-list is optional
+ --> any errors are detected by the caller
+ */
+ test_present = FALSE;
+ break;
+ }
+
+ if (test_present && test == NULL) {
+ sieve_parser_error(parser,
+ "failed to accept more tests for command '%s'",
+ node->identifier);
+ return -1;
+ }
+
+ return result;
+}
+
+/* commands = *command
+ command = identifier arguments ( ";" / block )
+ block = "{" commands "}"
+ */
+static int
+sieve_parse_commands(struct sieve_parser *parser, struct sieve_ast_node *block,
+ unsigned int depth)
+{
+ const struct sieve_lexer *lexer = parser->lexer;
+ int result = 1;
+
+ while (result > 0 &&
+ sieve_lexer_token_type(lexer) == STT_IDENTIFIER) {
+ struct sieve_ast_node *command;
+
+ /* Check parser status */
+ if (!parser->valid &&
+ !sieve_errors_more_allowed(parser->ehandler)) {
+ result = sieve_parser_recover(parser, STT_SEMICOLON);
+ break;
+ }
+
+ /* Create command node */
+ command = sieve_ast_command_create(
+ block, sieve_lexer_token_ident(lexer),
+ sieve_lexer_token_line(parser->lexer));
+ sieve_lexer_skip_token(lexer);
+
+ if (command == NULL) {
+ sieve_parser_error(parser,
+ "failed to accept more commands inside the block of command '%s'",
+ block->identifier);
+ return -1;
+ }
+
+ result = sieve_parse_arguments(parser, command, 1);
+
+ /* Check whether the command is properly terminated
+ (i.e. with ; or a new block)
+ */
+ if (result > 0 &&
+ sieve_lexer_token_type(lexer) != STT_SEMICOLON &&
+ sieve_lexer_token_type(lexer) != STT_LCURLY) {
+
+ sieve_parser_error(parser,
+ "expected end of command ';' or the beginning of a compound block '{', "
+ "but found %s",
+ sieve_lexer_token_description(lexer));
+ result = 0;
+ }
+
+ /* Try to recover from parse errors to reacquire a defined state
+ */
+ if (result == 0)
+ result = sieve_parser_recover(parser, STT_SEMICOLON);
+
+ /* Don't bother to continue if we are not in a defined state */
+ if (result <= 0)
+ return result;
+
+ switch (sieve_lexer_token_type(lexer)) {
+ /* End of the command */
+ case STT_SEMICOLON:
+ sieve_lexer_skip_token(lexer);
+ break;
+ /* Command has a block {...} */
+ case STT_LCURLY:
+ sieve_lexer_skip_token(lexer);
+
+ /* Check current depth first */
+ if ((depth + 1) > SIEVE_MAX_BLOCK_NESTING) {
+ sieve_parser_error(parser,
+ "cannot nest command blocks deeper than %u levels",
+ SIEVE_MAX_BLOCK_NESTING);
+ result = sieve_parser_recover(parser, STT_RCURLY);
+
+ if (result > 0)
+ sieve_lexer_skip_token(lexer);
+ break;
+ }
+
+ command->block = TRUE;
+
+ if ((result = sieve_parse_commands(parser, command, depth + 1)) > 0) {
+ if (sieve_lexer_token_type(lexer) != STT_RCURLY) {
+ sieve_parser_error(parser,
+ "expected end of compound block '}', "
+ "but found %s",
+ sieve_lexer_token_description(lexer));
+ result = sieve_parser_recover(parser, STT_RCURLY);
+ } else {
+ sieve_lexer_skip_token(lexer);
+ }
+ } else {
+ if (result < 0)
+ return result;
+
+ if ((result = sieve_parser_recover(parser, STT_RCURLY)) > 0)
+ sieve_lexer_skip_token(lexer);
+ }
+
+ break;
+
+ default:
+ /* Recovered previously, so this cannot happen */
+ i_unreached();
+ }
+ }
+
+ return result;
+}
+
+bool sieve_parser_run(struct sieve_parser *parser, struct sieve_ast **ast)
+{
+ if (parser->ast != NULL)
+ sieve_ast_unref(&parser->ast);
+
+ /* Create AST object if none is provided */
+ if (*ast == NULL)
+ *ast = sieve_ast_create(parser->script);
+ else
+ sieve_ast_ref(*ast);
+
+ parser->ast = *ast;
+
+ /* Scan first token */
+ sieve_lexer_skip_token(parser->lexer);
+
+ /* Parse */
+ if (sieve_parse_commands(parser, sieve_ast_root(parser->ast), 1) > 0 &&
+ parser->valid) {
+ /* Parsed right to EOF ? */
+ if (sieve_lexer_token_type(parser->lexer) != STT_EOF) {
+ sieve_parser_error(parser,
+ "unexpected %s found at (the presumed) end of file",
+ sieve_lexer_token_description(parser->lexer));
+ parser->valid = FALSE;
+ }
+ } else {
+ parser->valid = FALSE;
+ }
+
+ /* Clean up AST if parse failed */
+ if (!parser->valid) {
+ parser->ast = NULL;
+ sieve_ast_unref(ast);
+ }
+
+ return parser->valid;
+}
+
+/* Error recovery:
+ To continue parsing after an error it is important to find the next
+ parsible item in the stream. The recover function skips over the remaining
+ garbage after an error. It tries to find the end of the failed syntax
+ structure and takes nesting of structures into account.
+ */
+
+/* Assign useful names to priorities for readability */
+enum sieve_grammatical_prio {
+ SGP_BLOCK = 3,
+ SGP_COMMAND = 2,
+ SGP_TEST_LIST = 1,
+ SGP_STRING_LIST = 0,
+
+ SGP_OTHER = -1
+};
+
+static inline enum sieve_grammatical_prio
+__get_token_priority(enum sieve_token_type token)
+{
+ switch (token) {
+ case STT_LCURLY:
+ case STT_RCURLY:
+ return SGP_BLOCK;
+ case STT_SEMICOLON:
+ return SGP_COMMAND;
+ case STT_LBRACKET:
+ case STT_RBRACKET:
+ return SGP_TEST_LIST;
+ case STT_LSQUARE:
+ case STT_RSQUARE:
+ return SGP_STRING_LIST;
+ default:
+ break;
+ }
+
+ return SGP_OTHER;
+}
+
+static int
+sieve_parser_recover(struct sieve_parser *parser,
+ enum sieve_token_type end_token)
+{
+ /* The tokens that begin/end a specific block/command/list in order
+ of ascending grammatical priority.
+ */
+ static const enum sieve_token_type begin_tokens[4] = {
+ STT_LSQUARE, STT_LBRACKET, STT_NONE, STT_LCURLY };
+ static const enum sieve_token_type end_tokens[4] = {
+ STT_RSQUARE, STT_RBRACKET, STT_SEMICOLON, STT_RCURLY};
+ const struct sieve_lexer *lexer = parser->lexer;
+ int nesting = 1;
+ enum sieve_grammatical_prio end_priority =
+ __get_token_priority(end_token);
+
+ i_assert(end_priority != SGP_OTHER);
+
+ while (sieve_lexer_token_type(lexer) != STT_EOF &&
+ __get_token_priority(sieve_lexer_token_type(lexer))
+ <= end_priority) {
+ if (sieve_lexer_token_type(lexer) ==
+ begin_tokens[end_priority]) {
+ nesting++;
+ sieve_lexer_skip_token(lexer);
+ continue;
+ }
+ if (sieve_lexer_token_type(lexer) ==
+ end_tokens[end_priority]) {
+ nesting--;
+
+ if (nesting == 0) {
+ /* Next character is the end */
+ return 1;
+ }
+ }
+ sieve_lexer_skip_token(lexer);
+ }
+
+ /* Special case: COMMAND */
+ if (end_token == STT_SEMICOLON &&
+ sieve_lexer_token_type(lexer) == STT_LCURLY) {
+ return 1;
+ }
+
+ /* End not found before eof or end of surrounding grammatical structure
+ */
+ return 0;
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-parser.h b/pigeonhole/src/lib-sieve/sieve-parser.h
new file mode 100644
index 0000000..dfcb63c
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-parser.h
@@ -0,0 +1,17 @@
+#ifndef SIEVE_PARSER_H
+#define SIEVE_PARSER_H
+
+#include "lib.h"
+
+#include "sieve-common.h"
+
+struct sieve_parser;
+
+struct sieve_parser *
+sieve_parser_create(struct sieve_script *script,
+ struct sieve_error_handler *ehandler,
+ enum sieve_error *error_r);
+void sieve_parser_free(struct sieve_parser **parser);
+bool sieve_parser_run(struct sieve_parser *parser, struct sieve_ast **ast);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-plugins.c b/pigeonhole/src/lib-sieve/sieve-plugins.c
new file mode 100644
index 0000000..c0f32b1
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-plugins.c
@@ -0,0 +1,181 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "module-dir.h"
+
+#include "sieve-settings.h"
+#include "sieve-extensions.h"
+
+#include "sieve-common.h"
+#include "sieve-plugins.h"
+
+/*
+ * Types
+ */
+
+typedef void (*sieve_plugin_load_func_t)
+ (struct sieve_instance *svinst, void **context);
+typedef void (*sieve_plugin_unload_func_t)
+ (struct sieve_instance *svinst, void *context);
+
+struct sieve_plugin {
+ struct module *module;
+
+ void *context;
+
+ struct sieve_plugin *next;
+};
+
+/*
+ * Plugin support
+ */
+
+static struct module *sieve_modules = NULL;
+static int sieve_modules_refcount = 0;
+
+static struct module *sieve_plugin_module_find(const char *name)
+{
+ struct module *module;
+
+ module = sieve_modules;
+ while ( module != NULL ) {
+ const char *mod_name;
+
+ /* Strip module names */
+ mod_name = module_get_plugin_name(module);
+
+ if ( strcmp(mod_name, name) == 0 )
+ return module;
+
+ module = module->next;
+ }
+
+ return NULL;
+}
+
+void sieve_plugins_load
+(struct sieve_instance *svinst, const char *path, const char *plugins)
+{
+ struct module *module;
+ struct module_dir_load_settings mod_set;
+ const char **module_names;
+ unsigned int i;
+
+ /* Determine what to load */
+
+ if ( path == NULL && plugins == NULL ) {
+ path = sieve_setting_get(svinst, "sieve_plugin_dir");
+ plugins = sieve_setting_get(svinst, "sieve_plugins");
+ }
+
+ if ( plugins == NULL || *plugins == '\0' )
+ return;
+
+ if ( path == NULL || *path == '\0' )
+ path = MODULEDIR"/sieve";
+
+ i_zero(&mod_set);
+ mod_set.abi_version = PIGEONHOLE_ABI_VERSION;
+ mod_set.require_init_funcs = TRUE;
+ mod_set.debug = FALSE;
+
+ /* Load missing plugin modules */
+
+ sieve_modules = module_dir_load_missing
+ (sieve_modules, path, plugins, &mod_set);
+
+ /* Call plugin load functions for this Sieve instance */
+
+ if ( svinst->plugins == NULL ) {
+ sieve_modules_refcount++;
+ }
+
+ module_names = t_strsplit_spaces(plugins, ", ");
+
+ for (i = 0; module_names[i] != NULL; i++) {
+ /* Allow giving the module names also in non-base form. */
+ module_names[i] = module_file_get_name(module_names[i]);
+ }
+
+ for (i = 0; module_names[i] != NULL; i++) {
+ struct sieve_plugin *plugin;
+ const char *name = module_names[i];
+ sieve_plugin_load_func_t load_func;
+
+ /* Find the module */
+ module = sieve_plugin_module_find(name);
+ i_assert(module != NULL);
+
+ /* Check whether the plugin is already loaded in this instance */
+ plugin = svinst->plugins;
+ while ( plugin != NULL ) {
+ if ( plugin->module == module )
+ break;
+ plugin = plugin->next;
+ }
+
+ /* Skip it if it is loaded already */
+ if ( plugin != NULL )
+ continue;
+
+ /* Create plugin list item */
+ plugin = p_new(svinst->pool, struct sieve_plugin, 1);
+ plugin->module = module;
+
+ /* Call load function */
+ load_func = (sieve_plugin_load_func_t) module_get_symbol
+ (module, t_strdup_printf("%s_load", module->name));
+ if ( load_func != NULL ) {
+ load_func(svinst, &plugin->context);
+ }
+
+ /* Add plugin to the instance */
+ if ( svinst->plugins == NULL )
+ svinst->plugins = plugin;
+ else {
+ struct sieve_plugin *plugin_last;
+
+ plugin_last = svinst->plugins;
+ while ( plugin_last->next != NULL )
+ plugin_last = plugin_last->next;
+
+ plugin_last->next = plugin;
+ }
+ }
+}
+
+void sieve_plugins_unload(struct sieve_instance *svinst)
+{
+ struct sieve_plugin *plugin;
+
+ if ( svinst->plugins == NULL )
+ return;
+
+ /* Call plugin unload functions for this instance */
+
+ plugin = svinst->plugins;
+ while ( plugin != NULL ) {
+ struct module *module = plugin->module;
+ sieve_plugin_unload_func_t unload_func;
+
+ unload_func = (sieve_plugin_unload_func_t)module_get_symbol
+ (module, t_strdup_printf("%s_unload", module->name));
+ if ( unload_func != NULL ) {
+ unload_func(svinst, plugin->context);
+ }
+
+ plugin = plugin->next;
+ }
+
+ /* Physically unload modules */
+
+ i_assert(sieve_modules_refcount > 0);
+
+ if ( --sieve_modules_refcount != 0 )
+ return;
+
+ module_dir_unload(&sieve_modules);
+}
+
diff --git a/pigeonhole/src/lib-sieve/sieve-plugins.h b/pigeonhole/src/lib-sieve/sieve-plugins.h
new file mode 100644
index 0000000..996af41
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-plugins.h
@@ -0,0 +1,9 @@
+#ifndef SIEVE_PLUGINS_H
+#define SIEVE_PLUGINS_H
+
+#include "sieve-common.h"
+
+void sieve_plugins_load(struct sieve_instance *svinst, const char *path, const char *plugins);
+void sieve_plugins_unload(struct sieve_instance *svinst);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-result.c b/pigeonhole/src/lib-sieve/sieve-result.c
new file mode 100644
index 0000000..89d249e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-result.c
@@ -0,0 +1,2445 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "mempool.h"
+#include "ostream.h"
+#include "hash.h"
+#include "str.h"
+#include "llist.h"
+#include "strfuncs.h"
+#include "str-sanitize.h"
+#include "var-expand.h"
+#include "message-address.h"
+#include "mail-storage.h"
+
+#include "sieve-common.h"
+#include "sieve-limits.h"
+#include "sieve-script.h"
+#include "sieve-error.h"
+#include "sieve-interpreter.h"
+#include "sieve-actions.h"
+#include "sieve-message.h"
+
+#include "sieve-result.h"
+
+#include <stdio.h>
+
+struct event_category event_category_sieve_action = {
+ .parent = &event_category_sieve,
+ .name = "sieve-action",
+};
+
+/*
+ * Types
+ */
+
+enum sieve_action_execution_state {
+ SIEVE_ACTION_EXECUTION_STATE_INIT = 0,
+ SIEVE_ACTION_EXECUTION_STATE_STARTED,
+ SIEVE_ACTION_EXECUTION_STATE_EXECUTED,
+ SIEVE_ACTION_EXECUTION_STATE_FINALIZED,
+};
+
+struct sieve_result_action {
+ struct sieve_action action;
+
+ struct sieve_side_effects_list *seffects;
+
+ struct sieve_result_action *prev, *next;
+};
+
+struct sieve_side_effects_list {
+ struct sieve_result *result;
+
+ struct sieve_result_side_effect *first_effect;
+ struct sieve_result_side_effect *last_effect;
+};
+
+struct sieve_result_side_effect {
+ struct sieve_side_effect seffect;
+
+ struct sieve_result_side_effect *prev, *next;
+};
+
+struct sieve_result_action_context {
+ const struct sieve_action_def *action;
+ struct sieve_side_effects_list *seffects;
+};
+
+/*
+ * Result object
+ */
+
+struct sieve_result {
+ pool_t pool;
+ int refcount;
+
+ struct sieve_instance *svinst;
+ struct event *event;
+
+ /* Context data for extensions */
+ ARRAY(void *) ext_contexts;
+
+ const struct sieve_execute_env *exec_env;
+ struct sieve_error_handler *ehandler;
+ struct sieve_message_context *msgctx;
+
+ unsigned int exec_seq;
+ struct sieve_result_execution *exec;
+
+ struct sieve_action keep_action;
+ struct sieve_action failure_action;
+
+ unsigned int action_count;
+ struct sieve_result_action *actions_head, *actions_tail;
+
+ HASH_TABLE(const struct sieve_action_def *,
+ struct sieve_result_action_context *) action_contexts;
+};
+
+static const char *
+sieve_result_event_log_message(struct sieve_result *result,
+ enum log_type log_type, const char *message)
+{
+ const struct sieve_script_env *senv = result->exec_env->scriptenv;
+
+ i_assert(senv->result_amend_log_message != NULL);
+ return senv->result_amend_log_message(senv, log_type, message);
+}
+
+struct sieve_result *
+sieve_result_create(struct sieve_instance *svinst, pool_t pool,
+ const struct sieve_execute_env *eenv)
+{
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ const struct sieve_message_data *msgdata = eenv->msgdata;
+ struct sieve_result *result;
+
+ pool_ref(pool);
+
+ result = p_new(pool, struct sieve_result, 1);
+ result->refcount = 1;
+ result->pool = pool;
+ result->svinst = svinst;
+
+ result->event = event_create(eenv->event);
+ event_add_category(result->event, &event_category_sieve_action);
+ if (senv->result_amend_log_message != NULL) {
+ event_set_log_message_callback(
+ result->event, sieve_result_event_log_message, result);
+ }
+
+ p_array_init(&result->ext_contexts, pool, 4);
+
+ result->exec_env = eenv;
+ result->msgctx =
+ sieve_message_context_create(svinst, senv->user, msgdata);
+
+ result->keep_action.def = &act_store;
+ result->keep_action.ext = NULL;
+ result->failure_action.def = &act_store;
+ result->failure_action.ext = NULL;
+
+ result->action_count = 0;
+ result->actions_head = NULL;
+ result->actions_tail = NULL;
+
+ return result;
+}
+
+void sieve_result_ref(struct sieve_result *result)
+{
+ result->refcount++;
+}
+
+static void
+sieve_result_action_deinit(struct sieve_result_action *ract)
+{
+ event_unref(&ract->action.event);
+}
+
+void sieve_result_unref(struct sieve_result **_result)
+{
+ struct sieve_result *result = *_result;
+ struct sieve_result_action *ract;
+
+ i_assert(result->refcount > 0);
+
+ if (--result->refcount != 0)
+ return;
+
+ sieve_message_context_unref(&result->msgctx);
+
+ hash_table_destroy(&result->action_contexts);
+
+ ract = result->actions_head;
+ while (ract != NULL) {
+ sieve_result_action_deinit(ract);
+ ract = ract->next;
+ }
+ event_unref(&result->event);
+
+ pool_unref(&result->pool);
+ *_result = NULL;
+}
+
+pool_t sieve_result_pool(struct sieve_result *result)
+{
+ return result->pool;
+}
+
+/*
+ * Getters/Setters
+ */
+
+const struct sieve_script_env *
+sieve_result_get_script_env(struct sieve_result *result)
+{
+ return result->exec_env->scriptenv;
+}
+
+const struct sieve_message_data *
+sieve_result_get_message_data(struct sieve_result *result)
+{
+ return result->exec_env->msgdata;
+}
+
+struct sieve_message_context *
+sieve_result_get_message_context(struct sieve_result *result)
+{
+ return result->msgctx;
+}
+
+unsigned int sieve_result_get_exec_seq(struct sieve_result *result)
+{
+ return result->exec_seq;
+}
+
+/*
+ * Extension support
+ */
+
+void sieve_result_extension_set_context(struct sieve_result *result,
+ const struct sieve_extension *ext,
+ void *context)
+{
+ if (ext->id < 0)
+ return;
+
+ array_idx_set(&result->ext_contexts, (unsigned int) ext->id, &context);
+}
+
+const void *
+sieve_result_extension_get_context(struct sieve_result *result,
+ const struct sieve_extension *ext)
+{
+ void * const *ctx;
+
+ if (ext->id < 0 || ext->id >= (int) array_count(&result->ext_contexts))
+ return NULL;
+
+ ctx = array_idx(&result->ext_contexts, (unsigned int) ext->id);
+
+ return *ctx;
+}
+
+/*
+ * Result composition
+ */
+
+static void
+sieve_result_init_action_event(struct sieve_result *result,
+ struct sieve_action *action, bool add_prefix)
+{
+ const char *name = sieve_action_name(action);
+
+ if (action->event != NULL)
+ return;
+
+ action->event = event_create(result->event);
+ if (add_prefix && name != NULL) {
+ event_set_append_log_prefix(
+ action->event, t_strconcat(name, " action: ", NULL));
+ }
+ event_add_str(action->event, "action_name", name);
+ event_add_str(action->event, "script_location", action->location);
+}
+
+void sieve_result_add_implicit_side_effect(
+ struct sieve_result *result, const struct sieve_action_def *to_action,
+ bool to_keep, const struct sieve_extension *ext,
+ const struct sieve_side_effect_def *seff_def, void *context)
+{
+ struct sieve_result_action_context *actctx = NULL;
+ struct sieve_side_effect seffect;
+
+ to_action = to_keep ? &act_store : to_action;
+
+ if (!hash_table_is_created(result->action_contexts)) {
+ hash_table_create_direct(&result->action_contexts,
+ result->pool, 0);
+ } else {
+ actctx = hash_table_lookup(result->action_contexts, to_action);
+ }
+
+ if (actctx == NULL) {
+ actctx = p_new(result->pool,
+ struct sieve_result_action_context, 1);
+ actctx->action = to_action;
+ actctx->seffects = sieve_side_effects_list_create(result);
+
+ hash_table_insert(result->action_contexts, to_action, actctx);
+ }
+
+ seffect.object.def = &seff_def->obj_def;
+ seffect.object.ext = ext;
+ seffect.def = seff_def;
+ seffect.context = context;
+
+ sieve_side_effects_list_add(actctx->seffects, &seffect);
+}
+
+static int
+sieve_result_side_effects_merge(const struct sieve_runtime_env *renv,
+ const struct sieve_action *action,
+ struct sieve_result_action *old_action,
+ struct sieve_side_effects_list *new_seffects)
+{
+ struct sieve_side_effects_list *old_seffects = old_action->seffects;
+ int ret;
+ struct sieve_result_side_effect *rsef, *nrsef;
+
+ /* Allow side-effects to merge with existing copy */
+
+ /* Merge existing side effects */
+ rsef = old_seffects != NULL ? old_seffects->first_effect : NULL;
+ while (rsef != NULL) {
+ struct sieve_side_effect *seffect = &rsef->seffect;
+ bool found = FALSE;
+
+ i_assert(seffect->def != NULL);
+ if (seffect->def->merge != NULL) {
+ /* Try to find it among the new */
+ nrsef = (new_seffects != NULL ?
+ new_seffects->first_effect : NULL);
+ while (nrsef != NULL) {
+ struct sieve_side_effect *nseffect = &nrsef->seffect;
+
+ if (nseffect->def == seffect->def) {
+ if (seffect->def->merge(
+ renv, action, seffect, nseffect,
+ &seffect->context) < 0)
+ return -1;
+
+ found = TRUE;
+ break;
+ }
+ nrsef = nrsef->next;
+ }
+
+ /* Not found? */
+ if (!found && seffect->def->merge(
+ renv, action, seffect, NULL,
+ &rsef->seffect.context) < 0)
+ return -1;
+ }
+ rsef = rsef->next;
+ }
+
+ /* Merge new Side effects */
+ nrsef = new_seffects != NULL ? new_seffects->first_effect : NULL;
+ while (nrsef != NULL) {
+ struct sieve_side_effect *nseffect = &nrsef->seffect;
+ bool found = FALSE;
+
+ i_assert(nseffect->def != NULL);
+ if (nseffect->def->merge != NULL) {
+ /* Try to find it among the exising */
+ rsef = (old_seffects != NULL ?
+ old_seffects->first_effect : NULL);
+ while (rsef != NULL) {
+ if (rsef->seffect.def == nseffect->def) {
+ found = TRUE;
+ break;
+ }
+ rsef = rsef->next;
+ }
+
+ /* Not found? */
+ if (!found) {
+ void *new_context = NULL;
+
+ if ((ret = nseffect->def->merge(
+ renv, action, nseffect, nseffect,
+ &new_context)) < 0)
+ return -1;
+
+ if (ret != 0) {
+ if (old_action->seffects == NULL) {
+ old_action->seffects = old_seffects =
+ sieve_side_effects_list_create(renv->result);
+ }
+
+ nseffect->context = new_context;
+
+ /* Add side effect */
+ sieve_side_effects_list_add(old_seffects,
+ nseffect);
+ }
+ }
+ }
+ nrsef = nrsef->next;
+ }
+
+ return 1;
+}
+
+static void
+sieve_result_action_detach(struct sieve_result *result,
+ struct sieve_result_action *raction)
+{
+ if (result->actions_head == raction)
+ result->actions_head = raction->next;
+
+ if (result->actions_tail == raction)
+ result->actions_tail = raction->prev;
+
+ if (raction->next != NULL)
+ raction->next->prev = raction->prev;
+ if (raction->prev != NULL)
+ raction->prev->next = raction->next;
+
+ raction->next = NULL;
+ raction->prev = NULL;
+
+ if (result->action_count > 0)
+ result->action_count--;
+}
+
+static int
+_sieve_result_add_action(const struct sieve_runtime_env *renv,
+ const struct sieve_extension *ext, const char *name,
+ const struct sieve_action_def *act_def,
+ struct sieve_side_effects_list *seffects,
+ void *context, unsigned int instance_limit,
+ bool preserve_mail, bool keep)
+{
+ int ret = 0;
+ unsigned int instance_count = 0;
+ struct sieve_instance *svinst = renv->exec_env->svinst;
+ struct sieve_result *result = renv->result;
+ struct sieve_result_action *raction = NULL, *kaction = NULL;
+ struct sieve_action action;
+
+ i_assert(name != NULL || act_def != NULL);
+ action.name = name;
+ action.def = act_def;
+ action.ext = ext;
+ action.location = sieve_runtime_get_full_command_location(renv);
+ action.context = context;
+ action.exec_seq = result->exec_seq;
+
+ /* First, check for duplicates or conflicts */
+ raction = result->actions_head;
+ while (raction != NULL) {
+ const struct sieve_action *oact = &raction->action;
+ bool oact_new = (oact->exec_seq == result->exec_seq);
+
+ if (keep && raction->action.keep) {
+ /* Duplicate keep */
+ if (oact->def == NULL || !oact_new) {
+ /* Keep action from preceeding execution */
+
+ /* Detach existing keep action */
+ sieve_result_action_detach(result, raction);
+
+ /* Merge existing side-effects with new keep action */
+ if (kaction == NULL)
+ kaction = raction;
+
+ if ((ret = sieve_result_side_effects_merge(
+ renv, &action, kaction, seffects)) <= 0)
+ return ret;
+ } else {
+ /* True duplicate */
+ return sieve_result_side_effects_merge(
+ renv, &action, raction, seffects);
+ }
+ } else if ( act_def != NULL && raction->action.def == act_def ) {
+ instance_count++;
+
+ /* Possible duplicate */
+ if (act_def->check_duplicate != NULL) {
+ if ((ret = act_def->check_duplicate(
+ renv, &action, &raction->action)) < 0)
+ return ret;
+
+ /* Duplicate */
+ if (ret == 1) {
+ if (keep && !oact->keep) {
+ /* New keep has higher precedence than
+ existing duplicate non-keep action.
+ So, take over the result action object
+ and transform it into a keep.
+ */
+ if ((ret = sieve_result_side_effects_merge(
+ renv, &action, raction, seffects)) < 0)
+ return ret;
+
+ if (kaction == NULL) {
+ raction->action.context = NULL;
+ raction->action.location =
+ p_strdup(result->pool, action.location);
+
+ /* Note that existing execution
+ status is retained, making sure
+ that keep is not executed
+ multiple times.
+ */
+ kaction = raction;
+ } else {
+ sieve_result_action_detach(result, raction);
+
+ if ((ret = sieve_result_side_effects_merge(
+ renv, &action, kaction,
+ raction->seffects)) < 0)
+ return ret;
+ }
+ } else {
+ /* Merge side-effects, but don't add new action
+ */
+ return sieve_result_side_effects_merge(
+ renv, &action, raction, seffects);
+ }
+ }
+ }
+ } else {
+ if (act_def != NULL && oact->def != NULL) {
+ /* Check conflict */
+ if (act_def->check_conflict != NULL &&
+ (ret = act_def->check_conflict(
+ renv, &action, &raction->action)) != 0)
+ return ret;
+
+ if (oact_new &&
+ oact->def->check_conflict != NULL &&
+ (ret = oact->def->check_conflict(
+ renv, &raction->action, &action)) != 0)
+ return ret;
+ }
+ }
+ raction = raction->next;
+ }
+
+ if (kaction != NULL) {
+ /* Use existing keep action to define new one */
+ raction = kaction;
+ } else {
+ /* Check policy limit on total number of actions */
+ if (svinst->max_actions > 0 &&
+ result->action_count >= svinst->max_actions)
+ {
+ sieve_runtime_error(
+ renv, action.location,
+ "total number of actions exceeds policy limit "
+ "(%u > %u)",
+ result->action_count+1, svinst->max_actions);
+ return -1;
+ }
+
+ /* Check policy limit on number of this class of actions */
+ if (instance_limit > 0 && instance_count >= instance_limit) {
+ sieve_runtime_error(
+ renv, action.location,
+ "number of %s actions exceeds policy limit "
+ "(%u > %u)",
+ act_def->name, instance_count+1,
+ instance_limit);
+ return -1;
+ }
+
+ /* Create new action object */
+ raction = p_new(result->pool, struct sieve_result_action, 1);
+ raction->seffects = seffects;
+ }
+
+ raction->action.name = (action.name == NULL ?
+ act_def->name :
+ p_strdup(result->pool, action.name));
+ raction->action.context = context;
+ raction->action.def = act_def;
+ raction->action.ext = ext;
+ raction->action.location = p_strdup(result->pool, action.location);
+ raction->action.keep = keep;
+ raction->action.exec_seq = result->exec_seq;
+
+ if (raction->prev == NULL && raction != result->actions_head) {
+ /* Add */
+ if (result->actions_head == NULL) {
+ result->actions_head = raction;
+ result->actions_tail = raction;
+ raction->prev = NULL;
+ raction->next = NULL;
+ } else {
+ result->actions_tail->next = raction;
+ raction->prev = result->actions_tail;
+ result->actions_tail = raction;
+ raction->next = NULL;
+ }
+ result->action_count++;
+
+ /* Apply any implicit side effects */
+ if (hash_table_is_created(result->action_contexts)) {
+ struct sieve_result_action_context *actctx;
+
+ /* Check for implicit side effects to this particular
+ action */
+ actctx = hash_table_lookup(
+ result->action_contexts,
+ (keep ? &act_store : act_def));
+
+ if (actctx != NULL) {
+ struct sieve_result_side_effect *iseff;
+
+ /* Iterate through all implicit side effects and
+ add those that are missing.
+ */
+ iseff = actctx->seffects->first_effect;
+ while (iseff != NULL) {
+ struct sieve_result_side_effect *seff;
+ bool exists = FALSE;
+
+ /* Scan for presence */
+ if (seffects != NULL) {
+ seff = seffects->first_effect;
+ while (seff != NULL) {
+ if (seff->seffect.def == iseff->seffect.def) {
+ exists = TRUE;
+ break;
+ }
+
+ seff = seff->next;
+ }
+ } else {
+ raction->seffects = seffects =
+ sieve_side_effects_list_create(result);
+ }
+
+ /* If not present, add it */
+ if (!exists) {
+ sieve_side_effects_list_add(seffects, &iseff->seffect);
+ }
+
+ iseff = iseff->next;
+ }
+ }
+ }
+ }
+
+ if (preserve_mail) {
+ raction->action.mail = sieve_message_get_mail(renv->msgctx);
+ sieve_message_snapshot(renv->msgctx);
+ } else {
+ raction->action.mail = NULL;
+ }
+
+ sieve_result_init_action_event(result, &raction->action, !keep);
+ return 0;
+}
+
+int sieve_result_add_action(const struct sieve_runtime_env *renv,
+ const struct sieve_extension *ext, const char *name,
+ const struct sieve_action_def *act_def,
+ struct sieve_side_effects_list *seffects,
+ void *context, unsigned int instance_limit,
+ bool preserve_mail)
+{
+ return _sieve_result_add_action(renv, ext, name, act_def, seffects,
+ context, instance_limit, preserve_mail,
+ FALSE);
+}
+
+int sieve_result_add_keep(const struct sieve_runtime_env *renv,
+ struct sieve_side_effects_list *seffects)
+{
+ return _sieve_result_add_action(renv, renv->result->keep_action.ext,
+ "keep", renv->result->keep_action.def,
+ seffects, NULL, 0, TRUE, TRUE);
+}
+
+void sieve_result_set_keep_action(struct sieve_result *result,
+ const struct sieve_extension *ext,
+ const struct sieve_action_def *act_def)
+{
+ result->keep_action.def = act_def;
+ result->keep_action.ext = ext;
+}
+
+void sieve_result_set_failure_action(struct sieve_result *result,
+ const struct sieve_extension *ext,
+ const struct sieve_action_def *act_def)
+{
+ result->failure_action.def = act_def;
+ result->failure_action.ext = ext;
+}
+
+/*
+ * Result printing
+ */
+
+void sieve_result_vprintf(const struct sieve_result_print_env *penv,
+ const char *fmt, va_list args)
+{
+ string_t *outbuf = t_str_new(128);
+
+ str_vprintfa(outbuf, fmt, args);
+
+ o_stream_nsend(penv->stream, str_data(outbuf), str_len(outbuf));
+}
+
+void sieve_result_printf(const struct sieve_result_print_env *penv,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ sieve_result_vprintf(penv, fmt, args);
+ va_end(args);
+}
+
+void sieve_result_action_printf(const struct sieve_result_print_env *penv,
+ const char *fmt, ...)
+{
+ string_t *outbuf = t_str_new(128);
+ va_list args;
+
+ va_start(args, fmt);
+ str_append(outbuf, " * ");
+ str_vprintfa(outbuf, fmt, args);
+ str_append_c(outbuf, '\n');
+ va_end(args);
+
+ o_stream_nsend(penv->stream, str_data(outbuf), str_len(outbuf));
+}
+
+void sieve_result_seffect_printf(const struct sieve_result_print_env *penv,
+ const char *fmt, ...)
+{
+ string_t *outbuf = t_str_new(128);
+ va_list args;
+
+ va_start(args, fmt);
+ str_append(outbuf, " + ");
+ str_vprintfa(outbuf, fmt, args);
+ str_append_c(outbuf, '\n');
+ va_end(args);
+
+ o_stream_nsend(penv->stream, str_data(outbuf), str_len(outbuf));
+}
+
+static void
+sieve_result_print_side_effects(struct sieve_result_print_env *rpenv,
+ const struct sieve_action *action,
+ struct sieve_side_effects_list *slist,
+ bool *implicit_keep)
+{
+ struct sieve_result_side_effect *rsef;
+
+ /* Print side effects */
+ rsef = (slist != NULL ? slist->first_effect : NULL);
+ while (rsef != NULL) {
+ const struct sieve_side_effect *sef = &rsef->seffect;
+
+ i_assert(sef->def != NULL);
+
+ if (sef->def->print != NULL) {
+ sef->def->print(sef, action, rpenv,
+ implicit_keep);
+ }
+ rsef = rsef->next;
+ }
+}
+
+static void
+sieve_result_print_implicit_side_effects(struct sieve_result_print_env *rpenv)
+{
+ struct sieve_result *result = rpenv->result;
+ bool dummy = TRUE;
+
+ /* Print any implicit side effects if applicable */
+ if (hash_table_is_created(result->action_contexts)) {
+ struct sieve_result_action_context *actctx;
+
+ /* Check for implicit side effects to keep action */
+ actctx = hash_table_lookup(rpenv->result->action_contexts,
+ &act_store);
+
+ if (actctx != NULL && actctx->seffects != NULL) {
+ sieve_result_print_side_effects(
+ rpenv, &result->keep_action,
+ actctx->seffects, &dummy);
+ }
+ }
+}
+
+bool sieve_result_print(struct sieve_result *result,
+ const struct sieve_script_env *senv,
+ struct ostream *stream, bool *keep)
+{
+ struct sieve_action act_keep = result->keep_action;
+ struct sieve_result_print_env penv;
+ bool implicit_keep = TRUE, printed_any = FALSE;
+ struct sieve_result_action *rac;
+
+ if (keep != NULL)
+ *keep = FALSE;
+
+ /* Prepare environment */
+
+ penv.result = result;
+ penv.stream = stream;
+ penv.scriptenv = senv;
+
+ sieve_result_printf(&penv, "\nPerformed actions:\n\n");
+
+ rac = result->actions_head;
+ while (rac != NULL) {
+ bool impl_keep = TRUE;
+ const struct sieve_action *act = &rac->action;
+
+ if (act->exec_seq < result->exec_seq) {
+ rac = rac->next;
+ continue;
+ }
+
+ if (rac->action.keep && keep != NULL)
+ *keep = TRUE;
+
+ if (act->def != NULL) {
+ if (act->def->print != NULL)
+ act->def->print(act, &penv, &impl_keep);
+ else {
+ sieve_result_action_printf(
+ &penv, "%s", act->def->name);
+ }
+ } else {
+ if (act->keep) {
+ sieve_result_action_printf(&penv, "keep");
+ impl_keep = FALSE;
+ } else {
+ sieve_result_action_printf(&penv, "[NULL]");
+ }
+ }
+ printed_any = TRUE;
+
+ /* Print side effects */
+ sieve_result_print_side_effects(
+ &penv, &rac->action, rac->seffects, &impl_keep);
+
+ implicit_keep = implicit_keep && impl_keep;
+
+ rac = rac->next;
+ }
+ if (!printed_any)
+ sieve_result_printf(&penv, " (none)\n");
+
+ if (implicit_keep && keep != NULL)
+ *keep = TRUE;
+
+ sieve_result_printf(&penv, "\nImplicit keep:\n\n");
+
+ if (implicit_keep) {
+ bool dummy = TRUE;
+
+ if (act_keep.def == NULL) {
+ sieve_result_action_printf(&penv, "keep");
+
+ sieve_result_print_implicit_side_effects(&penv);
+ } else {
+ /* Scan for execution of keep-equal actions */
+ rac = result->actions_head;
+ while (act_keep.def != NULL && rac != NULL) {
+ if (rac->action.def == act_keep.def &&
+ act_keep.def->equals != NULL &&
+ act_keep.def->equals(senv, NULL, &rac->action) &&
+ sieve_action_is_executed(&rac->action,
+ result))
+ act_keep.def = NULL;
+
+ rac = rac->next;
+ }
+
+ if (act_keep.def == NULL) {
+ sieve_result_printf(&penv,
+ " (none; keep or equivalent action executed earlier)\n");
+ } else {
+ act_keep.def->print(&act_keep, &penv, &dummy);
+
+ sieve_result_print_implicit_side_effects(&penv);
+ }
+ }
+ } else {
+ sieve_result_printf(&penv, " (none)\n");
+ }
+
+ sieve_result_printf(&penv, "\n");
+
+ return TRUE;
+}
+
+/*
+ * Result execution
+ */
+
+struct sieve_side_effect_execution {
+ struct sieve_result_side_effect *seffect;
+
+ void *tr_context;
+
+ struct sieve_side_effect_execution *prev, *next;
+};
+
+struct sieve_action_execution {
+ struct sieve_result_action *action;
+ unsigned int exec_seq;
+ struct sieve_action_execution *prev, *next;
+
+ struct sieve_side_effect_execution *seffects_head, *seffects_tail;
+
+ struct sieve_error_handler *ehandler;
+ void *tr_context;
+ enum sieve_action_execution_state state;
+ int status;
+
+ bool commit:1;
+};
+
+struct sieve_result_execution {
+ pool_t pool;
+ struct sieve_action_exec_env action_env;
+ struct sieve_error_handler *ehandler;
+ struct event *event;
+
+ int status;
+
+ struct sieve_action_execution *actions_head, *actions_tail;
+
+ struct sieve_result_action keep_action;
+ struct sieve_action_execution keep;
+ struct sieve_action_execution *keep_equiv_action;
+ int keep_status;
+
+ bool keep_success:1;
+ bool keep_explicit:1;
+ bool keep_implicit:1;
+ bool keep_finalizing:1;
+ bool seen_delivery:1;
+ bool executed:1;
+ bool executed_delivery:1;
+ bool committed:1;
+};
+
+void sieve_result_mark_executed(struct sieve_result *result)
+{
+ result->exec_seq++;
+}
+
+/* Side effect */
+
+static int
+sieve_result_side_effect_pre_execute(struct sieve_result_execution *rexec,
+ struct sieve_action_execution *aexec,
+ struct sieve_side_effect_execution *seexec)
+{
+ struct sieve_result_side_effect *rsef = seexec->seffect;
+ struct sieve_side_effect *sef = &rsef->seffect;
+
+ i_assert(sef->def != NULL);
+ if (sef->def->pre_execute == NULL)
+ return SIEVE_EXEC_OK;
+
+ return sef->def->pre_execute(sef, &rexec->action_env,
+ aexec->tr_context, &seexec->tr_context);
+}
+
+static int
+sieve_result_side_effect_post_execute(
+ struct sieve_result_execution *rexec,
+ struct sieve_action_execution *aexec,
+ struct sieve_side_effect_execution *seexec, bool *impl_keep)
+{
+ struct sieve_result_side_effect *rsef = seexec->seffect;
+ struct sieve_side_effect *sef = &rsef->seffect;
+
+ i_assert(sef->def != NULL);
+ if (sef->def->post_execute == NULL)
+ return SIEVE_EXEC_OK;
+
+ return sef->def->post_execute(sef, &rexec->action_env,
+ aexec->tr_context, seexec->tr_context,
+ impl_keep);
+}
+
+static void
+sieve_result_side_effect_post_commit(struct sieve_result_execution *rexec,
+ struct sieve_action_execution *aexec,
+ struct sieve_side_effect_execution *seexec,
+ int commit_status)
+{
+ struct sieve_result_side_effect *rsef = seexec->seffect;
+ struct sieve_side_effect *sef = &rsef->seffect;
+
+ i_assert(sef->def != NULL);
+ if (sef->def->post_commit == NULL)
+ return;
+
+ sef->def->post_commit(sef, &rexec->action_env,
+ aexec->tr_context, seexec->tr_context,
+ commit_status);
+}
+
+static void
+sieve_result_side_effect_rollback(struct sieve_result_execution *rexec,
+ struct sieve_action_execution *aexec,
+ struct sieve_side_effect_execution *seexec)
+{
+ struct sieve_result_side_effect *rsef = seexec->seffect;
+ struct sieve_side_effect *sef = &rsef->seffect;
+
+ i_assert(sef->def != NULL);
+ if (sef->def->rollback == NULL)
+ return;
+
+ sef->def->rollback(sef, &rexec->action_env,
+ aexec->tr_context, seexec->tr_context,
+ (aexec->status == SIEVE_EXEC_OK));
+}
+
+static void
+sieve_action_execution_add_side_effect(struct sieve_result_execution *rexec,
+ struct sieve_action_execution *aexec,
+ struct sieve_result_side_effect *seffect)
+{
+ struct sieve_side_effect_execution *seexec;
+
+ seexec = aexec->seffects_head;
+ while (seexec != NULL) {
+ if (seexec->seffect == seffect)
+ return;
+ seexec = seexec->next;
+ }
+
+ seexec = p_new(rexec->pool, struct sieve_side_effect_execution, 1);
+ seexec->seffect = seffect;
+
+ DLLIST2_APPEND(&aexec->seffects_head, &aexec->seffects_tail, seexec);
+}
+
+static void
+sieve_action_execution_add_side_effects(struct sieve_result_execution *rexec,
+ struct sieve_action_execution *aexec,
+ struct sieve_result_action *rac)
+{
+ struct sieve_result_side_effect *rsef;
+
+ rsef = (rac->seffects == NULL ? NULL : rac->seffects->first_effect);
+ while (rsef != NULL) {
+ sieve_action_execution_add_side_effect(rexec, aexec, rsef);
+ rsef = rsef->next;
+ }
+}
+
+/* Action */
+
+static void
+sieve_action_execution_pre(struct sieve_result_execution *rexec,
+ struct sieve_action_execution *aexec)
+{
+ if (aexec->ehandler == NULL)
+ aexec->ehandler = rexec->ehandler;
+ rexec->action_env.action = &aexec->action->action;
+ rexec->action_env.event = aexec->action->action.event;
+ rexec->action_env.ehandler = aexec->ehandler;
+}
+
+static void
+sieve_action_execution_post(struct sieve_result_execution *rexec)
+{
+ rexec->action_env.action = NULL;
+ rexec->action_env.event = rexec->action_env.result->event;
+ rexec->action_env.ehandler = NULL;
+}
+
+static int
+sieve_result_action_start(struct sieve_result_execution *rexec,
+ struct sieve_action_execution *aexec)
+{
+ struct sieve_result_action *rac = aexec->action;
+ struct sieve_action *act = &rac->action;
+ int status = SIEVE_EXEC_OK;
+
+ /* Skip actions that are already started. */
+ if (aexec->state >= SIEVE_ACTION_EXECUTION_STATE_STARTED)
+ return status;
+ aexec->state = SIEVE_ACTION_EXECUTION_STATE_STARTED;
+ aexec->status = status;
+
+ /* Skip non-actions (inactive keep). */
+ if (act->def == NULL)
+ return status;
+
+ if (act->def->start != NULL) {
+ sieve_action_execution_pre(rexec, aexec);
+ status = act->def->start(&rexec->action_env,
+ &aexec->tr_context);
+ aexec->status = status;
+ sieve_action_execution_post(rexec);
+ }
+ return status;
+}
+
+static int
+sieve_result_action_execute(struct sieve_result_execution *rexec,
+ struct sieve_action_execution *aexec,
+ int start_status)
+{
+ struct sieve_result_action *rac = aexec->action;
+ struct sieve_action *act = &rac->action;
+ struct sieve_side_effect_execution *seexec;
+ int status = start_status;
+ bool impl_keep = TRUE;
+
+ /* Skip actions that are already executed. */
+ if (aexec->state >= SIEVE_ACTION_EXECUTION_STATE_EXECUTED)
+ return status;
+ aexec->state = SIEVE_ACTION_EXECUTION_STATE_EXECUTED;
+
+ /* Record explicit keep when it is not the final implicit keep */
+ if (act->keep && aexec != &rexec->keep)
+ rexec->keep_explicit = TRUE;
+
+ /* Skip non-actions (inactive keep) */
+ if (act->def == NULL) {
+ i_assert(aexec != &rexec->keep);
+ if (act->keep)
+ e_debug(rexec->event, "Executed explicit keep");
+ return status;
+ }
+
+ /* Don't execute if others already failed */
+ if (status != SIEVE_EXEC_OK)
+ return status;
+
+ if (aexec == &rexec->keep)
+ e_debug(rexec->event, "Executing implicit keep action");
+ else {
+ e_debug(rexec->event, "Executing %s action%s",
+ sieve_action_name(act),
+ (act->keep ? " (explicit keep)" : ""));
+ }
+
+ sieve_action_execution_pre(rexec, aexec);
+
+ /* Execute pre-execute event of side effects */
+ seexec = aexec->seffects_head;
+ while (status == SIEVE_EXEC_OK && seexec != NULL) {
+ status = sieve_result_side_effect_pre_execute(
+ rexec, aexec, seexec);
+ seexec = seexec->next;
+ }
+
+ /* Execute the action itself */
+ if (status == SIEVE_EXEC_OK && act->def != NULL &&
+ act->def->execute != NULL) {
+ status = act->def->execute(&rexec->action_env,
+ aexec->tr_context,
+ &impl_keep);
+ if (status == SIEVE_EXEC_OK)
+ rexec->executed = TRUE;
+ }
+
+ /* Execute post-execute event of side effects */
+ seexec = aexec->seffects_head;
+ while (status == SIEVE_EXEC_OK && seexec != NULL) {
+ status = sieve_result_side_effect_post_execute(
+ rexec, aexec, seexec, &impl_keep);
+ seexec = seexec->next;
+ }
+
+ if (aexec == &rexec->keep) {
+ e_debug(rexec->event,
+ "Finished executing implicit keep action (status=%s)",
+ sieve_execution_exitcode_to_str(status));
+ } else {
+ e_debug(rexec->event, "Finished executing %s action "
+ "(status=%s, keep=%s)", sieve_action_name(act),
+ sieve_execution_exitcode_to_str(status),
+ (act->keep ? "explicit" :
+ (impl_keep && rexec->keep_implicit ?
+ "implicit" : "canceled")));
+ }
+
+ if (status == SIEVE_EXEC_OK &&
+ (act->def->flags & SIEVE_ACTFLAG_TRIES_DELIVER) != 0)
+ rexec->seen_delivery = TRUE;
+
+ /* Update implicit keep status (but only when we're not running the
+ implicit keep right now). */
+ if (aexec != &rexec->keep)
+ rexec->keep_implicit = rexec->keep_implicit && impl_keep;
+
+ sieve_action_execution_post(rexec);
+
+ aexec->status = status;
+ return status;
+}
+
+static int
+sieve_result_action_commit(struct sieve_result_execution *rexec,
+ struct sieve_action_execution *aexec)
+{
+ struct sieve_result_action *rac = aexec->action;
+ struct sieve_action *act = &rac->action;
+ struct sieve_side_effect_execution *seexec;
+ int cstatus = SIEVE_EXEC_OK;
+
+ if (aexec == &rexec->keep) {
+ e_debug(rexec->event, "Commit implicit keep action");
+ } else {
+ e_debug(rexec->event, "Commit %s action%s",
+ sieve_action_name(act),
+ (act->keep ? " (explicit keep)" : ""));
+ }
+
+ sieve_action_execution_pre(rexec, aexec);
+
+ if (act->def->commit != NULL) {
+ cstatus = act->def->commit(&rexec->action_env,
+ aexec->tr_context);
+ if (cstatus == SIEVE_EXEC_OK)
+ rexec->committed = TRUE;
+ }
+
+ /* Execute post_commit event of side effects */
+ seexec = aexec->seffects_head;
+ while (seexec != NULL) {
+ sieve_result_side_effect_post_commit(
+ rexec, aexec, seexec, cstatus);
+ seexec = seexec->next;
+ }
+
+ sieve_action_execution_post(rexec);
+
+ return cstatus;
+}
+
+static void
+sieve_result_action_rollback(struct sieve_result_execution *rexec,
+ struct sieve_action_execution *aexec)
+{
+ struct sieve_result_action *rac = aexec->action;
+ struct sieve_action *act = &rac->action;
+ struct sieve_side_effect_execution *seexec;
+
+ if (aexec == &rexec->keep) {
+ e_debug(rexec->event, "Roll back implicit keep action");
+ } else {
+ e_debug(rexec->event, "Roll back %s action%s",
+ sieve_action_name(act),
+ (act->keep ? " (explicit keep)" : ""));
+ }
+
+ sieve_action_execution_pre(rexec, aexec);
+
+ if (act->def->rollback != NULL) {
+ act->def->rollback(&rexec->action_env, aexec->tr_context,
+ (aexec->status == SIEVE_EXEC_OK));
+ }
+
+ /* Rollback side effects */
+ seexec = aexec->seffects_head;
+ while (seexec != NULL) {
+ sieve_result_side_effect_rollback(rexec, aexec, seexec);
+ seexec = seexec->next;
+ }
+
+ sieve_action_execution_post(rexec);
+}
+
+static int
+sieve_result_action_commit_or_rollback(struct sieve_result_execution *rexec,
+ struct sieve_action_execution *aexec,
+ int status, int *commit_status)
+{
+ struct sieve_result_action *rac = aexec->action;
+ struct sieve_action *act = &rac->action;
+
+ /* Skip actions that are already finalized. */
+ if (aexec->state >= SIEVE_ACTION_EXECUTION_STATE_FINALIZED)
+ return status;
+ aexec->state = SIEVE_ACTION_EXECUTION_STATE_FINALIZED;
+
+ if (aexec == &rexec->keep) {
+ e_debug(rexec->event, "Finalize implicit keep action"
+ "(status=%s, action_status=%s, commit_status=%s)",
+ sieve_execution_exitcode_to_str(status),
+ sieve_execution_exitcode_to_str(aexec->status),
+ sieve_execution_exitcode_to_str(*commit_status));
+ } else {
+ e_debug(rexec->event, "Finalize %s action "
+ "(%sstatus=%s, action_status=%s, commit_status=%s, "
+ "pre-commit=%s)",
+ sieve_action_name(act),
+ (act->keep ? "explicit keep, " : ""),
+ sieve_execution_exitcode_to_str(status),
+ sieve_execution_exitcode_to_str(aexec->status),
+ sieve_execution_exitcode_to_str(*commit_status),
+ (aexec->commit ? "yes" : "no"));
+ }
+
+ /* Skip non-actions (inactive keep) */
+ if (act->def == NULL)
+ return status;
+
+ if (aexec->status == SIEVE_EXEC_OK &&
+ (status == SIEVE_EXEC_OK ||
+ (aexec->commit && *commit_status == SIEVE_EXEC_OK))) {
+ int cstatus = SIEVE_EXEC_OK;
+
+ cstatus = sieve_result_action_commit(rexec, aexec);
+ if (cstatus != SIEVE_EXEC_OK) {
+ /* This is bad; try to salvage as much as possible */
+ if (*commit_status == SIEVE_EXEC_OK) {
+ *commit_status = cstatus;
+ if (!rexec->committed) {
+ /* We haven't executed anything yet;
+ continue as rollback */
+ status = cstatus;
+ }
+ }
+ }
+ } else {
+ sieve_result_action_rollback(rexec, aexec);
+ }
+
+ if (act->keep) {
+ if (status == SIEVE_EXEC_FAILURE)
+ status = SIEVE_EXEC_KEEP_FAILED;
+ if (*commit_status == SIEVE_EXEC_FAILURE)
+ *commit_status = SIEVE_EXEC_KEEP_FAILED;
+ }
+
+ return status;
+}
+
+static void
+sieve_result_action_finish(struct sieve_result_execution *rexec,
+ struct sieve_action_execution *aexec, int status)
+{
+ struct sieve_result_action *rac = aexec->action;
+ struct sieve_action *act = &rac->action;
+
+ /* Skip non-actions (inactive keep) */
+ if (act->def == NULL)
+ return;
+
+ if (aexec == &rexec->keep) {
+ e_debug(rexec->event, "Finish implicit keep action");
+ } else {
+ e_debug(rexec->event, "Finish %s action%s",
+ sieve_action_name(act),
+ (act->keep ? " (explicit keep)" : ""));
+ }
+
+ if (act->def->finish != NULL) {
+ sieve_action_execution_pre(rexec, aexec);
+ act->def->finish(&rexec->action_env, aexec->tr_context, status);
+ sieve_action_execution_post(rexec);
+ }
+}
+
+static void
+sieve_result_action_abort(struct sieve_result_execution *rexec,
+ struct sieve_action_execution *aexec)
+{
+ if (aexec->state > SIEVE_ACTION_EXECUTION_STATE_INIT &&
+ aexec->state < SIEVE_ACTION_EXECUTION_STATE_FINALIZED)
+ sieve_result_action_rollback(rexec, aexec);
+ DLLIST2_REMOVE(&rexec->actions_head, &rexec->actions_tail, aexec);
+}
+
+static void
+sieve_action_execution_update(struct sieve_result_execution *rexec,
+ struct sieve_action_execution *aexec)
+{
+ const struct sieve_action_exec_env *aenv = &rexec->action_env;
+ struct sieve_result *result = aenv->result;
+ struct sieve_result_action *rac;
+
+ rac = result->actions_head;
+ while (rac != NULL) {
+ if (aexec->action == rac)
+ break;
+ rac = rac->next;
+ }
+
+ if (rac == NULL) {
+ /* Action was removed; abort it. */
+ sieve_result_action_abort(rexec, aexec);
+ return;
+ }
+
+ if (aexec->exec_seq != rac->action.exec_seq) {
+ i_assert(rac->action.keep);
+
+ /* Recycled keep */
+ aexec->exec_seq = rac->action.exec_seq;
+ aexec->state = SIEVE_ACTION_EXECUTION_STATE_INIT;
+ }
+
+ sieve_action_execution_add_side_effects(rexec, aexec, rac);
+}
+
+static void
+sieve_result_execution_add_action(struct sieve_result_execution *rexec,
+ struct sieve_result_action *rac)
+{
+ struct sieve_action_execution *aexec;
+
+ aexec = rexec->actions_head;
+ while (aexec != NULL) {
+ if (aexec->action == rac)
+ return;
+ aexec = aexec->next;
+ }
+
+ aexec = p_new(rexec->pool, struct sieve_action_execution, 1);
+ aexec->action = rac;
+ aexec->exec_seq = rac->action.exec_seq;
+ aexec->ehandler = rexec->ehandler;
+
+ DLLIST2_APPEND(&rexec->actions_head, &rexec->actions_tail, aexec);
+
+ sieve_action_execution_add_side_effects(rexec, aexec, rac);
+}
+
+/* Result */
+
+struct sieve_result_execution *
+sieve_result_execution_create(struct sieve_result *result, pool_t pool)
+{
+ struct sieve_result_execution *rexec;
+
+ pool_ref(pool);
+ rexec = p_new(pool, struct sieve_result_execution, 1);
+ rexec->pool = pool;
+ rexec->event = result->event;
+ rexec->action_env.result = result;
+ rexec->action_env.event = result->event;
+ rexec->action_env.exec_env = result->exec_env;
+ rexec->action_env.msgctx = result->msgctx;
+ rexec->status = SIEVE_EXEC_OK;
+ rexec->keep_success = TRUE;
+ rexec->keep_status = SIEVE_EXEC_OK;
+ rexec->keep_explicit = FALSE;
+ rexec->keep_implicit = TRUE;
+
+ sieve_result_ref(result);
+ result->exec = rexec;
+
+ return rexec;
+}
+
+void sieve_result_execution_destroy(struct sieve_result_execution **_rexec)
+{
+ struct sieve_result_execution *rexec = *_rexec;
+
+ *_rexec = NULL;
+
+ if (rexec == NULL)
+ return;
+
+ rexec->action_env.result->exec = NULL;
+ sieve_result_unref(&rexec->action_env.result);
+ pool_unref(&rexec->pool);
+}
+
+static void
+sieve_result_implicit_keep_execute(struct sieve_result_execution *rexec)
+{
+ const struct sieve_action_exec_env *aenv = &rexec->action_env;
+ struct sieve_result *result = aenv->result;
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_action_execution *aexec;
+ int status = SIEVE_EXEC_OK;
+ struct sieve_action_execution *aexec_keep = &rexec->keep;
+ struct sieve_result_action *ract_keep = &rexec->keep_action;
+ struct sieve_action *act_keep = &ract_keep->action;
+ bool success = FALSE;
+
+ switch (rexec->status) {
+ case SIEVE_EXEC_OK:
+ success = TRUE;
+ break;
+ case SIEVE_EXEC_TEMP_FAILURE:
+ case SIEVE_EXEC_RESOURCE_LIMIT:
+ if (rexec->committed) {
+ e_debug(rexec->event,
+ "Temporary failure occurred (status=%s), "
+ "but other actions were already committed: "
+ "execute failure implicit keep",
+ sieve_execution_exitcode_to_str(rexec->status));
+ break;
+ }
+ if (rexec->keep_finalizing)
+ break;
+
+ e_debug(rexec->event,
+ "Skip implicit keep for temporary failure "
+ "(state=execute, status=%s)",
+ sieve_execution_exitcode_to_str(rexec->status));
+ return;
+ default:
+ break;
+ }
+
+ if (rexec->keep_equiv_action != NULL) {
+ e_debug(rexec->event, "No implicit keep needed "
+ "(equivalent action already executed)");
+ return;
+ }
+
+ rexec->keep.action = &rexec->keep_action;
+ rexec->keep.ehandler = rexec->ehandler;
+ rexec->keep_success = success;
+ rexec->keep_status = status;
+
+ if ((eenv->flags & SIEVE_EXECUTE_FLAG_DEFER_KEEP) != 0) {
+ e_debug(rexec->event, "Execution of implicit keep is deferred");
+ return;
+ }
+
+ if (!success)
+ *act_keep = result->failure_action;
+ else
+ *act_keep = result->keep_action;
+ act_keep->name = "keep";
+ act_keep->mail = NULL;
+ act_keep->keep = TRUE;
+
+ /* If keep is a non-action, return right away */
+ if (act_keep->def == NULL) {
+ e_debug(rexec->event, "Keep is not defined yet");
+ return;
+ }
+
+ /* Scan for execution of keep-equal actions */
+ aexec = rexec->actions_head;
+ while (aexec != NULL) {
+ struct sieve_result_action *rac = aexec->action;
+
+ if (rac->action.def == act_keep->def &&
+ act_keep->def->equals != NULL &&
+ act_keep->def->equals(eenv->scriptenv, NULL,
+ &rac->action) &&
+ aexec->state >= SIEVE_ACTION_EXECUTION_STATE_EXECUTED) {
+ e_debug(rexec->event, "No implicit keep needed "
+ "(equivalent %s action already executed)",
+ sieve_action_name(&rac->action));
+ rexec->keep_equiv_action = aexec;
+ return;
+ }
+
+ aexec = aexec->next;
+ }
+
+ /* Scan for deferred keep */
+ aexec = rexec->actions_tail;
+ while (aexec != NULL) {
+ struct sieve_result_action *rac = aexec->action;
+
+ if (aexec->state < SIEVE_ACTION_EXECUTION_STATE_EXECUTED) {
+ aexec = NULL;
+ break;
+ }
+ if (rac->action.keep && rac->action.def == NULL)
+ break;
+ aexec = aexec->prev;
+ }
+
+ if (aexec == NULL) {
+ if (success)
+ act_keep->mail = sieve_message_get_mail(aenv->msgctx);
+ } else {
+ e_debug(rexec->event, "Found deferred keep action");
+
+ if (success) {
+ act_keep->location = aexec->action->action.location;
+ act_keep->mail = aexec->action->action.mail;
+ ract_keep->seffects = aexec->action->seffects;
+ }
+ aexec->state = SIEVE_ACTION_EXECUTION_STATE_FINALIZED;
+ }
+
+ if (ract_keep->seffects == NULL) {
+ /* Apply any implicit side effects if applicable */
+ if (success && hash_table_is_created(result->action_contexts)) {
+ struct sieve_result_action_context *actctx;
+
+ /* Check for implicit side effects to keep action */
+ actctx = hash_table_lookup(result->action_contexts,
+ act_keep->def);
+
+ if (actctx != NULL)
+ ract_keep->seffects = actctx->seffects;
+ }
+ }
+
+ e_debug(rexec->event, "Execute implicit keep (status=%s)",
+ sieve_execution_exitcode_to_str(rexec->status));
+
+ /* Initialize side effects */
+ sieve_action_execution_add_side_effects(rexec, aexec_keep, ract_keep);
+
+ /* Initialize keep action event */
+ sieve_result_init_action_event(result, act_keep, FALSE);
+
+ /* Start keep action */
+ status = sieve_result_action_start(rexec, aexec_keep);
+
+ /* Execute keep action */
+ if (status == SIEVE_EXEC_OK)
+ status = sieve_result_action_execute(rexec, aexec_keep, status);
+ if (status == SIEVE_EXEC_OK)
+ aexec_keep->commit = TRUE;
+
+ rexec->executed_delivery = rexec->seen_delivery;
+ rexec->keep_status = status;
+ sieve_action_execution_post(rexec);
+}
+
+static int
+sieve_result_implicit_keep_finalize(struct sieve_result_execution *rexec)
+{
+ const struct sieve_action_exec_env *aenv = &rexec->action_env;
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_action_execution *aexec_keep = &rexec->keep;
+ struct sieve_result_action *ract_keep = &rexec->keep_action;
+ struct sieve_action *act_keep = &ract_keep->action;
+ int commit_status = SIEVE_EXEC_OK;
+ bool success = FALSE, temp_failure = FALSE;
+
+ switch (rexec->status) {
+ case SIEVE_EXEC_OK:
+ success = TRUE;
+ break;
+ case SIEVE_EXEC_TEMP_FAILURE:
+ case SIEVE_EXEC_RESOURCE_LIMIT:
+ if (rexec->committed) {
+ e_debug(rexec->event,
+ "Temporary failure occurred (status=%s), "
+ "but other actions were already committed: "
+ "commit failure implicit keep",
+ sieve_execution_exitcode_to_str(rexec->status));
+ break;
+ }
+
+ if (aexec_keep->state !=
+ SIEVE_ACTION_EXECUTION_STATE_EXECUTED) {
+ e_debug(rexec->event,
+ "Skip implicit keep for temporary failure "
+ "(state=commit, status=%s)",
+ sieve_execution_exitcode_to_str(rexec->status));
+ return rexec->status;
+ }
+ /* Roll back for temporary failure when no other action
+ is committed. */
+ commit_status = rexec->status;
+ temp_failure = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ if ((eenv->flags & SIEVE_EXECUTE_FLAG_DEFER_KEEP) != 0) {
+ e_debug(rexec->event, "Execution of implicit keep is deferred");
+ return rexec->keep_status;
+ }
+
+ rexec->keep_finalizing = TRUE;
+
+ /* Start keep if necessary */
+ if (temp_failure) {
+ rexec->keep_status = rexec->status;
+ } else if (act_keep->def == NULL ||
+ aexec_keep->state != SIEVE_ACTION_EXECUTION_STATE_EXECUTED) {
+ sieve_result_implicit_keep_execute(rexec);
+ /* Switch to failure keep if necessary. */
+ } else if (rexec->keep_success && !success){
+ e_debug(rexec->event, "Switch to failure implicit keep");
+
+ /* Failed transaction, rollback success keep action. */
+ sieve_result_action_rollback(rexec, aexec_keep);
+
+ event_unref(&act_keep->event);
+ i_zero(aexec_keep);
+
+ /* Start failure keep action. */
+ sieve_result_implicit_keep_execute(rexec);
+ }
+ if (act_keep->def == NULL)
+ return rexec->keep_status;
+
+ if (rexec->keep_equiv_action != NULL) {
+ struct sieve_action_execution *ke_aexec =
+ rexec->keep_equiv_action;
+
+ i_assert(ke_aexec->state >=
+ SIEVE_ACTION_EXECUTION_STATE_FINALIZED);
+
+ e_debug(rexec->event, "No implicit keep needed "
+ "(equivalent %s action already finalized)",
+ sieve_action_name(&ke_aexec->action->action));
+ return ke_aexec->status;
+ }
+
+ e_debug(rexec->event, "Finalize implicit keep (status=%s)",
+ sieve_execution_exitcode_to_str(rexec->status));
+
+ i_assert(aexec_keep->state == SIEVE_ACTION_EXECUTION_STATE_EXECUTED);
+
+ /* Finalize keep action */
+ rexec->keep_status = sieve_result_action_commit_or_rollback(
+ rexec, aexec_keep, rexec->keep_status, &commit_status);
+
+ /* Finish keep action */
+ sieve_result_action_finish(rexec, aexec_keep,
+ rexec->keep_status);
+
+ sieve_action_execution_post(rexec);
+ event_unref(&act_keep->event);
+
+ if (rexec->keep_status == SIEVE_EXEC_FAILURE)
+ rexec->keep_status = SIEVE_EXEC_KEEP_FAILED;
+ return rexec->keep_status;
+}
+
+bool sieve_result_executed(struct sieve_result_execution *rexec)
+{
+ return rexec->executed;
+}
+
+bool sieve_result_committed(struct sieve_result_execution *rexec)
+{
+ return rexec->committed;
+}
+
+bool sieve_result_executed_delivery(struct sieve_result_execution *rexec)
+{
+ return rexec->executed_delivery;
+}
+
+static int sieve_result_transaction_start(struct sieve_result_execution *rexec)
+{
+ struct sieve_action_execution *aexec;
+ int status = SIEVE_EXEC_OK;
+
+ e_debug(rexec->event, "Starting execution of actions");
+
+ aexec = rexec->actions_head;
+ while (status == SIEVE_EXEC_OK && aexec != NULL) {
+ status = sieve_result_action_start(rexec, aexec);
+ aexec = aexec->next;
+ }
+ sieve_action_execution_post(rexec);
+
+ return status;
+}
+
+static int
+sieve_result_transaction_execute(struct sieve_result_execution *rexec,
+ int start_status)
+{
+ struct sieve_action_execution *aexec;
+ int status = SIEVE_EXEC_OK;
+
+ e_debug(rexec->event, "Executing actions");
+
+ rexec->seen_delivery = FALSE;
+ aexec = rexec->actions_head;
+ while (status == SIEVE_EXEC_OK && aexec != NULL) {
+ status = sieve_result_action_execute(rexec, aexec,
+ start_status);
+ aexec = aexec->next;
+ }
+ sieve_action_execution_post(rexec);
+
+ if (status == SIEVE_EXEC_OK) {
+ /* Since this execution series is successful so far, mark all
+ actions in it to be committed. */
+ aexec = rexec->actions_head;
+ while (aexec != NULL) {
+ aexec->commit = TRUE;
+ aexec = aexec->next;
+ }
+
+ rexec->executed_delivery =
+ rexec->executed_delivery || rexec->seen_delivery;
+ }
+
+ e_debug(rexec->event, "Finished executing actions "
+ "(status=%s, keep=%s, executed=%s)",
+ sieve_execution_exitcode_to_str(status),
+ (rexec->keep_explicit ? "explicit" :
+ (rexec->keep_implicit ? "implicit" : "none")),
+ (rexec->executed ? "yes" : "no"));
+ return status;
+}
+
+static int
+sieve_result_transaction_commit_or_rollback(
+ struct sieve_result_execution *rexec, int status)
+{
+ struct sieve_action_execution *aexec;
+ int commit_status = SIEVE_EXEC_OK;
+
+ switch (status) {
+ case SIEVE_EXEC_TEMP_FAILURE:
+ /* Roll back all actions */
+ commit_status = status;
+ break;
+ default:
+ break;
+ }
+
+ e_debug(rexec->event, "Finalizing actions");
+
+ /* First commit/rollback all storage actions */
+ aexec = rexec->actions_head;
+ while (aexec != NULL) {
+ struct sieve_result_action *rac = aexec->action;
+ struct sieve_action *act = &rac->action;
+
+ if (act->def == NULL ||
+ (act->def->flags & SIEVE_ACTFLAG_MAIL_STORAGE) == 0) {
+ aexec = aexec->next;
+ continue;
+ }
+
+ status = sieve_result_action_commit_or_rollback(
+ rexec, aexec, status, &commit_status);
+
+ aexec = aexec->next;
+ }
+
+ /* Then commit/rollback all other actions */
+ aexec = rexec->actions_head;
+ while (aexec != NULL) {
+ struct sieve_result_action *rac = aexec->action;
+ struct sieve_action *act = &rac->action;
+
+ if (act->def != NULL &&
+ (act->def->flags & SIEVE_ACTFLAG_MAIL_STORAGE) != 0) {
+ aexec = aexec->next;
+ continue;
+ }
+
+ status = sieve_result_action_commit_or_rollback(
+ rexec, aexec, status, &commit_status);
+
+ aexec = aexec->next;
+ }
+
+ e_debug(rexec->event, "Finished finalizing actions "
+ "(status=%s, keep=%s, committed=%s)",
+ sieve_execution_exitcode_to_str(status),
+ (rexec->keep_explicit ? "explicit" :
+ (rexec->keep_implicit ? "implicit" : "none")),
+ (rexec->committed ? "yes" : "no"));
+
+ return commit_status;
+}
+
+static void
+sieve_result_transaction_finish(struct sieve_result_execution *rexec,
+ int status)
+{
+ struct sieve_action_execution *aexec;
+
+ e_debug(rexec->event, "Finishing actions");
+
+ aexec = rexec->actions_head;
+ while (aexec != NULL) {
+ sieve_result_action_finish(rexec, aexec, status);
+ aexec = aexec->next;
+ }
+ sieve_action_execution_post(rexec);
+}
+
+static void
+sieve_result_execute_update_status(struct sieve_result_execution *rexec,
+ int status)
+{
+ switch (status) {
+ case SIEVE_EXEC_OK:
+ break;
+ case SIEVE_EXEC_TEMP_FAILURE:
+ rexec->status = status;
+ break;
+ case SIEVE_EXEC_BIN_CORRUPT:
+ i_unreached();
+ case SIEVE_EXEC_FAILURE:
+ case SIEVE_EXEC_KEEP_FAILED:
+ if (rexec->status == SIEVE_EXEC_OK)
+ rexec->status = status;
+ break;
+ case SIEVE_EXEC_RESOURCE_LIMIT:
+ if (rexec->status != SIEVE_EXEC_TEMP_FAILURE)
+ rexec->status = status;
+ break;
+ }
+}
+
+static void
+sieve_result_execution_update(struct sieve_result_execution *rexec)
+{
+ const struct sieve_action_exec_env *aenv = &rexec->action_env;
+ struct sieve_result *result = aenv->result;
+ struct sieve_action_execution *aexec;
+ struct sieve_result_action *rac;
+
+ aexec = rexec->actions_head;
+ while (aexec != NULL) {
+ struct sieve_action_execution *aexec_next = aexec->next;
+
+ sieve_action_execution_update(rexec, aexec);
+ aexec = aexec_next;
+ }
+
+ rac = result->actions_head;
+ while (rac != NULL) {
+ sieve_result_execution_add_action(rexec, rac);
+ rac = rac->next;
+ }
+}
+
+int sieve_result_execute(struct sieve_result_execution *rexec, int status,
+ bool commit, struct sieve_error_handler *ehandler,
+ bool *keep_r)
+{
+ const struct sieve_action_exec_env *aenv = &rexec->action_env;
+ struct sieve_result *result = aenv->result;
+ int result_status, ret;
+
+ e_debug(rexec->event, "Executing result (status=%s, commit=%s)",
+ sieve_execution_exitcode_to_str(status),
+ (commit ? "yes" : "no"));
+
+ if (keep_r != NULL)
+ *keep_r = FALSE;
+ sieve_result_mark_executed(result);
+
+ /* Prepare environment */
+
+ rexec->ehandler = ehandler;
+
+ /* Update actions in execution from result */
+
+ sieve_result_execution_update(rexec);
+
+ /* Transaction start and execute */
+
+ if (status != SIEVE_EXEC_OK) {
+ sieve_result_execute_update_status(rexec, status);
+ } else if (rexec->status == SIEVE_EXEC_OK) {
+ /* Transaction start */
+
+ status = sieve_result_transaction_start(rexec);
+
+ /* Transaction execute */
+
+ status = sieve_result_transaction_execute(rexec, status);
+ sieve_result_execute_update_status(rexec, status);
+ }
+
+ if (!commit) {
+ sieve_action_execution_post(rexec);
+ rexec->ehandler = NULL;
+
+ /* Merge explicit keep status into implicit keep for the next
+ execution round. */
+ rexec->keep_implicit = (rexec->keep_explicit ||
+ rexec->keep_implicit);
+ rexec->keep_explicit = FALSE;
+
+ e_debug(rexec->event, "Finished executing result "
+ "(no commit, status=%s, keep=%s)",
+ sieve_execution_exitcode_to_str(rexec->status),
+ (rexec->keep_implicit ? "yes" : "no"));
+
+ if (keep_r != NULL)
+ *keep_r = rexec->keep_implicit;
+ return rexec->status;
+ }
+
+ /* Execute implicit keep if the transaction failed or when the
+ implicit keep was not canceled during transaction.
+ */
+ if (rexec->status != SIEVE_EXEC_OK || rexec->keep_implicit)
+ sieve_result_implicit_keep_execute(rexec);
+
+ /* Transaction commit/rollback */
+
+ status = sieve_result_transaction_commit_or_rollback(rexec, status);
+ sieve_result_execute_update_status(rexec, status);
+
+ /* Commit implicit keep if necessary */
+
+ result_status = rexec->status;
+
+ /* Commit implicit keep if the transaction failed or when the
+ implicit keep was not canceled during transaction.
+ */
+ if (rexec->status != SIEVE_EXEC_OK || rexec->keep_implicit) {
+ ret = sieve_result_implicit_keep_finalize(rexec);
+ switch (ret) {
+ case SIEVE_EXEC_OK:
+ if (result_status == SIEVE_EXEC_TEMP_FAILURE)
+ result_status = SIEVE_EXEC_FAILURE;
+ break;
+ case SIEVE_EXEC_TEMP_FAILURE:
+ case SIEVE_EXEC_RESOURCE_LIMIT:
+ if (!rexec->committed) {
+ result_status = ret;
+ break;
+ }
+ /* fall through */
+ default:
+ result_status = SIEVE_EXEC_KEEP_FAILED;
+ }
+ }
+ if (rexec->status == SIEVE_EXEC_OK)
+ rexec->status = result_status;
+
+ /* Finish execution */
+
+ sieve_result_transaction_finish(rexec, rexec->status);
+
+ sieve_action_execution_post(rexec);
+ rexec->ehandler = NULL;
+
+ rexec->status = result_status;
+
+ /* Merge explicit keep status into implicit keep (in this case only for
+ completeness).
+ */
+ rexec->keep_implicit = (rexec->keep_explicit ||
+ rexec->keep_implicit);
+ rexec->keep_explicit = FALSE;
+
+ e_debug(rexec->event, "Finished executing result "
+ "(final, status=%s, keep=%s)",
+ sieve_execution_exitcode_to_str(result_status),
+ (rexec->keep_implicit ? "yes" : "no"));
+
+ if (keep_r != NULL)
+ *keep_r = rexec->keep_implicit;
+ return result_status;
+}
+
+/*
+ * Result evaluation
+ */
+
+struct sieve_result_iterate_context {
+ struct sieve_result *result;
+ struct sieve_result_action *current_action;
+ struct sieve_result_action *next_action;
+};
+
+struct sieve_result_iterate_context *
+sieve_result_iterate_init(struct sieve_result *result)
+{
+ struct sieve_result_iterate_context *rictx =
+ t_new(struct sieve_result_iterate_context, 1);
+
+ rictx->result = result;
+ rictx->current_action = NULL;
+ rictx->next_action = result->actions_head;
+
+ return rictx;
+}
+
+const struct sieve_action *
+sieve_result_iterate_next(struct sieve_result_iterate_context *rictx,
+ bool *keep)
+{
+ struct sieve_result_action *rac;
+
+ if (rictx == NULL)
+ return NULL;
+
+ rac = rictx->current_action = rictx->next_action;
+ if (rac != NULL) {
+ rictx->next_action = rac->next;
+
+ if (keep != NULL)
+ *keep = rac->action.keep;
+
+ return &rac->action;
+ }
+
+ return NULL;
+}
+
+void sieve_result_iterate_delete(struct sieve_result_iterate_context *rictx)
+{
+ struct sieve_result *result;
+ struct sieve_result_action *rac;
+
+ if (rictx == NULL || rictx->current_action == NULL)
+ return;
+
+ result = rictx->result;
+ rac = rictx->current_action;
+
+ /* Delete action */
+
+ if (rac->prev == NULL)
+ result->actions_head = rac->next;
+ else
+ rac->prev->next = rac->next;
+
+ if (rac->next == NULL)
+ result->actions_tail = rac->prev;
+ else
+ rac->next->prev = rac->prev;
+
+ sieve_result_action_deinit(rac);
+
+ /* Skip to next action in iteration */
+
+ rictx->current_action = NULL;
+}
+
+/*
+ * Side effects list
+ */
+
+struct sieve_side_effects_list *
+sieve_side_effects_list_create(struct sieve_result *result)
+{
+ struct sieve_side_effects_list *list =
+ p_new(result->pool, struct sieve_side_effects_list, 1);
+
+ list->result = result;
+ list->first_effect = NULL;
+ list->last_effect = NULL;
+
+ return list;
+}
+
+void sieve_side_effects_list_add(struct sieve_side_effects_list *list,
+ const struct sieve_side_effect *seffect)
+{
+ struct sieve_result_side_effect *reffect, *reffect_pos;
+
+ /* Prevent duplicates */
+ reffect = list->first_effect;
+ reffect_pos = NULL;
+ while (reffect != NULL) {
+ const struct sieve_side_effect_def *ref_def = reffect->seffect.def;
+ const struct sieve_side_effect_def *sef_def = seffect->def;
+
+ i_assert(ref_def != NULL);
+ i_assert(sef_def != NULL);
+
+ if (sef_def == ref_def) {
+ /* already listed */
+ i_assert(reffect_pos == NULL);
+ return;
+ }
+ if (sef_def->precedence > ref_def->precedence) {
+ /* insert it before this position */
+ reffect_pos = reffect;
+ }
+
+ reffect = reffect->next;
+ }
+
+ /* Create new side effect object */
+ reffect = p_new(list->result->pool, struct sieve_result_side_effect, 1);
+ reffect->seffect = *seffect;
+
+ if (reffect_pos != NULL) {
+ /* Insert */
+ reffect->next = reffect_pos;
+ reffect_pos->prev = reffect;
+ if (list->first_effect == reffect_pos)
+ list->first_effect = reffect;
+ } else {
+ /* Add */
+ if ( list->first_effect == NULL ) {
+ list->first_effect = reffect;
+ list->last_effect = reffect;
+ reffect->prev = NULL;
+ reffect->next = NULL;
+ } else {
+ list->last_effect->next = reffect;
+ reffect->prev = list->last_effect;
+ list->last_effect = reffect;
+ reffect->next = NULL;
+ }
+ }
+}
+
+/*
+ * Error handling
+ */
+
+#undef sieve_result_error
+void sieve_result_error(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_ERROR,
+ .event = aenv->event,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ va_start(args, fmt);
+ sieve_logv(aenv->ehandler, &params, fmt, args);
+ va_end(args);
+}
+
+#undef sieve_result_global_error
+void sieve_result_global_error(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename,
+ unsigned int csrc_linenum, const char *fmt, ...)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_ERROR,
+ .event = aenv->event,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ va_start(args, fmt);
+ sieve_global_logv(eenv->svinst, aenv->ehandler, &params, fmt, args);
+ va_end(args);
+}
+
+#undef sieve_result_warning
+void sieve_result_warning(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_WARNING,
+ .event = aenv->event,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ va_start(args, fmt);
+ sieve_logv(aenv->ehandler, &params, fmt, args);
+ va_end(args);
+}
+
+#undef sieve_result_global_warning
+void sieve_result_global_warning(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *fmt, ...)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_WARNING,
+ .event = aenv->event,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ va_start(args, fmt);
+ sieve_global_logv(eenv->svinst, aenv->ehandler, &params, fmt, args);
+ va_end(args);
+}
+
+#undef sieve_result_log
+void sieve_result_log(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *fmt, ...)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_error_params params = {
+ .log_type = (HAS_ALL_BITS(eenv->flags,
+ SIEVE_EXECUTE_FLAG_LOG_RESULT) ?
+ LOG_TYPE_INFO : LOG_TYPE_DEBUG),
+ .event = aenv->event,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ va_start(args, fmt);
+ sieve_logv(aenv->ehandler, &params, fmt, args);
+ va_end(args);
+}
+
+#undef sieve_result_global_log
+void sieve_result_global_log(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename,
+ unsigned int csrc_linenum, const char *fmt, ...)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_error_params params = {
+ .log_type = (HAS_ALL_BITS(eenv->flags,
+ SIEVE_EXECUTE_FLAG_LOG_RESULT) ?
+ LOG_TYPE_INFO : LOG_TYPE_DEBUG),
+ .event = aenv->event,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ va_start(args, fmt);
+ sieve_global_logv(eenv->svinst, aenv->ehandler, &params, fmt, args);
+ va_end(args);
+}
+
+#undef sieve_result_global_log_error
+void sieve_result_global_log_error(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *fmt, ...)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_ERROR,
+ .event = aenv->event,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ va_start(args, fmt);
+ sieve_global_info_logv(eenv->svinst, aenv->ehandler, &params,
+ fmt, args);
+ va_end(args);
+}
+
+#undef sieve_result_global_log_warning
+void sieve_result_global_log_warning(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *fmt, ...)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_WARNING,
+ .event = aenv->event,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ va_start(args, fmt);
+ sieve_global_info_logv(eenv->svinst, aenv->ehandler, &params,
+ fmt, args);
+ va_end(args);
+}
+
+#undef sieve_result_event_log
+void sieve_result_event_log(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename,
+ unsigned int csrc_linenum, struct event *event,
+ const char *fmt, ...)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_error_params params = {
+ .log_type = (HAS_ALL_BITS(eenv->flags,
+ SIEVE_EXECUTE_FLAG_LOG_RESULT) ?
+ LOG_TYPE_INFO : LOG_TYPE_DEBUG),
+ .event = event,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ va_start(args, fmt);
+ sieve_global_logv(eenv->svinst, aenv->ehandler, &params, fmt, args);
+ va_end(args);
+}
+
+
+#undef sieve_result_critical
+void sieve_result_critical(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *user_prefix, const char *fmt, ...)
+{
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_ERROR,
+ .event = aenv->event,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ va_start(args, fmt);
+
+ T_BEGIN {
+ sieve_criticalv(eenv->svinst, aenv->ehandler, &params,
+ user_prefix, fmt, args);
+ } T_END;
+
+ va_end(args);
+}
+
+#undef sieve_result_mail_error
+int sieve_result_mail_error(const struct sieve_action_exec_env *aenv,
+ struct mail *mail,
+ const char *csrc_filename,
+ unsigned int csrc_linenum, const char *fmt, ...)
+{
+ const char *error_msg, *user_prefix;
+ va_list args;
+
+ error_msg = mailbox_get_last_internal_error(mail->box, NULL);
+
+ va_start(args, fmt);
+ user_prefix = t_strdup_vprintf(fmt, args);
+ sieve_result_critical(aenv, csrc_filename, csrc_linenum,
+ user_prefix, "%s: %s", user_prefix, error_msg);
+ va_end(args);
+
+ return SIEVE_EXEC_TEMP_FAILURE;
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-result.h b/pigeonhole/src/lib-sieve/sieve-result.h
new file mode 100644
index 0000000..a9fcadc
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-result.h
@@ -0,0 +1,224 @@
+#ifndef SIEVE_RESULT_H
+#define SIEVE_RESULT_H
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-execute.h"
+
+/*
+ * Types
+ */
+
+struct sieve_side_effects_list;
+
+/*
+ * Result object
+ */
+
+struct sieve_result;
+
+struct sieve_result *
+sieve_result_create(struct sieve_instance *svinst, pool_t pool,
+ const struct sieve_execute_env *eenv);
+
+void sieve_result_ref(struct sieve_result *result);
+
+void sieve_result_unref(struct sieve_result **result);
+
+pool_t sieve_result_pool(struct sieve_result *result);
+
+/*
+ * Getters/Setters
+ */
+
+const struct sieve_script_env *
+sieve_result_get_script_env(struct sieve_result *result);
+const struct sieve_message_data *
+sieve_result_get_message_data(struct sieve_result *result);
+struct sieve_message_context *
+sieve_result_get_message_context(struct sieve_result *result);
+unsigned int sieve_result_get_exec_seq(struct sieve_result *result);
+
+/*
+ * Extension support
+ */
+
+void sieve_result_extension_set_context(struct sieve_result *result,
+ const struct sieve_extension *ext,
+ void *context);
+const void *
+sieve_result_extension_get_context(struct sieve_result *result,
+ const struct sieve_extension *ext);
+
+/*
+ * Result printing
+ */
+
+struct sieve_result_print_env {
+ struct sieve_result *result;
+ const struct sieve_script_env *scriptenv;
+ struct ostream *stream;
+};
+
+void sieve_result_vprintf(const struct sieve_result_print_env *penv,
+ const char *fmt, va_list args) ATTR_FORMAT(2, 0);
+void sieve_result_printf(const struct sieve_result_print_env *penv,
+ const char *fmt, ...) ATTR_FORMAT(2, 3);
+void sieve_result_action_printf(const struct sieve_result_print_env *penv,
+ const char *fmt, ...) ATTR_FORMAT(2, 3);
+void sieve_result_seffect_printf(const struct sieve_result_print_env *penv,
+ const char *fmt, ...) ATTR_FORMAT(2, 3);
+
+bool sieve_result_print(struct sieve_result *result,
+ const struct sieve_script_env *senv,
+ struct ostream *stream, bool *keep);
+
+/*
+ * Result composition
+ */
+
+void sieve_result_add_implicit_side_effect(
+ struct sieve_result *result, const struct sieve_action_def *to_action,
+ bool to_keep, const struct sieve_extension *ext,
+ const struct sieve_side_effect_def *seffect, void *context);
+
+int sieve_result_add_action(const struct sieve_runtime_env *renv,
+ const struct sieve_extension *ext, const char *name,
+ const struct sieve_action_def *act_def,
+ struct sieve_side_effects_list *seffects,
+ void *context, unsigned int instance_limit,
+ bool preserve_mail);
+int sieve_result_add_keep(const struct sieve_runtime_env *renv,
+ struct sieve_side_effects_list *seffects);
+
+void sieve_result_set_keep_action(struct sieve_result *result,
+ const struct sieve_extension *ext,
+ const struct sieve_action_def *act_def);
+void sieve_result_set_failure_action(struct sieve_result *result,
+ const struct sieve_extension *ext,
+ const struct sieve_action_def *act_def);
+
+/*
+ * Result execution
+ */
+
+struct sieve_result_execution;
+
+void sieve_result_mark_executed(struct sieve_result *result);
+
+struct sieve_result_execution *
+sieve_result_execution_create(struct sieve_result *result, pool_t pool);
+void sieve_result_execution_destroy(struct sieve_result_execution **_rexec);
+
+void *sieve_result_execution_get_dup_transaction(
+ struct sieve_result_execution *rexec);
+
+int sieve_result_execute(struct sieve_result_execution *rexec, int status,
+ bool commit, struct sieve_error_handler *ehandler,
+ bool *keep_r);
+
+bool sieve_result_executed(struct sieve_result_execution *rexec);
+bool sieve_result_committed(struct sieve_result_execution *rexec);
+
+bool sieve_result_executed_delivery(struct sieve_result_execution *rexec);
+
+/*
+ * Result evaluation
+ */
+
+struct sieve_result_iterate_context;
+
+struct sieve_result_iterate_context *
+sieve_result_iterate_init(struct sieve_result *result);
+const struct sieve_action *
+sieve_result_iterate_next(struct sieve_result_iterate_context *rictx,
+ bool *keep);
+void sieve_result_iterate_delete(struct sieve_result_iterate_context *rictx);
+
+/*
+ * Side effects list
+ */
+
+struct sieve_side_effects_list *
+sieve_side_effects_list_create(struct sieve_result *result);
+void sieve_side_effects_list_add(struct sieve_side_effects_list *list,
+ const struct sieve_side_effect *seffect);
+
+/*
+ * Error handling
+ */
+
+void sieve_result_error(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *fmt, ...)
+ ATTR_FORMAT(4, 5);
+#define sieve_result_error(aenv, ...) \
+ sieve_result_error(aenv, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_result_global_error(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename,
+ unsigned int csrc_linenum, const char *fmt, ...)
+ ATTR_FORMAT(4, 5);
+#define sieve_result_global_error(aenv, ...) \
+ sieve_result_global_error(aenv, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_result_warning(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *fmt, ...)
+ ATTR_FORMAT(4, 5);
+#define sieve_result_warning(aenv, ...) \
+ sieve_result_warning(aenv, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_result_global_warning(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *fmt, ...)
+ ATTR_FORMAT(4, 5);
+#define sieve_result_global_warning(aenv, ...) \
+ sieve_result_global_warning(aenv, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_result_log(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *fmt, ...)
+ ATTR_FORMAT(4, 5);
+#define sieve_result_log(aenv, ...) \
+ sieve_result_log(aenv, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_result_global_log(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename,
+ unsigned int csrc_linenum, const char *fmt, ...)
+ ATTR_FORMAT(4, 5);
+#define sieve_result_global_log(aenv, ...) \
+ sieve_result_global_log(aenv, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_result_global_log_error(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *fmt, ...)
+ ATTR_FORMAT(4, 5);
+#define sieve_result_global_log_error(aenv, ...) \
+ sieve_result_global_log_error(aenv, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_result_global_log_warning(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ const char *fmt, ...)
+ ATTR_FORMAT(4, 5);
+#define sieve_result_global_log_warning(aenv, ...) \
+ sieve_result_global_log_warning(aenv, __FILE__, __LINE__, __VA_ARGS__)
+
+void sieve_result_event_log(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename,
+ unsigned int csrc_linenum, struct event *event,
+ const char *fmt, ...) ATTR_FORMAT(5, 0);
+#define sieve_result_event_log(aenv, event, ...) \
+ sieve_result_event_log(aenv, __FILE__, __LINE__, event, __VA_ARGS__)
+
+void sieve_result_critical(const struct sieve_action_exec_env *aenv,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ const char *user_prefix, const char *fmt, ...)
+ ATTR_FORMAT(5, 6);
+#define sieve_result_critical(aenv, ...) \
+ sieve_result_critical(aenv, __FILE__, __LINE__, __VA_ARGS__)
+int sieve_result_mail_error(const struct sieve_action_exec_env *aenv,
+ struct mail *mail,
+ const char *csrc_filename,
+ unsigned int csrc_linenum, const char *fmt, ...)
+ ATTR_FORMAT(5, 6);
+#define sieve_result_mail_error(aenv, mail, ...) \
+ sieve_result_mail_error(aenv, mail, __FILE__, __LINE__, __VA_ARGS__)
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-runtime-trace.c b/pigeonhole/src/lib-sieve/sieve-runtime-trace.c
new file mode 100644
index 0000000..a9351a3
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-runtime-trace.c
@@ -0,0 +1,151 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "ostream.h"
+
+#include "sieve-common.h"
+#include "sieve-script.h"
+#include "sieve-binary.h"
+#include "sieve-code.h"
+#include "sieve-interpreter.h"
+#include "sieve-runtime.h"
+#include "sieve-runtime-trace.h"
+
+static inline string_t *_trace_line_new
+(const struct sieve_runtime_env *renv, sieve_size_t address, unsigned int cmd_line)
+{
+ string_t *trline;
+ unsigned int i;
+
+ trline = t_str_new(128);
+ if ( (renv->trace->config.flags & SIEVE_TRFLG_ADDRESSES) > 0 )
+ str_printfa(trline, "%08llx: ", (unsigned long long) address);
+ if ( cmd_line > 0 )
+ str_printfa(trline, "%4d: ", cmd_line);
+ else
+ str_append(trline, " ");
+
+ for ( i = 0; i < renv->trace->indent; i++ )
+ str_append(trline, " ");
+
+ return trline;
+}
+
+static inline void _trace_line_print
+(string_t *trline, const struct sieve_runtime_env *renv)
+{
+ sieve_trace_log_write_line(renv->trace->log, trline);
+}
+
+static inline void _trace_line_print_empty
+(const struct sieve_runtime_env *renv)
+{
+ sieve_trace_log_write_line(renv->trace->log, NULL);
+}
+
+/*
+ * Trace errors
+ */
+
+void _sieve_runtime_trace_error
+(const struct sieve_runtime_env *renv, const char *fmt, va_list args)
+{
+ string_t *trline = _trace_line_new(renv, renv->pc, 0);
+
+ str_printfa(trline, "%s: #ERROR#: ", sieve_operation_mnemonic(renv->oprtn));
+ str_vprintfa(trline, fmt, args);
+
+ _trace_line_print(trline, renv);
+}
+
+void _sieve_runtime_trace_operand_error
+(const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ const char *fmt, va_list args)
+{
+ string_t *trline = _trace_line_new(renv, oprnd->address,
+ sieve_runtime_get_source_location(renv, oprnd->address));
+
+ str_printfa(trline, "%s: #ERROR#: ", sieve_operation_mnemonic(renv->oprtn));
+
+ if ( oprnd->field_name != NULL )
+ str_printfa(trline, "%s: ", oprnd->field_name);
+
+ str_vprintfa(trline, fmt, args);
+
+ _trace_line_print(trline, renv);
+}
+
+/*
+ * Trace info
+ */
+
+static inline void ATTR_FORMAT(4, 0) _sieve_runtime_trace_vprintf
+(const struct sieve_runtime_env *renv, sieve_size_t address,
+ unsigned int cmd_line, const char *fmt, va_list args)
+{
+ string_t *trline = _trace_line_new(renv, address, cmd_line);
+
+ str_vprintfa(trline, fmt, args);
+
+ _trace_line_print(trline, renv);
+}
+
+static inline void ATTR_FORMAT(4, 5) _sieve_runtime_trace_printf
+(const struct sieve_runtime_env *renv, sieve_size_t address,
+ unsigned int cmd_line, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ _sieve_runtime_trace_vprintf(renv, address, cmd_line, fmt, args);
+ va_end(args);
+}
+
+void ATTR_FORMAT(2, 0) _sieve_runtime_trace
+(const struct sieve_runtime_env *renv, const char *fmt, va_list args)
+{
+ _sieve_runtime_trace_vprintf
+ (renv, renv->oprtn->address, sieve_runtime_get_command_location(renv),
+ fmt, args);
+}
+
+void _sieve_runtime_trace_address
+(const struct sieve_runtime_env *renv, sieve_size_t address,
+ const char *fmt, va_list args)
+{
+ _sieve_runtime_trace_vprintf
+ (renv, address, sieve_runtime_get_source_location(renv, address), fmt,
+ args);
+}
+
+/*
+ * Trace boundaries
+ */
+
+void _sieve_runtime_trace_begin(const struct sieve_runtime_env *renv)
+{
+ const char *script_name = ( renv->script != NULL ?
+ sieve_script_name(renv->script) : sieve_binary_path(renv->sbin) );
+
+ _trace_line_print_empty(renv);
+ _sieve_runtime_trace_printf(renv, renv->pc, 0,
+ "## Started executing script '%s'", script_name);
+}
+
+void _sieve_runtime_trace_end(const struct sieve_runtime_env *renv)
+{
+ const char *script_name = ( renv->script != NULL ?
+ sieve_script_name(renv->script) : sieve_binary_path(renv->sbin) );
+
+ _sieve_runtime_trace_printf(renv, renv->pc, 0,
+ "## Finished executing script '%s'", script_name);
+ _trace_line_print_empty(renv);
+}
+
+void _sieve_runtime_trace_sep(const struct sieve_runtime_env *renv)
+{
+ _trace_line_print_empty(renv);
+}
+
diff --git a/pigeonhole/src/lib-sieve/sieve-runtime-trace.h b/pigeonhole/src/lib-sieve/sieve-runtime-trace.h
new file mode 100644
index 0000000..b165586
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-runtime-trace.h
@@ -0,0 +1,182 @@
+#ifndef SIEVE_RUNTIME_TRACE_H
+#define SIEVE_RUNTIME_TRACE_H
+
+#include "sieve-common.h"
+#include "sieve-runtime.h"
+
+/*
+ * Runtime trace
+ */
+
+struct sieve_runtime_trace {
+ struct sieve_trace_config config;
+ struct sieve_trace_log *log;
+ unsigned int indent;
+};
+
+/* Trace configuration */
+
+static inline bool sieve_runtime_trace_active
+(const struct sieve_runtime_env *renv, sieve_trace_level_t trace_level)
+{
+ return ( renv->trace != NULL && trace_level <= renv->trace->config.level );
+}
+
+static inline bool sieve_runtime_trace_hasflag
+(const struct sieve_runtime_env *renv, unsigned int flag)
+{
+ return ( renv->trace != NULL && (renv->trace->config.flags & flag) != 0 );
+}
+
+/* Trace indent */
+
+static inline void sieve_runtime_trace_descend
+(const struct sieve_runtime_env *renv)
+{
+ if ( renv->trace != NULL ) renv->trace->indent++;
+}
+
+static inline void sieve_runtime_trace_ascend
+(const struct sieve_runtime_env *renv)
+{
+ if ( renv->trace != NULL ) renv->trace->indent--;
+}
+
+static inline void sieve_runtime_trace_toplevel
+(const struct sieve_runtime_env *renv)
+{
+ if ( renv->trace != NULL ) renv->trace->indent = 0;
+}
+
+/* Trace errors */
+
+void _sieve_runtime_trace_error
+ (const struct sieve_runtime_env *renv, const char *fmt, va_list args)
+ ATTR_FORMAT(2, 0);
+
+void _sieve_runtime_trace_operand_error
+ (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ const char *fmt, va_list args) ATTR_FORMAT(3, 0);
+
+static inline void sieve_runtime_trace_error
+ (const struct sieve_runtime_env *renv, const char *fmt, ...)
+ ATTR_FORMAT(2, 3);
+
+static inline void sieve_runtime_trace_operand_error
+ (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ const char *fmt, ...) ATTR_FORMAT(3, 4);
+
+static inline void ATTR_FORMAT(2, 3) sieve_runtime_trace_error
+ (const struct sieve_runtime_env *renv, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ if ( renv->trace != NULL )
+ _sieve_runtime_trace_error(renv, fmt, args);
+ va_end(args);
+}
+
+static inline void ATTR_FORMAT(3, 4) sieve_runtime_trace_operand_error
+ (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ if ( renv->trace != NULL )
+ _sieve_runtime_trace_operand_error(renv, oprnd, fmt, args);
+ va_end(args);
+}
+
+/* Trace info */
+
+void _sieve_runtime_trace
+ (const struct sieve_runtime_env *renv, const char *fmt, va_list args)
+ ATTR_FORMAT(2, 0);
+
+static inline void sieve_runtime_trace
+ (const struct sieve_runtime_env *renv, sieve_trace_level_t trace_level,
+ const char *fmt, ...) ATTR_FORMAT(3, 4);
+
+static inline void ATTR_FORMAT(3, 4) sieve_runtime_trace
+(const struct sieve_runtime_env *renv, sieve_trace_level_t trace_level,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+
+ if ( renv->trace != NULL && trace_level <= renv->trace->config.level ) {
+ _sieve_runtime_trace(renv, fmt, args);
+ }
+
+ va_end(args);
+}
+
+void _sieve_runtime_trace_address
+ (const struct sieve_runtime_env *renv, sieve_size_t address,
+ const char *fmt, va_list args) ATTR_FORMAT(3, 0);
+
+static inline void sieve_runtime_trace_address
+ (const struct sieve_runtime_env *renv, sieve_trace_level_t trace_level,
+ sieve_size_t address, const char *fmt, ...) ATTR_FORMAT(4, 5);
+
+static inline void ATTR_FORMAT(4, 5) sieve_runtime_trace_address
+(const struct sieve_runtime_env *renv, sieve_trace_level_t trace_level,
+ sieve_size_t address, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+
+ if ( renv->trace != NULL && trace_level <= renv->trace->config.level ) {
+ _sieve_runtime_trace_address(renv, address, fmt, args);
+ }
+
+ va_end(args);
+}
+
+static inline void ATTR_FORMAT(3, 4) sieve_runtime_trace_here
+(const struct sieve_runtime_env *renv, sieve_trace_level_t trace_level,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+
+ if ( renv->trace != NULL && trace_level <= renv->trace->config.level ) {
+ _sieve_runtime_trace_address(renv, renv->pc, fmt, args);
+ }
+
+ va_end(args);
+}
+
+/* Trace boundaries */
+
+void _sieve_runtime_trace_begin(const struct sieve_runtime_env *renv);
+void _sieve_runtime_trace_end(const struct sieve_runtime_env *renv);
+void _sieve_runtime_trace_sep(const struct sieve_runtime_env *renv);
+
+static inline void sieve_runtime_trace_begin
+(const struct sieve_runtime_env *renv)
+{
+ if ( renv->trace != NULL )
+ _sieve_runtime_trace_begin(renv);
+}
+
+static inline void sieve_runtime_trace_end
+(const struct sieve_runtime_env *renv)
+{
+ if ( renv->trace != NULL )
+ _sieve_runtime_trace_end(renv);
+}
+
+static inline void sieve_runtime_trace_sep
+(const struct sieve_runtime_env *renv)
+{
+ if ( renv->trace != NULL )
+ _sieve_runtime_trace_sep(renv);
+}
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-runtime.h b/pigeonhole/src/lib-sieve/sieve-runtime.h
new file mode 100644
index 0000000..fa50602
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-runtime.h
@@ -0,0 +1,40 @@
+#ifndef SIEVE_RUNTIME_H
+#define SIEVE_RUNTIME_H
+
+#include "sieve-common.h"
+#include "sieve-execute.h"
+
+/*
+ * Runtime environment
+ */
+
+struct sieve_runtime_env {
+ const struct sieve_execute_env *exec_env;
+ struct event *event;
+
+ /* Interpreter */
+ struct sieve_interpreter *interp;
+ struct sieve_error_handler *ehandler;
+
+ /* Executing script */
+ struct sieve_script *script;
+
+ /* Executing binary */
+ struct sieve_binary *sbin;
+ struct sieve_binary_block *sblock;
+
+ /* Current code */
+ sieve_size_t pc;
+ const struct sieve_operation *oprtn;
+
+ /* Tested message */
+ struct sieve_message_context *msgctx;
+
+ /* Filter result */
+ struct sieve_result *result;
+
+ /* Runtime tracing */
+ struct sieve_runtime_trace *trace;
+};
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-script-private.h b/pigeonhole/src/lib-sieve/sieve-script-private.h
new file mode 100644
index 0000000..7f23c19
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-script-private.h
@@ -0,0 +1,100 @@
+#ifndef SIEVE_SCRIPT_PRIVATE_H
+#define SIEVE_SCRIPT_PRIVATE_H
+
+#include "sieve-common.h"
+#include "sieve-script.h"
+
+/*
+ * Script object
+ */
+
+struct sieve_script_vfuncs {
+ void (*destroy)(struct sieve_script *script);
+
+ int (*open)(struct sieve_script *script, enum sieve_error *error_r);
+
+ int (*get_stream)(struct sieve_script *script,
+ struct istream **stream_r, enum sieve_error *error_r);
+
+ /* binary */
+ int (*binary_read_metadata)(struct sieve_script *_script,
+ struct sieve_binary_block *sblock,
+ sieve_size_t *offset);
+ void (*binary_write_metadata)(struct sieve_script *script,
+ struct sieve_binary_block *sblock);
+ bool (*binary_dump_metadata)(struct sieve_script *script,
+ struct sieve_dumptime_env *denv,
+ struct sieve_binary_block *sblock,
+ sieve_size_t *offset);
+ struct sieve_binary *(*binary_load)(struct sieve_script *script,
+ enum sieve_error *error_r);
+ int (*binary_save)(struct sieve_script *script,
+ struct sieve_binary *sbin, bool update,
+ enum sieve_error *error_r);
+ const char *(*binary_get_prefix)(struct sieve_script *script);
+
+ /* management */
+ int (*rename)(struct sieve_script *script, const char *newname);
+ int (*delete)(struct sieve_script *script);
+ int (*is_active)(struct sieve_script *script);
+ int (*activate)(struct sieve_script *script);
+
+ /* properties */
+ int (*get_size)(const struct sieve_script *script, uoff_t *size_r);
+
+ /* matching */
+ bool (*equals)(const struct sieve_script *script,
+ const struct sieve_script *other);
+};
+
+struct sieve_script {
+ pool_t pool;
+ unsigned int refcount;
+ struct sieve_storage *storage;
+ struct event *event;
+
+ const char *driver_name;
+ const struct sieve_script *script_class;
+ struct sieve_script_vfuncs v;
+
+ const char *name;
+ const char *location;
+
+ /* Stream */
+ struct istream *stream;
+
+ bool open:1;
+};
+
+void sieve_script_init(struct sieve_script *script,
+ struct sieve_storage *storage,
+ const struct sieve_script *script_class,
+ const char *location, const char *name);
+
+/*
+ * Built-in script drivers
+ */
+
+extern const struct sieve_script sieve_data_script;
+extern const struct sieve_script sieve_file_script;
+extern const struct sieve_script sieve_dict_script;
+extern const struct sieve_script sieve_ldap_script;
+
+/*
+ * Error handling
+ */
+
+void sieve_script_set_error(struct sieve_script *script, enum sieve_error error,
+ const char *fmt, ...) ATTR_FORMAT(3, 4);
+void sieve_script_set_internal_error(struct sieve_script *script);
+void sieve_script_set_critical(struct sieve_script *script,
+ const char *fmt, ...) ATTR_FORMAT(2, 3);
+
+/*
+ * Script sequence
+ */
+
+void sieve_script_sequence_init(struct sieve_script_sequence *seq,
+ struct sieve_storage *storage);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-script.c b/pigeonhole/src/lib-sieve/sieve-script.c
new file mode 100644
index 0000000..32963a0
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-script.c
@@ -0,0 +1,906 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "compat.h"
+#include "unichar.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "hash.h"
+#include "array.h"
+#include "eacces-error.h"
+#include "istream.h"
+
+#include "sieve-common.h"
+#include "sieve-limits.h"
+#include "sieve-settings.h"
+#include "sieve-error.h"
+#include "sieve-dump.h"
+#include "sieve-binary.h"
+
+#include "sieve-storage-private.h"
+#include "sieve-script-private.h"
+
+/*
+ * Script name
+ */
+
+bool sieve_script_name_is_valid(const char *scriptname)
+{
+ ARRAY_TYPE(unichars) uni_name;
+ unsigned int count, i;
+ const unichar_t *name_chars;
+ size_t namelen = strlen(scriptname);
+
+ /* Check minimum length */
+ if (namelen == 0)
+ return FALSE;
+
+ /* Check worst-case maximum length */
+ if (namelen > SIEVE_MAX_SCRIPT_NAME_LEN * 4)
+ return FALSE;
+
+ /* Intialize array for unicode characters */
+ t_array_init(&uni_name, namelen * 4);
+
+ /* Convert UTF-8 to UCS4/UTF-32 */
+ if (uni_utf8_to_ucs4(scriptname, &uni_name) < 0)
+ return FALSE;
+ name_chars = array_get(&uni_name, &count);
+
+ /* Check true maximum length */
+ if (count > SIEVE_MAX_SCRIPT_NAME_LEN)
+ return FALSE;
+
+ /* Scan name for invalid characters
+ * FIXME: compliance with Net-Unicode Definition (Section 2 of
+ * RFC 5198) is not checked fully and no normalization
+ * is performed.
+ */
+ for (i = 0; i < count; i++) {
+ /* 0000-001F; [CONTROL CHARACTERS] */
+ if (name_chars[i] <= 0x001f)
+ return FALSE;
+ /* 002F; SLASH (not RFC-prohibited, but '/' is dangerous) */
+ if (name_chars[i] == 0x002f)
+ return FALSE;
+ /* 007F; DELETE */
+ if (name_chars[i] == 0x007f)
+ return FALSE;
+ /* 0080-009F; [CONTROL CHARACTERS] */
+ if (name_chars[i] >= 0x0080 && name_chars[i] <= 0x009f)
+ return FALSE;
+ /* 00FF */
+ if (name_chars[i] == 0x00ff)
+ return FALSE;
+ /* 2028; LINE SEPARATOR */
+ /* 2029; PARAGRAPH SEPARATOR */
+ if (name_chars[i] == 0x2028 || name_chars[i] == 0x2029)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Script instance
+ */
+
+void sieve_script_init(struct sieve_script *script,
+ struct sieve_storage *storage,
+ const struct sieve_script *script_class,
+ const char *location, const char *name)
+{
+ i_assert(storage != NULL);
+
+ script->script_class = script_class;
+ script->refcount = 1;
+ script->storage = storage;
+ script->location = p_strdup_empty(script->pool, location);
+ script->name = p_strdup(script->pool, name);
+
+ script->event = event_create(storage->event);
+ event_add_str(script->event, "script_name", name);
+ event_add_str(script->event, "script_location", location);
+ if (name == NULL)
+ event_set_append_log_prefix(script->event, "script: ");
+ else {
+ event_set_append_log_prefix(
+ script->event, t_strdup_printf("script `%s': ", name));
+ }
+
+ sieve_storage_ref(storage);
+}
+
+struct sieve_script *
+sieve_script_create(struct sieve_instance *svinst, const char *location,
+ const char *name, enum sieve_error *error_r)
+{
+ struct sieve_storage *storage;
+ struct sieve_script *script;
+ enum sieve_error error;
+
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NONE;
+ else
+ error_r = &error;
+
+ storage = sieve_storage_create(svinst, location, 0, error_r);
+ if (storage == NULL)
+ return NULL;
+
+ script = sieve_storage_get_script(storage, name, error_r);
+
+ sieve_storage_unref(&storage);
+ return script;
+}
+
+void sieve_script_ref(struct sieve_script *script)
+{
+ script->refcount++;
+}
+
+void sieve_script_unref(struct sieve_script **_script)
+{
+ struct sieve_script *script = *_script;
+
+ *_script = NULL;
+
+ if (script == NULL)
+ return;
+
+ i_assert(script->refcount > 0);
+ if (--script->refcount != 0)
+ return;
+
+ if (script->stream != NULL) {
+ struct event_passthrough *e =
+ event_create_passthrough(script->event)->
+ set_name("sieve_script_closed");
+ e_debug(e->event(), "Closed script");
+ }
+ i_stream_unref(&script->stream);
+
+ if (script->v.destroy != NULL)
+ script->v.destroy(script);
+
+ sieve_storage_unref(&script->storage);
+ event_unref(&script->event);
+ pool_unref(&script->pool);
+}
+
+int sieve_script_open(struct sieve_script *script, enum sieve_error *error_r)
+{
+ enum sieve_error error;
+
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NONE;
+ else
+ error_r = &error;
+
+ if (script->open)
+ return 0;
+
+ if (script->v.open(script, error_r) < 0)
+ return -1;
+
+ i_assert(script->location != NULL);
+ i_assert(script->name != NULL);
+ script->open = TRUE;
+
+ if (*script->name != '\0') {
+ e_debug(script->event, "Opened script `%s' from `%s'",
+ script->name, script->location);
+ } else {
+ e_debug(script->event, "Opened nameless script from `%s'",
+ script->location);
+ }
+ return 0;
+}
+
+int sieve_script_open_as(struct sieve_script *script, const char *name,
+ enum sieve_error *error_r)
+{
+ if (sieve_script_open(script, error_r) < 0)
+ return -1;
+
+ /* override name */
+ script->name = p_strdup(script->pool, name);
+ event_add_str(script->event, "script_name", name);
+ return 0;
+}
+
+struct sieve_script *
+sieve_script_create_open(struct sieve_instance *svinst, const char *location,
+ const char *name, enum sieve_error *error_r)
+{
+ struct sieve_script *script;
+
+ script = sieve_script_create(svinst, location, name, error_r);
+ if (script == NULL)
+ return NULL;
+
+ if (sieve_script_open(script, error_r) < 0) {
+ sieve_script_unref(&script);
+ return NULL;
+ }
+
+ return script;
+}
+
+int sieve_script_check(struct sieve_instance *svinst, const char *location,
+ const char *name, enum sieve_error *error_r)
+{
+ struct sieve_script *script;
+ enum sieve_error error;
+
+ if (error_r == NULL)
+ error_r = &error;
+
+ script = sieve_script_create_open(svinst, location, name, error_r);
+ if (script == NULL)
+ return (*error_r == SIEVE_ERROR_NOT_FOUND ? 0 : -1);
+
+ sieve_script_unref(&script);
+ return 1;
+}
+
+/*
+ * Properties
+ */
+
+const char *sieve_script_name(const struct sieve_script *script)
+{
+ return script->name;
+}
+
+const char *sieve_script_location(const struct sieve_script *script)
+{
+ return script->location;
+}
+
+struct sieve_instance *sieve_script_svinst(const struct sieve_script *script)
+{
+ return script->storage->svinst;
+}
+
+int sieve_script_get_size(struct sieve_script *script, uoff_t *size_r)
+{
+ struct istream *stream;
+ int ret;
+
+ if (script->v.get_size != NULL) {
+ if ((ret = script->v.get_size(script, size_r)) != 0)
+ return ret;
+ }
+
+ /* Try getting size from the stream */
+ if (script->stream == NULL &&
+ sieve_script_get_stream(script, &stream, NULL) < 0)
+ return -1;
+
+ if (i_stream_get_size(script->stream, TRUE, size_r) < 0) {
+ sieve_storage_set_critical(script->storage,
+ "i_stream_get_size(%s) failed: %s",
+ i_stream_get_name(script->stream),
+ i_stream_get_error(script->stream));
+ return -1;
+ }
+ return 0;
+}
+
+bool sieve_script_is_open(const struct sieve_script *script)
+{
+ return script->open;
+}
+
+bool sieve_script_is_default(const struct sieve_script *script)
+{
+ return script->storage->is_default;
+}
+
+/*
+ * Stream management
+ */
+
+int sieve_script_get_stream(struct sieve_script *script,
+ struct istream **stream_r,
+ enum sieve_error *error_r)
+{
+ struct sieve_storage *storage = script->storage;
+ enum sieve_error error;
+ int ret;
+
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NONE;
+ else
+ error_r = &error;
+
+ if (script->stream != NULL) {
+ *stream_r = script->stream;
+ return 0;
+ }
+
+ // FIXME: necessary?
+ i_assert(script->open);
+
+ T_BEGIN {
+ ret = script->v.get_stream(script, &script->stream, error_r);
+ } T_END;
+
+ if (ret < 0) {
+ struct event_passthrough *e =
+ event_create_passthrough(script->event)->
+ add_str("error", storage->error)->
+ set_name("sieve_script_opened");
+ e_debug(e->event(), "Failed to open script for reading: %s",
+ storage->error);
+ return -1;
+ }
+
+ struct event_passthrough *e =
+ event_create_passthrough(script->event)->
+ set_name("sieve_script_opened");
+ e_debug(e->event(), "Opened script for reading");
+
+ *stream_r = script->stream;
+ return 0;
+}
+
+/*
+ * Comparison
+ */
+
+bool sieve_script_equals(const struct sieve_script *script,
+ const struct sieve_script *other)
+{
+ if (script == other)
+ return TRUE;
+ if (script == NULL || other == NULL)
+ return FALSE;
+ if (script->script_class != other->script_class)
+ return FALSE;
+
+ if (script->v.equals == NULL) {
+ i_assert (script->location != NULL && other->location != NULL);
+
+ return (strcmp(script->location, other->location) == 0);
+ }
+
+ return script->v.equals(script, other);
+}
+
+unsigned int sieve_script_hash(const struct sieve_script *script)
+{
+ i_assert(script->name != NULL);
+
+ return str_hash(script->name);
+}
+
+/*
+ * Binary
+ */
+
+int sieve_script_binary_read_metadata(struct sieve_script *script,
+ struct sieve_binary_block *sblock,
+ sieve_size_t *offset)
+{
+ struct sieve_binary *sbin = sieve_binary_block_get_binary(sblock);
+ string_t *storage_class, *location;
+ unsigned int version;
+
+ if ((sieve_binary_block_get_size(sblock) - *offset) == 0)
+ return 0;
+
+ /* storage class */
+ if (!sieve_binary_read_string(sblock, offset, &storage_class)) {
+ e_error(script->event,
+ "Binary `%s' has invalid metadata for script `%s': "
+ "Invalid storage class",
+ sieve_binary_path(sbin), script->location);
+ return -1;
+ }
+ if (strcmp(str_c(storage_class), script->driver_name) != 0) {
+ e_debug(script->event,
+ "Binary `%s' reports unexpected driver name for script `%s' "
+ "(`%s' rather than `%s')",
+ sieve_binary_path(sbin), script->location,
+ str_c(storage_class), script->driver_name);
+ return 0;
+ }
+
+ /* version */
+ if (!sieve_binary_read_unsigned(sblock, offset, &version)) {
+ e_error(script->event,
+ "Binary `%s' has invalid metadata for script `%s': "
+ "Invalid version",
+ sieve_binary_path(sbin), script->location);
+ return -1;
+ }
+ if (script->storage->version != version) {
+ e_debug(script->event,
+ "Binary `%s' was compiled with "
+ "a different version of the `%s' script storage class "
+ "(compiled v%d, expected v%d; "
+ "automatically fixed when re-compiled)",
+ sieve_binary_path(sbin), script->driver_name,
+ version, script->storage->version);
+ return 0;
+ }
+
+ /* location */
+ if (!sieve_binary_read_string(sblock, offset, &location)) {
+ e_error(script->event,
+ "Binary `%s' has invalid metadata for script `%s': "
+ "Invalid location",
+ sieve_binary_path(sbin), script->location);
+ return -1;
+ }
+ i_assert(script->location != NULL);
+ if (strcmp(str_c(location), script->location) != 0) {
+ e_debug(script->event,
+ "Binary `%s' reports different location "
+ "for script `%s' (binary points to `%s')",
+ sieve_binary_path(sbin), script->location,
+ str_c(location));
+ return 0;
+ }
+
+ if (script->v.binary_read_metadata == NULL)
+ return 1;
+
+ return script->v.binary_read_metadata(script, sblock, offset);
+}
+
+void sieve_script_binary_write_metadata(struct sieve_script *script,
+ struct sieve_binary_block *sblock)
+{
+ sieve_binary_emit_cstring(sblock, script->driver_name);
+ sieve_binary_emit_unsigned(sblock, script->storage->version);
+ sieve_binary_emit_cstring(sblock, (script->location == NULL ?
+ "" : script->location));
+
+ if (script->v.binary_write_metadata == NULL)
+ return;
+
+ script->v.binary_write_metadata(script, sblock);
+}
+
+bool sieve_script_binary_dump_metadata(struct sieve_script *script,
+ struct sieve_dumptime_env *denv,
+ struct sieve_binary_block *sblock,
+ sieve_size_t *offset)
+{
+ struct sieve_binary *sbin = sieve_binary_block_get_binary(sblock);
+ struct sieve_instance *svinst = sieve_binary_svinst(sbin);
+ string_t *storage_class, *location;
+ struct sieve_script *adhoc_script = NULL;
+ unsigned int version;
+ bool result = TRUE;
+
+ /* storage class */
+ if (!sieve_binary_read_string(sblock, offset, &storage_class))
+ return FALSE;
+ sieve_binary_dumpf(denv, "class = %s\n", str_c(storage_class));
+
+ /* version */
+ if (!sieve_binary_read_unsigned(sblock, offset, &version))
+ return FALSE;
+ sieve_binary_dumpf(denv, "class.version = %d\n", version);
+
+ /* location */
+ if (!sieve_binary_read_string(sblock, offset, &location))
+ return FALSE;
+ sieve_binary_dumpf(denv, "location = %s\n", str_c(location));
+
+ if (script == NULL) {
+ script = adhoc_script =
+ sieve_script_create(svinst, str_c(location),
+ NULL, NULL);
+ }
+
+ if (script != NULL && script->v.binary_dump_metadata != NULL) {
+ result = script->v.binary_dump_metadata(
+ script, denv, sblock, offset);
+ }
+
+ if (adhoc_script != NULL)
+ sieve_script_unref(&adhoc_script);
+ return result;
+}
+
+struct sieve_binary *
+sieve_script_binary_load(struct sieve_script *script, enum sieve_error *error_r)
+{
+ if (script->v.binary_load == NULL) {
+ *error_r = SIEVE_ERROR_NOT_POSSIBLE;
+ return NULL;
+ }
+
+ return script->v.binary_load(script, error_r);
+}
+
+int sieve_script_binary_save(struct sieve_script *script,
+ struct sieve_binary *sbin, bool update,
+ enum sieve_error *error_r)
+{
+ struct sieve_script *bin_script = sieve_binary_script(sbin);
+ enum sieve_error error;
+
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NONE;
+ else
+ error_r = &error;
+
+ i_assert(bin_script == NULL || sieve_script_equals(bin_script, script));
+
+ if (script->v.binary_save == NULL) {
+ *error_r = SIEVE_ERROR_NOT_POSSIBLE;
+ return -1;
+ }
+
+ return script->v.binary_save(script, sbin, update, error_r);
+}
+
+const char *sieve_script_binary_get_prefix(struct sieve_script *script)
+{
+ struct sieve_storage *storage = script->storage;
+
+ if (storage->bin_dir != NULL &&
+ sieve_storage_setup_bindir(storage, 0700) >= 0) {
+ return t_strconcat(storage->bin_dir, "/", script->name, NULL);
+ }
+
+ if (script->v.binary_get_prefix == NULL)
+ return NULL;
+
+ return script->v.binary_get_prefix(script);
+}
+
+/*
+ * Management
+ */
+
+static int
+sieve_script_copy_from_default(struct sieve_script *script, const char *newname)
+{
+ struct sieve_storage *storage = script->storage;
+ struct istream *input;
+ int ret;
+
+ /* copy from default */
+ if ((ret = sieve_script_open(script, NULL)) < 0 ||
+ (ret = sieve_script_get_stream(script, &input, NULL)) < 0) {
+ sieve_storage_copy_error(storage->default_for, storage);
+ return ret;
+ }
+
+ ret = sieve_storage_save_as(storage->default_for, input, newname);
+ if (ret < 0) {
+ sieve_storage_copy_error(storage, storage->default_for);
+ } else if (sieve_script_is_active(script) > 0) {
+ struct sieve_script *newscript;
+ enum sieve_error error;
+
+ newscript = sieve_storage_open_script(storage->default_for,
+ newname, &error);
+ if (newscript == NULL) {
+ /* Somehow not actually saved */
+ ret = (error == SIEVE_ERROR_NOT_FOUND ? 0 : -1);
+ } else if (sieve_script_activate(newscript, (time_t)-1) < 0) {
+ /* Failed to activate; roll back */
+ ret = -1;
+ (void)sieve_script_delete(newscript, TRUE);
+ }
+ if (newscript != NULL)
+ sieve_script_unref(&newscript);
+
+ if (ret < 0) {
+ e_error(storage->event,
+ "Failed to implicitly activate script `%s' "
+ "after rename", newname);
+ sieve_storage_copy_error(storage->default_for, storage);
+ }
+ }
+
+ return ret;
+}
+
+int sieve_script_rename(struct sieve_script *script, const char *newname)
+{
+ struct sieve_storage *storage = script->storage;
+ const char *oldname = script->name;
+ struct event_passthrough *event;
+ int ret;
+
+ i_assert(newname != NULL);
+
+ /* Check script name */
+ if (!sieve_script_name_is_valid(newname)) {
+ sieve_script_set_error(script,
+ SIEVE_ERROR_BAD_PARAMS,
+ "Invalid new Sieve script name `%s'.",
+ str_sanitize(newname, 80));
+ return -1;
+ }
+
+ i_assert(script->open); // FIXME: auto-open?
+
+ if (storage->default_for == NULL) {
+ i_assert((storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0);
+
+ /* rename script */
+ i_assert(script->v.rename != NULL);
+ ret = script->v.rename(script, newname);
+
+ /* rename INBOX mailbox attribute */
+ if (ret >= 0 && oldname != NULL) {
+ (void)sieve_storage_sync_script_rename(storage, oldname,
+ newname);
+ }
+ } else if (sieve_storage_check_script(storage->default_for,
+ newname, NULL) > 0) {
+ sieve_script_set_error(script, SIEVE_ERROR_EXISTS,
+ "A sieve script with that name already exists.");
+ sieve_storage_copy_error(storage->default_for, storage);
+ ret = -1;
+ } else {
+ ret = sieve_script_copy_from_default(script, newname);
+ }
+
+ event = event_create_passthrough(script->event)->
+ clear_field("script_name")->
+ add_str("old_script_name", script->name)->
+ add_str("new_script_name", newname)->
+ set_name("sieve_script_renamed");
+
+ if (ret >= 0) {
+ e_debug(event->event(), "Script renamed to `%s'", newname);
+ } else {
+ event = event->add_str("error", storage->error);
+
+ e_debug(event->event(), "Failed to rename script: %s",
+ storage->error);
+ }
+
+ return ret;
+}
+
+int sieve_script_delete(struct sieve_script *script, bool ignore_active)
+{
+ struct sieve_storage *storage = script->storage;
+ bool is_active = FALSE;
+ int ret = 0;
+
+ i_assert(script->open); // FIXME: auto-open?
+
+ /* Is the requested script active? */
+ if (sieve_script_is_active(script) > 0) {
+ is_active = TRUE;
+ if (!ignore_active) {
+ sieve_script_set_error(script, SIEVE_ERROR_ACTIVE,
+ "Cannot delete the active Sieve script.");
+ if (storage->default_for != NULL) {
+ sieve_storage_copy_error(storage->default_for,
+ storage);
+ }
+ return -1;
+ }
+ }
+
+ /* Trying to delete the default script? */
+ if (storage->is_default) {
+ /* ignore */
+ return 0;
+ }
+
+ i_assert((script->storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0);
+
+ /* Deactivate it explicity */
+ if (ignore_active && is_active)
+ (void)sieve_storage_deactivate(storage, (time_t)-1);
+
+ i_assert(script->v.delete != NULL);
+ ret = script->v.delete(script);
+
+ if (ret >= 0) {
+ struct event_passthrough *e =
+ event_create_passthrough(script->event)->
+ set_name("sieve_script_deleted");
+ e_debug(e->event(), "Script deleted");
+
+ /* unset INBOX mailbox attribute */
+ (void)sieve_storage_sync_script_delete(storage, script->name);
+ } else {
+ struct event_passthrough *e =
+ event_create_passthrough(script->event)->
+ add_str("error", storage->error)->
+ set_name("sieve_script_deleted");
+ e_debug(e->event(), "Failed to delete script: %s",
+ storage->error);
+ }
+ return ret;
+}
+
+int sieve_script_is_active(struct sieve_script *script)
+{
+ struct sieve_storage *storage = script->storage;
+
+ /* Special handling if this is a default script */
+ if (storage->default_for != NULL) {
+ int ret = sieve_storage_active_script_is_default(
+ storage->default_for);
+ if (ret < 0)
+ sieve_storage_copy_error(storage, storage->default_for);
+ return ret;
+ }
+
+ if (script->v.is_active == NULL)
+ return 0;
+ return script->v.is_active(script);
+}
+
+int sieve_script_activate(struct sieve_script *script, time_t mtime)
+{
+ struct sieve_storage *storage = script->storage;
+ int ret = 0;
+
+ i_assert(script->open); // FIXME: auto-open?
+
+ if (storage->default_for == NULL) {
+ i_assert((storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0);
+
+ i_assert(script->v.activate != NULL);
+ ret = script->v.activate(script);
+
+ if (ret >= 0) {
+ struct event_passthrough *e =
+ event_create_passthrough(script->event)->
+ set_name("sieve_script_activated");
+ e_debug(e->event(), "Script activated");
+
+ sieve_storage_set_modified(storage, mtime);
+ (void)sieve_storage_sync_script_activate(storage);
+ } else {
+ struct event_passthrough *e =
+ event_create_passthrough(script->event)->
+ add_str("error", storage->error)->
+ set_name("sieve_script_activated");
+ e_debug(e->event(), "Failed to activate script: %s",
+ storage->error);
+ }
+
+ } else {
+ /* Activating the default script is equal to deactivating
+ the storage */
+ ret = sieve_storage_deactivate(storage->default_for,
+ (time_t)-1);
+ if (ret < 0)
+ sieve_storage_copy_error(storage, storage->default_for);
+ }
+
+ return ret;
+}
+
+/*
+ * Error handling
+ */
+
+void sieve_script_set_error(struct sieve_script *script, enum sieve_error error,
+ const char *fmt, ...)
+{
+ struct sieve_storage *storage = script->storage;
+ va_list va;
+
+ sieve_storage_clear_error(storage);
+
+ if (fmt != NULL) {
+ va_start(va, fmt);
+ storage->error = i_strdup_vprintf(fmt, va);
+ va_end(va);
+ }
+ storage->error_code = error;
+}
+
+void sieve_script_set_internal_error(struct sieve_script *script)
+{
+ sieve_storage_set_internal_error(script->storage);
+}
+
+void sieve_script_set_critical(struct sieve_script *script,
+ const char *fmt, ...)
+{
+ struct sieve_storage *storage = script->storage;
+
+ va_list va;
+
+ if (fmt != NULL) {
+ if ((storage->flags & SIEVE_STORAGE_FLAG_SYNCHRONIZING) == 0) {
+ va_start(va, fmt);
+ e_error(script->event, "%s", t_strdup_vprintf(fmt, va));
+ va_end(va);
+
+ sieve_storage_set_internal_error(storage);
+
+ } else {
+ sieve_storage_clear_error(storage);
+
+ /* no user is involved while synchronizing, so do it the
+ normal way */
+ va_start(va, fmt);
+ storage->error = i_strdup_vprintf(fmt, va);
+ va_end(va);
+
+ storage->error_code = SIEVE_ERROR_TEMP_FAILURE;
+ }
+ }
+}
+
+const char *
+sieve_script_get_last_error(struct sieve_script *script,
+ enum sieve_error *error_r)
+{
+ return sieve_storage_get_last_error(script->storage, error_r);
+}
+
+const char *sieve_script_get_last_error_lcase(struct sieve_script *script)
+{
+ return sieve_error_from_external(script->storage->error);
+}
+
+/*
+ * Script sequence
+ */
+
+void sieve_script_sequence_init(struct sieve_script_sequence *seq,
+ struct sieve_storage *storage)
+{
+ seq->storage = storage;
+ sieve_storage_ref(storage);
+}
+
+struct sieve_script_sequence *
+sieve_script_sequence_create(struct sieve_instance *svinst,
+ const char *location, enum sieve_error *error_r)
+{
+ struct sieve_storage *storage;
+ struct sieve_script_sequence *seq;
+ enum sieve_error error;
+
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NONE;
+ else
+ error_r = &error;
+
+ storage = sieve_storage_create(svinst, location, 0, error_r);
+ if (storage == NULL)
+ return NULL;
+
+ seq = sieve_storage_get_script_sequence(storage, error_r);
+
+ sieve_storage_unref(&storage);
+ return seq;
+}
+
+struct sieve_script *
+sieve_script_sequence_next(struct sieve_script_sequence *seq,
+ enum sieve_error *error_r)
+{
+ struct sieve_storage *storage = seq->storage;
+
+ i_assert(storage->v.script_sequence_next != NULL);
+ return storage->v.script_sequence_next(seq, error_r);
+}
+
+void sieve_script_sequence_free(struct sieve_script_sequence **_seq)
+{
+ struct sieve_script_sequence *seq = *_seq;
+ struct sieve_storage *storage = seq->storage;
+
+ if (storage->v.script_sequence_destroy != NULL)
+ storage->v.script_sequence_destroy(seq);
+
+ sieve_storage_unref(&storage);
+ *_seq = NULL;
+}
+
diff --git a/pigeonhole/src/lib-sieve/sieve-script.h b/pigeonhole/src/lib-sieve/sieve-script.h
new file mode 100644
index 0000000..8ee53f4
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-script.h
@@ -0,0 +1,163 @@
+#ifndef SIEVE_SCRIPT_H
+#define SIEVE_SCRIPT_H
+
+#include "sieve-common.h"
+
+#include <sys/types.h>
+
+
+/*
+ * Sieve script name
+ */
+
+bool sieve_script_name_is_valid(const char *scriptname);
+
+/*
+ * Sieve script file
+ */
+
+bool sieve_script_file_has_extension(const char *filename);
+
+/*
+ * Sieve script class
+ */
+
+void sieve_script_class_register(struct sieve_instance *svinst,
+ const struct sieve_script *script_class);
+void sieve_script_class_unregister(struct sieve_instance *svinst,
+ const struct sieve_script *script_class);
+
+/*
+ * Sieve script instance
+ */
+
+struct sieve_script;
+
+ARRAY_DEFINE_TYPE(sieve_script, struct sieve_script *);
+
+struct sieve_script *
+sieve_script_create(struct sieve_instance *svinst, const char *location,
+ const char *name, enum sieve_error *error_r) ATTR_NULL(3,4);
+
+void sieve_script_ref(struct sieve_script *script);
+void sieve_script_unref(struct sieve_script **script);
+
+int sieve_script_open(struct sieve_script *script, enum sieve_error *error_r)
+ ATTR_NULL(2);
+int sieve_script_open_as(struct sieve_script *script, const char *name,
+ enum sieve_error *error_r) ATTR_NULL(3);
+
+struct sieve_script *
+sieve_script_create_open(struct sieve_instance *svinst, const char *location,
+ const char *name, enum sieve_error *error_r)
+ ATTR_NULL(3, 4);
+int sieve_script_check(struct sieve_instance *svinst, const char *location,
+ const char *name, enum sieve_error *error_r)
+ ATTR_NULL(3, 4);
+
+/*
+ * Data script
+ */
+
+struct sieve_script *
+sieve_data_script_create_from_input(struct sieve_instance *svinst,
+ const char *name, struct istream *input);
+
+/*
+ * Binary
+ */
+
+int sieve_script_binary_read_metadata(struct sieve_script *script,
+ struct sieve_binary_block *sblock,
+ sieve_size_t *offset);
+void sieve_script_binary_write_metadata(struct sieve_script *script,
+ struct sieve_binary_block *sblock);
+bool sieve_script_binary_dump_metadata(struct sieve_script *script,
+ struct sieve_dumptime_env *denv,
+ struct sieve_binary_block *sblock,
+ sieve_size_t *offset) ATTR_NULL(1);
+
+struct sieve_binary *
+sieve_script_binary_load(struct sieve_script *script,
+ enum sieve_error *error_r);
+int sieve_script_binary_save(struct sieve_script *script,
+ struct sieve_binary *sbin, bool update,
+ enum sieve_error *error_r) ATTR_NULL(4);
+
+const char *sieve_script_binary_get_prefix(struct sieve_script *script);
+
+/*
+ * Stream management
+ */
+
+int sieve_script_get_stream(struct sieve_script *script,
+ struct istream **stream_r,
+ enum sieve_error *error_r) ATTR_NULL(3);
+
+/*
+ * Management
+ */
+
+// FIXME: check read/write flag!
+
+int sieve_script_rename(struct sieve_script *script, const char *newname);
+int sieve_script_is_active(struct sieve_script *script);
+int sieve_script_activate(struct sieve_script *script, time_t mtime);
+int sieve_script_delete(struct sieve_script *script, bool ignore_active);
+
+/*
+ * Properties
+ */
+
+const char *sieve_script_name(const struct sieve_script *script) ATTR_PURE;
+const char *sieve_script_location(const struct sieve_script *script) ATTR_PURE;
+struct sieve_instance *
+sieve_script_svinst(const struct sieve_script *script) ATTR_PURE;
+
+int sieve_script_get_size(struct sieve_script *script, uoff_t *size_r);
+bool sieve_script_is_open(const struct sieve_script *script) ATTR_PURE;
+bool sieve_script_is_default(const struct sieve_script *script) ATTR_PURE;
+
+const char *
+sieve_file_script_get_dirpath(const struct sieve_script *script) ATTR_PURE;
+const char *
+sieve_file_script_get_path(const struct sieve_script *script) ATTR_PURE;
+
+/*
+ * Comparison
+ */
+
+bool sieve_script_equals(const struct sieve_script *script,
+ const struct sieve_script *other);
+
+unsigned int sieve_script_hash(const struct sieve_script *script);
+static inline int
+sieve_script_cmp(const struct sieve_script *script,
+ const struct sieve_script *other)
+{
+ return ( sieve_script_equals(script, other) ? 0 : -1 );
+}
+
+/*
+ * Error handling
+ */
+
+const char *sieve_script_get_last_error(struct sieve_script *script,
+ enum sieve_error *error_r) ATTR_NULL(2);
+const char *sieve_script_get_last_error_lcase(struct sieve_script *script);
+
+/*
+ * Script sequence
+ */
+
+struct sieve_script_sequence;
+
+struct sieve_script_sequence *
+sieve_script_sequence_create(struct sieve_instance *svinst,
+ const char *location, enum sieve_error *error_r);
+struct sieve_script *
+sieve_script_sequence_next(struct sieve_script_sequence *seq,
+ enum sieve_error *error_r);
+void sieve_script_sequence_free(struct sieve_script_sequence **_seq);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-settings.c b/pigeonhole/src/lib-sieve/sieve-settings.c
new file mode 100644
index 0000000..47f70da
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-settings.c
@@ -0,0 +1,270 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-limits.h"
+#include "sieve-error.h"
+#include "sieve-address.h"
+#include "sieve-address-source.h"
+#include "sieve-settings.h"
+
+#include <ctype.h>
+
+/*
+ * Access to settings
+ */
+
+bool sieve_setting_get_uint_value(struct sieve_instance *svinst,
+ const char *setting,
+ unsigned long long int *value_r)
+{
+ const char *str_value;
+
+ str_value = sieve_setting_get(svinst, setting);
+
+ if (str_value == NULL || *str_value == '\0')
+ return FALSE;
+
+ if (str_to_ullong(str_value, value_r) < 0) {
+ e_warning(svinst->event,
+ "invalid unsigned integer value for setting '%s': "
+ "'%s'", setting, str_value);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool sieve_setting_get_int_value(struct sieve_instance *svinst,
+ const char *setting, long long int *value_r)
+{
+ const char *str_value;
+
+ str_value = sieve_setting_get(svinst, setting);
+ if (str_value == NULL || *str_value == '\0')
+ return FALSE;
+
+ if (str_to_llong(str_value, value_r) < 0) {
+ e_warning(svinst->event,
+ "invalid integer value for setting '%s': '%s'",
+ setting, str_value);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool sieve_setting_get_size_value(struct sieve_instance *svinst,
+ const char *setting, size_t *value_r)
+{
+ const char *str_value;
+ uintmax_t value, multiply = 1;
+ const char *endp;
+
+ str_value = sieve_setting_get(svinst, setting);
+ if (str_value == NULL || *str_value == '\0')
+ return FALSE;
+
+ if (str_parse_uintmax(str_value, &value, &endp) < 0) {
+ e_warning(svinst->event,
+ "invalid size value for setting '%s': '%s'",
+ setting, str_value);
+ return FALSE;
+ }
+ switch (i_toupper(*endp)) {
+ case '\0': /* default */
+ case 'B': /* byte (useless) */
+ multiply = 1;
+ break;
+ case 'K': /* kilobyte */
+ multiply = 1024;
+ break;
+ case 'M': /* megabyte */
+ multiply = 1024*1024;
+ break;
+ case 'G': /* gigabyte */
+ multiply = 1024*1024*1024;
+ break;
+ case 'T': /* terabyte */
+ multiply = 1024ULL*1024*1024*1024;
+ break;
+ default:
+ e_warning(svinst->event,
+ "invalid size value for setting '%s': '%s'",
+ setting, str_value);
+ return FALSE;
+ }
+
+ if (value > SSIZE_T_MAX / multiply) {
+ e_warning(svinst->event,
+ "overflowing size value for setting '%s': '%s'",
+ setting, str_value);
+ return FALSE;
+ }
+
+ *value_r = (size_t)(value * multiply);
+ return TRUE;
+}
+
+bool sieve_setting_get_bool_value(struct sieve_instance *svinst,
+ const char *setting, bool *value_r)
+{
+ const char *str_value;
+
+ str_value = sieve_setting_get(svinst, setting);
+ if (str_value == NULL)
+ return FALSE;
+
+ str_value = t_str_trim(str_value, "\t ");
+ if (*str_value == '\0')
+ return FALSE;
+
+ if (strcasecmp(str_value, "yes") == 0) {
+ *value_r = TRUE;
+ return TRUE;
+ }
+
+ if (strcasecmp(str_value, "no") == 0) {
+ *value_r = FALSE;
+ return TRUE;
+ }
+
+ e_warning(svinst->event,
+ "invalid boolean value for setting '%s': '%s'",
+ setting, str_value);
+ return FALSE;
+}
+
+bool sieve_setting_get_duration_value(struct sieve_instance *svinst,
+ const char *setting,
+ sieve_number_t *value_r)
+{
+ const char *str_value;
+ uintmax_t value, multiply = 1;
+ const char *endp;
+
+ str_value = sieve_setting_get(svinst, setting);
+ if (str_value == NULL)
+ return FALSE;
+
+ str_value = t_str_trim(str_value, "\t ");
+ if (*str_value == '\0')
+ return FALSE;
+
+ if (str_parse_uintmax(str_value, &value, &endp) < 0) {
+ e_warning(svinst->event,
+ "invalid duration value for setting '%s': '%s'",
+ setting, str_value);
+ return FALSE;
+ }
+
+ switch (i_tolower(*endp)) {
+ case '\0': /* default */
+ case 's': /* seconds */
+ multiply = 1;
+ break;
+ case 'm': /* minutes */
+ multiply = 60;
+ break;
+ case 'h': /* hours */
+ multiply = 60*60;
+ break;
+ case 'd': /* days */
+ multiply = 24*60*60;
+ break;
+ default:
+ e_warning(svinst->event,
+ "invalid duration value for setting '%s': '%s'",
+ setting, str_value);
+ return FALSE;
+ }
+
+ if (value > SIEVE_MAX_NUMBER / multiply) {
+ e_warning(svinst->event,
+ "overflowing duration value for setting '%s': '%s'",
+ setting, str_value);
+ return FALSE;
+ }
+
+ *value_r = (unsigned int)(value * multiply);
+ return TRUE;
+}
+
+/*
+ * Main Sieve engine settings
+ */
+
+void sieve_settings_load(struct sieve_instance *svinst)
+{
+ const char *str_setting, *error;
+ unsigned long long int uint_setting;
+ size_t size_setting;
+ sieve_number_t period;
+
+ svinst->max_script_size = SIEVE_DEFAULT_MAX_SCRIPT_SIZE;
+ if (sieve_setting_get_size_value(svinst, "sieve_max_script_size",
+ &size_setting))
+ svinst->max_script_size = size_setting;
+
+ svinst->max_actions = SIEVE_DEFAULT_MAX_ACTIONS;
+ if (sieve_setting_get_uint_value(svinst, "sieve_max_actions",
+ &uint_setting))
+ svinst->max_actions = (unsigned int)uint_setting;
+
+ svinst->max_redirects = SIEVE_DEFAULT_MAX_REDIRECTS;
+ if (sieve_setting_get_uint_value(svinst, "sieve_max_redirects",
+ &uint_setting))
+ svinst->max_redirects = (unsigned int)uint_setting;
+
+ svinst->max_cpu_time_secs =
+ (svinst->env_location == SIEVE_ENV_LOCATION_MS ?
+ 0 : SIEVE_DEFAULT_MAX_CPU_TIME_SECS);
+ if (sieve_setting_get_duration_value(svinst, "sieve_max_cpu_time",
+ &period)) {
+ if (period > (UINT_MAX / 1000))
+ svinst->max_cpu_time_secs = (UINT_MAX / 1000);
+ else
+ svinst->max_cpu_time_secs = (unsigned int)period;
+ }
+ svinst->resource_usage_timeout_secs =
+ SIEVE_DEFAULT_RESOURCE_USAGE_TIMEOUT_SECS;
+ if (sieve_setting_get_duration_value(
+ svinst, "sieve_resource_usage_timeout", &period)) {
+ if (period > UINT_MAX)
+ svinst->resource_usage_timeout_secs = UINT_MAX;
+ else {
+ svinst->resource_usage_timeout_secs =
+ (unsigned int)period;
+ }
+ }
+
+ (void)sieve_address_source_parse_from_setting(
+ svinst, svinst->pool, "sieve_redirect_envelope_from",
+ &svinst->redirect_from);
+
+ svinst->redirect_duplicate_period = DEFAULT_REDIRECT_DUPLICATE_PERIOD;
+ if (sieve_setting_get_duration_value(
+ svinst, "sieve_redirect_duplicate_period", &period)) {
+ if (period > UINT_MAX)
+ svinst->redirect_duplicate_period = UINT_MAX;
+ else {
+ svinst->redirect_duplicate_period =
+ (unsigned int)period;
+ }
+ }
+
+ str_setting = sieve_setting_get(svinst, "sieve_user_email");
+ if (str_setting != NULL && *str_setting != '\0') {
+ struct smtp_address *address;
+ if (smtp_address_parse_path(
+ svinst->pool, str_setting,
+ SMTP_ADDRESS_PARSE_FLAG_BRACKETS_OPTIONAL,
+ &address, &error) < 0) {
+ e_warning(svinst->event,
+ "Invalid address value for setting "
+ "`sieve_user_email': %s", error);
+ } else {
+ svinst->user_email = address;
+ }
+ }
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-settings.h b/pigeonhole/src/lib-sieve/sieve-settings.h
new file mode 100644
index 0000000..f2dfca2
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-settings.h
@@ -0,0 +1,57 @@
+#ifndef SIEVE_SETTINGS_H
+#define SIEVE_SETTINGS_H
+
+#include "sieve-common.h"
+
+/*
+ * Access to settings
+ */
+
+static inline const char *
+sieve_setting_get(struct sieve_instance *svinst, const char *identifier)
+{
+ const struct sieve_callbacks *callbacks = svinst->callbacks;
+
+ if (callbacks == NULL || callbacks->get_setting == NULL)
+ return NULL;
+
+ return callbacks->get_setting(svinst->context, identifier);
+}
+
+bool sieve_setting_get_uint_value(struct sieve_instance *svinst,
+ const char *setting,
+ unsigned long long int *value_r);
+bool sieve_setting_get_int_value(struct sieve_instance *svinst,
+ const char *setting, long long int *value_r);
+bool sieve_setting_get_size_value(struct sieve_instance *svinst,
+ const char *setting, size_t *value_r);
+bool sieve_setting_get_bool_value(struct sieve_instance *svinst,
+ const char *setting, bool *value_r);
+bool sieve_setting_get_duration_value(struct sieve_instance *svinst,
+ const char *setting,
+ sieve_number_t *value_r);
+
+/*
+ * Main Sieve engine settings
+ */
+
+void sieve_settings_load(struct sieve_instance *svinst);
+
+/*
+ * Home directory
+ */
+
+static inline const char *
+sieve_environment_get_homedir(struct sieve_instance *svinst)
+{
+ const struct sieve_callbacks *callbacks = svinst->callbacks;
+
+ if (svinst->home_dir != NULL)
+ return svinst->home_dir;
+ if (callbacks == NULL || callbacks->get_homedir == NULL)
+ return NULL;
+
+ return callbacks->get_homedir(svinst->context);
+}
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-smtp.c b/pigeonhole/src/lib-sieve/sieve-smtp.c
new file mode 100644
index 0000000..40b40ea
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-smtp.c
@@ -0,0 +1,95 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+#include "lib.h"
+#include "smtp-address.h"
+
+#include "sieve-common.h"
+#include "sieve-smtp.h"
+
+struct sieve_smtp_context {
+ const struct sieve_script_env *senv;
+ void *handle;
+
+ bool sent:1;
+};
+
+bool sieve_smtp_available
+(const struct sieve_script_env *senv)
+{
+ return ( senv->smtp_start != NULL && senv->smtp_add_rcpt != NULL &&
+ senv->smtp_send != NULL && senv->smtp_finish != NULL );
+}
+
+struct sieve_smtp_context *sieve_smtp_start
+(const struct sieve_script_env *senv,
+ const struct smtp_address *mail_from)
+{
+ struct sieve_smtp_context *sctx;
+ void *handle;
+
+ if ( !sieve_smtp_available(senv) )
+ return NULL;
+
+ handle = senv->smtp_start(senv, mail_from);
+ i_assert( handle != NULL );
+
+ sctx = i_new(struct sieve_smtp_context, 1);
+ sctx->senv = senv;
+ sctx->handle = handle;
+
+ return sctx;
+}
+
+void sieve_smtp_add_rcpt
+(struct sieve_smtp_context *sctx,
+ const struct smtp_address *rcpt_to)
+{
+ i_assert(!sctx->sent);
+ sctx->senv->smtp_add_rcpt(sctx->senv, sctx->handle, rcpt_to);
+}
+
+struct ostream *sieve_smtp_send
+(struct sieve_smtp_context *sctx)
+{
+ i_assert(!sctx->sent);
+ sctx->sent = TRUE;
+
+ return sctx->senv->smtp_send(sctx->senv, sctx->handle);
+}
+
+struct sieve_smtp_context *sieve_smtp_start_single
+(const struct sieve_script_env *senv,
+ const struct smtp_address *rcpt_to,
+ const struct smtp_address *mail_from,
+ struct ostream **output_r)
+{
+ struct sieve_smtp_context *sctx;
+
+ sctx = sieve_smtp_start(senv, mail_from);
+ sieve_smtp_add_rcpt(sctx, rcpt_to);
+ *output_r = sieve_smtp_send(sctx);
+
+ return sctx;
+}
+
+void sieve_smtp_abort
+(struct sieve_smtp_context *sctx)
+{
+ const struct sieve_script_env *senv = sctx->senv;
+ void *handle = sctx->handle;
+
+ i_free(sctx);
+ i_assert(senv->smtp_abort != NULL);
+ senv->smtp_abort(senv, handle);
+}
+
+int sieve_smtp_finish
+(struct sieve_smtp_context *sctx, const char **error_r)
+{
+ const struct sieve_script_env *senv = sctx->senv;
+ void *handle = sctx->handle;
+
+ i_free(sctx);
+ return senv->smtp_finish(senv, handle, error_r);
+}
+
diff --git a/pigeonhole/src/lib-sieve/sieve-smtp.h b/pigeonhole/src/lib-sieve/sieve-smtp.h
new file mode 100644
index 0000000..f7b9c84
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-smtp.h
@@ -0,0 +1,31 @@
+#ifndef SIEVE_SMTP_H
+#define SIEVE_SMTP_H
+
+#include "sieve-common.h"
+
+bool sieve_smtp_available
+ (const struct sieve_script_env *senv);
+
+struct sieve_smtp_context;
+
+struct sieve_smtp_context *sieve_smtp_start
+ (const struct sieve_script_env *senv,
+ const struct smtp_address *mail_from);
+void sieve_smtp_add_rcpt
+ (struct sieve_smtp_context *sctx,
+ const struct smtp_address *rcpt_to);
+struct ostream *sieve_smtp_send
+ (struct sieve_smtp_context *sctx);
+
+struct sieve_smtp_context *sieve_smtp_start_single
+ (const struct sieve_script_env *senv,
+ const struct smtp_address *rcpt_to,
+ const struct smtp_address *mail_from,
+ struct ostream **output_r);
+
+void sieve_smtp_abort
+ (struct sieve_smtp_context *sctx);
+int sieve_smtp_finish
+ (struct sieve_smtp_context *sctx, const char **error_r);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-storage-private.h b/pigeonhole/src/lib-sieve/sieve-storage-private.h
new file mode 100644
index 0000000..16af3d4
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-storage-private.h
@@ -0,0 +1,256 @@
+#ifndef SIEVE_STORAGE_PRIVATE_H
+#define SIEVE_STORAGE_PRIVATE_H
+
+#include "sieve.h"
+#include "sieve-error-private.h"
+
+#include "sieve-storage.h"
+
+#define MAILBOX_ATTRIBUTE_PREFIX_SIEVE \
+ MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER"sieve/"
+#define MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES \
+ MAILBOX_ATTRIBUTE_PREFIX_SIEVE"files/"
+#define MAILBOX_ATTRIBUTE_SIEVE_DEFAULT \
+ MAILBOX_ATTRIBUTE_PREFIX_SIEVE"default"
+
+#define MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_LINK 'L'
+#define MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_SCRIPT 'S'
+
+struct sieve_storage;
+
+ARRAY_DEFINE_TYPE(sieve_storage_class, const struct sieve_storage *);
+
+struct sieve_storage_vfuncs {
+ struct sieve_storage *(*alloc)(void);
+ void (*destroy)(struct sieve_storage *storage);
+ int (*init)(struct sieve_storage *storage, const char *const *options,
+ enum sieve_error *error_r);
+
+ int (*get_last_change)(struct sieve_storage *storage,
+ time_t *last_change_r);
+ void (*set_modified)(struct sieve_storage *storage, time_t mtime);
+
+ int (*is_singular)(struct sieve_storage *storage);
+
+ /* script access */
+ struct sieve_script *(*get_script)(struct sieve_storage *storage,
+ const char *name);
+
+ /* script sequence */
+ struct sieve_script_sequence *(*get_script_sequence)(
+ struct sieve_storage *storage, enum sieve_error *error_r);
+ struct sieve_script *(*script_sequence_next)(
+ struct sieve_script_sequence *seq, enum sieve_error *error_r);
+ void (*script_sequence_destroy)(struct sieve_script_sequence *seq);
+
+ /* active script */
+ int (*active_script_get_name)(struct sieve_storage *storage,
+ const char **name_r);
+ struct sieve_script *(*active_script_open)(
+ struct sieve_storage *storage);
+ int (*deactivate)(struct sieve_storage *storage);
+ int (*active_script_get_last_change)(struct sieve_storage *storage,
+ time_t *last_change_r);
+
+ /* listing scripts */
+ struct sieve_storage_list_context *(*list_init)(
+ struct sieve_storage *storage);
+ const char *(*list_next)(struct sieve_storage_list_context *lctx,
+ bool *active_r);
+ int (*list_deinit)(struct sieve_storage_list_context *lctx);
+
+ /* saving scripts */
+ // FIXME: simplify this API; reduce this mostly to a single save function
+ struct sieve_storage_save_context *(*save_alloc)(
+ struct sieve_storage *storage);
+ int (*save_init)(struct sieve_storage_save_context *sctx,
+ const char *scriptname, struct istream *input);
+ int (*save_continue)(struct sieve_storage_save_context *sctx);
+ int (*save_finish)(struct sieve_storage_save_context *sctx);
+ struct sieve_script *(*save_get_tempscript)(
+ struct sieve_storage_save_context *sctx);
+ void (*save_cancel)(struct sieve_storage_save_context *sctx);
+ int (*save_commit)(struct sieve_storage_save_context *sctx);
+ int (*save_as)(struct sieve_storage *storage, struct istream *input,
+ const char *name);
+ int (*save_as_active)(struct sieve_storage *storage,
+ struct istream *input, time_t mtime);
+
+ /* checking quota */
+ int (*quota_havespace)(struct sieve_storage *storage,
+ const char *scriptname, size_t size,
+ enum sieve_storage_quota *quota_r,
+ uint64_t *limit_r);
+};
+
+struct sieve_storage {
+ pool_t pool;
+ unsigned int refcount;
+ struct sieve_instance *svinst;
+ struct event *event;
+
+ const char *driver_name;
+ unsigned int version;
+
+ const struct sieve_storage *storage_class;
+ struct sieve_storage_vfuncs v;
+
+ uint64_t max_scripts;
+ uint64_t max_storage;
+
+ char *error;
+ enum sieve_error error_code;
+
+ const char *data;
+ const char *location;
+ const char *script_name;
+ const char *bin_dir;
+
+ const char *default_name;
+ const char *default_location;
+ struct sieve_storage *default_for;
+
+ struct mail_namespace *sync_inbox_ns;
+
+ enum sieve_storage_flags flags;
+
+ /* this is the main personal storage */
+ bool main_storage:1;
+ bool allows_synchronization:1;
+ bool is_default:1;
+};
+
+struct event *
+sieve_storage_event_create(struct sieve_instance *svinst,
+ const struct sieve_storage *storage_class);
+struct sieve_storage *
+sieve_storage_alloc(struct sieve_instance *svinst, struct event *event,
+ const struct sieve_storage *storage_class, const char *data,
+ enum sieve_storage_flags flags, bool main) ATTR_NULL(2, 4);
+
+int sieve_storage_setup_bindir(struct sieve_storage *storage, mode_t mode);
+
+/*
+ * Active script
+ */
+
+int sieve_storage_active_script_is_default(struct sieve_storage *storage);
+
+/*
+ * Listing scripts
+ */
+
+struct sieve_storage_list_context {
+ struct sieve_storage *storage;
+
+ bool seen_active:1; // Just present for assertions
+ bool seen_default:1;
+};
+
+/*
+ * Script sequence
+ */
+
+struct sieve_script_sequence {
+ struct sieve_storage *storage;
+};
+
+/*
+ * Saving scripts
+ */
+
+struct sieve_storage_save_context {
+ pool_t pool;
+ struct sieve_storage *storage;
+ struct event *event;
+
+ const char *scriptname, *active_scriptname;
+ struct sieve_script *scriptobject;
+
+ struct istream *input;
+
+ time_t mtime;
+
+ bool failed:1;
+ bool finished:1;
+};
+
+/*
+ * Storage class
+ */
+
+struct sieve_storage_class_registry;
+
+void sieve_storages_init(struct sieve_instance *svinst);
+void sieve_storages_deinit(struct sieve_instance *svinst);
+
+void sieve_storage_class_register(struct sieve_instance *svinst,
+ const struct sieve_storage *storage_class);
+void sieve_storage_class_unregister(struct sieve_instance *svinst,
+ const struct sieve_storage *storage_class);
+const struct sieve_storage *
+sieve_storage_find_class(struct sieve_instance *svinst, const char *name);
+
+/*
+ * Built-in storage drivers
+ */
+
+/* data (currently only for internal use) */
+
+#define SIEVE_DATA_STORAGE_DRIVER_NAME "data"
+
+extern const struct sieve_storage sieve_data_storage;
+
+/* file */
+
+#define SIEVE_FILE_STORAGE_DRIVER_NAME "file"
+
+extern const struct sieve_storage sieve_file_storage;
+
+struct sieve_storage *
+sieve_file_storage_init_legacy(struct sieve_instance *svinst,
+ const char *active_path,
+ const char *storage_path,
+ enum sieve_storage_flags flags,
+ enum sieve_error *error_r) ATTR_NULL(6);
+
+/* dict */
+
+#define SIEVE_DICT_STORAGE_DRIVER_NAME "dict"
+
+extern const struct sieve_storage sieve_dict_storage;
+
+/* ldap */
+
+#define SIEVE_LDAP_STORAGE_DRIVER_NAME "ldap"
+
+extern const struct sieve_storage sieve_ldap_storage;
+
+/*
+ * Error handling
+ */
+
+void sieve_storage_set_internal_error(struct sieve_storage *storage);
+
+void sieve_storage_copy_error(struct sieve_storage *storage,
+ const struct sieve_storage *source);
+
+/*
+ * Synchronization
+ */
+
+int sieve_storage_sync_init(struct sieve_storage *storage,
+ struct mail_user *user);
+void sieve_storage_sync_deinit(struct sieve_storage *storage);
+
+int sieve_storage_sync_script_save(struct sieve_storage *storage,
+ const char *name);
+int sieve_storage_sync_script_rename(struct sieve_storage *storage,
+ const char *oldname, const char *newname);
+int sieve_storage_sync_script_delete(struct sieve_storage *storage,
+ const char *name);
+
+int sieve_storage_sync_script_activate(struct sieve_storage *storage);
+int sieve_storage_sync_deactivate(struct sieve_storage *storage);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-storage-sync.c b/pigeonhole/src/lib-sieve/sieve-storage-sync.c
new file mode 100644
index 0000000..b1abfcc
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-storage-sync.c
@@ -0,0 +1,195 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "str-sanitize.h"
+#include "home-expand.h"
+#include "eacces-error.h"
+#include "mkdir-parents.h"
+#include "ioloop.h"
+#include "mail-storage-private.h"
+
+#include "sieve-common.h"
+#include "sieve-settings.h"
+#include "sieve-error-private.h"
+
+#include "sieve-script-private.h"
+#include "sieve-storage-private.h"
+
+/*
+ * Synchronization
+ */
+
+int sieve_storage_sync_init
+(struct sieve_storage *storage, struct mail_user *user)
+{
+ enum sieve_storage_flags sflags = storage->flags;
+
+ if ( (sflags & SIEVE_STORAGE_FLAG_SYNCHRONIZING) == 0 &&
+ (sflags & SIEVE_STORAGE_FLAG_READWRITE) == 0 )
+ return 0;
+
+ if ( !storage->allows_synchronization ) {
+ if ( (sflags & SIEVE_STORAGE_FLAG_SYNCHRONIZING) != 0 )
+ return -1;
+ return 0;
+ }
+
+ e_debug(storage->event, "sync: Synchronization active");
+
+ storage->sync_inbox_ns = mail_namespace_find_inbox(user->namespaces);
+ return 0;
+}
+
+void sieve_storage_sync_deinit
+(struct sieve_storage *storage ATTR_UNUSED)
+{
+ /* nothing */
+}
+
+/*
+ * Sync attributes
+ */
+
+static int sieve_storage_sync_transaction_begin
+(struct sieve_storage *storage, struct mailbox_transaction_context **trans_r)
+{
+ enum mailbox_flags mflags = MAILBOX_FLAG_IGNORE_ACLS;
+ struct mail_namespace *ns = storage->sync_inbox_ns;
+ struct mailbox *inbox;
+ enum mail_error error;
+
+ if (ns == NULL)
+ return 0;
+
+ inbox = mailbox_alloc(ns->list, "INBOX", mflags);
+ if (mailbox_open(inbox) < 0) {
+ e_warning(storage->event, "sync: "
+ "Failed to open user INBOX for attribute modifications: %s",
+ mailbox_get_last_internal_error(inbox, &error));
+ mailbox_free(&inbox);
+ return -1;
+ }
+
+ *trans_r = mailbox_transaction_begin(inbox,
+ MAILBOX_TRANSACTION_FLAG_EXTERNAL,
+ __func__);
+ return 1;
+}
+
+static int sieve_storage_sync_transaction_finish
+(struct sieve_storage *storage, struct mailbox_transaction_context **trans)
+{
+ struct mailbox *inbox;
+ int ret;
+
+ inbox = mailbox_transaction_get_mailbox(*trans);
+
+ if ((ret=mailbox_transaction_commit(trans)) < 0) {
+ enum mail_error error;
+
+ e_warning(storage->event, "sync: "
+ "Failed to update INBOX attributes: %s",
+ mail_storage_get_last_error(
+ mailbox_get_storage(inbox), &error));
+ }
+
+ mailbox_free(&inbox);
+ return ret;
+}
+
+int sieve_storage_sync_script_save
+(struct sieve_storage *storage, const char *name)
+{
+ struct mailbox_transaction_context *trans;
+ const char *key;
+ int ret;
+
+ if ((ret=sieve_storage_sync_transaction_begin
+ (storage, &trans)) <= 0)
+ return ret;
+
+ key = t_strconcat
+ (MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES, name, NULL);
+
+ mail_index_attribute_set(trans->itrans, TRUE, key, ioloop_time, 0);
+
+ return sieve_storage_sync_transaction_finish(storage, &trans);
+}
+
+int sieve_storage_sync_script_rename
+(struct sieve_storage *storage, const char *oldname,
+ const char *newname)
+{
+ struct mailbox_transaction_context *trans;
+ const char *oldkey, *newkey;
+ int ret;
+
+ if ((ret=sieve_storage_sync_transaction_begin
+ (storage, &trans)) <= 0)
+ return ret;
+
+ oldkey = t_strconcat
+ (MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES, oldname, NULL);
+ newkey = t_strconcat
+ (MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES, newname, NULL);
+
+ mail_index_attribute_unset(trans->itrans, TRUE, oldkey, ioloop_time);
+ mail_index_attribute_set(trans->itrans, TRUE, newkey, ioloop_time, 0);
+
+ return sieve_storage_sync_transaction_finish(storage, &trans);
+}
+
+int sieve_storage_sync_script_delete
+(struct sieve_storage *storage, const char *name)
+{
+ struct mailbox_transaction_context *trans;
+ const char *key;
+ int ret;
+
+ if ((ret=sieve_storage_sync_transaction_begin
+ (storage, &trans)) <= 0)
+ return ret;
+
+ key = t_strconcat
+ (MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES, name, NULL);
+
+ mail_index_attribute_unset(trans->itrans, TRUE, key, ioloop_time);
+
+ return sieve_storage_sync_transaction_finish(storage, &trans);
+}
+
+int sieve_storage_sync_script_activate
+(struct sieve_storage *storage)
+{
+ struct mailbox_transaction_context *trans;
+ int ret;
+
+ if ((ret=sieve_storage_sync_transaction_begin
+ (storage, &trans)) <= 0)
+ return ret;
+
+ mail_index_attribute_set(trans->itrans,
+ TRUE, MAILBOX_ATTRIBUTE_SIEVE_DEFAULT, ioloop_time, 0);
+
+ return sieve_storage_sync_transaction_finish(storage, &trans);
+}
+
+int sieve_storage_sync_deactivate
+(struct sieve_storage *storage)
+{
+ struct mailbox_transaction_context *trans;
+ int ret;
+
+ if ((ret=sieve_storage_sync_transaction_begin
+ (storage, &trans)) <= 0)
+ return ret;
+
+ mail_index_attribute_unset(trans->itrans,
+ TRUE, MAILBOX_ATTRIBUTE_SIEVE_DEFAULT, ioloop_time);
+
+ return sieve_storage_sync_transaction_finish(storage, &trans);
+}
+
+
diff --git a/pigeonhole/src/lib-sieve/sieve-storage.c b/pigeonhole/src/lib-sieve/sieve-storage.c
new file mode 100644
index 0000000..1e2aa34
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-storage.c
@@ -0,0 +1,1590 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "str-sanitize.h"
+#include "home-expand.h"
+#include "eacces-error.h"
+#include "mkdir-parents.h"
+#include "ioloop.h"
+
+#include "sieve-common.h"
+#include "sieve-settings.h"
+#include "sieve-error-private.h"
+
+#include "sieve-script-private.h"
+#include "sieve-storage-private.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <time.h>
+#include <utime.h>
+
+#define CRITICAL_MSG \
+ "Internal error occurred. Refer to server log for more information."
+#define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]"
+
+struct event_category event_category_sieve_storage = {
+ .parent = &event_category_sieve,
+ .name = "sieve-storage",
+};
+
+/*
+ * Storage class
+ */
+
+struct sieve_storage_class_registry {
+ ARRAY_TYPE(sieve_storage_class) storage_classes;
+};
+
+void sieve_storages_init(struct sieve_instance *svinst)
+{
+ svinst->storage_reg = p_new(svinst->pool,
+ struct sieve_storage_class_registry, 1);
+ p_array_init(&svinst->storage_reg->storage_classes, svinst->pool, 8);
+
+ sieve_storage_class_register(svinst, &sieve_file_storage);
+ sieve_storage_class_register(svinst, &sieve_dict_storage);
+ sieve_storage_class_register(svinst, &sieve_ldap_storage);
+}
+
+void sieve_storages_deinit(struct sieve_instance *svinst ATTR_UNUSED)
+{
+ /* nothing yet */
+}
+
+void sieve_storage_class_register(struct sieve_instance *svinst,
+ const struct sieve_storage *storage_class)
+{
+ struct sieve_storage_class_registry *reg = svinst->storage_reg;
+ const struct sieve_storage *old_class;
+
+ old_class = sieve_storage_find_class(svinst,
+ storage_class->driver_name);
+ if (old_class != NULL) {
+ if (old_class->v.alloc == NULL) {
+ /* replacing a "support not compiled in" storage class
+ */
+ sieve_storage_class_unregister(svinst, old_class);
+ } else {
+ i_panic("sieve_storage_class_register(%s): "
+ "Already registered",
+ storage_class->driver_name);
+ }
+ }
+
+ array_append(&reg->storage_classes, &storage_class, 1);
+}
+
+void sieve_storage_class_unregister(struct sieve_instance *svinst,
+ const struct sieve_storage *storage_class)
+{
+ struct sieve_storage_class_registry *reg = svinst->storage_reg;
+ const struct sieve_storage *const *classes;
+ unsigned int i, count;
+
+ classes = array_get(&reg->storage_classes, &count);
+ for (i = 0; i < count; i++) {
+ if (classes[i] == storage_class) {
+ array_delete(&reg->storage_classes, i, 1);
+ break;
+ }
+ }
+}
+
+const struct sieve_storage *
+sieve_storage_find_class(struct sieve_instance *svinst, const char *name)
+{
+ struct sieve_storage_class_registry *reg = svinst->storage_reg;
+ const struct sieve_storage *const *classes;
+ unsigned int i, count;
+
+ i_assert(name != NULL);
+
+ classes = array_get(&reg->storage_classes, &count);
+ for (i = 0; i < count; i++) {
+ if (strcasecmp(classes[i]->driver_name, name) == 0)
+ return classes[i];
+ }
+ return NULL;
+}
+
+/*
+ * Storage instance
+ */
+
+static const char *split_next_arg(const char *const **_args)
+{
+ const char *const *args = *_args;
+ const char *str = args[0];
+
+ /* join arguments for escaped ";" separator */
+
+ args++;
+ while (*args != NULL && **args == '\0') {
+ args++;
+ if (*args == NULL) {
+ /* string ends with ";", just ignore it. */
+ break;
+ }
+ str = t_strconcat(str, ";", *args, NULL);
+ args++;
+ }
+ *_args = args;
+ return str;
+}
+
+static int
+sieve_storage_driver_parse(struct sieve_instance *svinst, const char **data,
+ const struct sieve_storage **driver_r)
+{
+ const struct sieve_storage *storage_class = NULL;
+ const char *p;
+
+ p = strchr(*data, ':');
+ if (p == NULL)
+ return 0;
+
+ /* Lookup storage driver */
+ T_BEGIN {
+ const char *driver;
+
+ driver = t_strdup_until(*data, p);
+ *data = p+1;
+
+ storage_class = sieve_storage_find_class(svinst, driver);
+ if (storage_class == NULL) {
+ e_error(svinst->event,
+ "Unknown storage driver module `%s'",
+ driver);
+ } else if (storage_class->v.alloc == NULL) {
+ e_error(svinst->event,
+ "Support not compiled in for storage driver `%s'",
+ driver);
+ storage_class = NULL;
+ }
+ } T_END;
+
+ *driver_r = storage_class;
+ return (storage_class == NULL ? -1 : 1);
+}
+
+static int
+sieve_storage_data_parse(struct sieve_storage *storage, const char *data,
+ const char **location_r, const char *const **options_r)
+{
+ ARRAY_TYPE(const_string) options;
+ const char *const *tmp;
+
+ if (*data == '\0') {
+ *options_r = NULL;
+ *location_r = data;
+ return 0;
+ }
+
+ /* <location> */
+ tmp = t_strsplit(data, ";");
+ *location_r = split_next_arg(&tmp);
+
+ if (options_r != NULL) {
+ t_array_init(&options, 8);
+
+ /* [<option> *(';' <option>)] */
+ while (*tmp != NULL) {
+ const char *option = split_next_arg(&tmp);
+
+ if (strncasecmp(option, "name=", 5) == 0) {
+ if (option[5] == '\0') {
+ e_error(storage->event,
+ "Failed to parse storage location: "
+ "Empty name not allowed");
+ return -1;
+ }
+
+ if (storage->script_name == NULL) {
+ if (!sieve_script_name_is_valid(option+5)) {
+ e_error(storage->event,
+ "Failed to parse storage location: "
+ "Invalid script name `%s'.",
+ str_sanitize(option+5, 80));
+ return -1;
+ }
+ storage->script_name = p_strdup(storage->pool, option+5);
+ }
+
+ } else if (strncasecmp(option, "bindir=", 7) == 0) {
+ const char *bin_dir = option+7;
+
+ if (bin_dir[0] == '\0') {
+ e_error(storage->event,
+ "Failed to parse storage location: "
+ "Empty bindir not allowed");
+ return -1;
+ }
+
+ if (bin_dir[0] == '~') {
+ /* home-relative path. change to absolute. */
+ const char *home = sieve_environment_get_homedir(storage->svinst);
+
+ if (home != NULL) {
+ bin_dir = home_expand_tilde(bin_dir, home);
+ } else if (bin_dir[1] == '/' || bin_dir[1] == '\0') {
+ e_error(storage->event,
+ "Failed to parse storage location: "
+ "bindir is relative to home directory (~/), "
+ "but home directory cannot be determined");
+ return -1;
+ }
+ }
+
+ storage->bin_dir = p_strdup(storage->pool, bin_dir);
+ } else {
+ array_append(&options, &option, 1);
+ }
+ }
+
+ (void)array_append_space(&options);
+ *options_r = array_idx(&options, 0);
+ }
+
+ return 0;
+}
+
+struct event *
+sieve_storage_event_create(struct sieve_instance *svinst,
+ const struct sieve_storage *storage_class)
+{
+ struct event *event;
+
+ event = event_create(svinst->event);
+ event_add_category(event, &event_category_sieve_storage);
+ event_add_str(event, "driver", storage_class->driver_name);
+ event_set_append_log_prefix(
+ event, t_strdup_printf("%s storage: ",
+ storage_class->driver_name));
+
+ return event;
+}
+
+struct sieve_storage *
+sieve_storage_alloc(struct sieve_instance *svinst, struct event *event,
+ const struct sieve_storage *storage_class, const char *data,
+ enum sieve_storage_flags flags, bool main)
+{
+ struct sieve_storage *storage;
+
+ i_assert(storage_class->v.alloc != NULL);
+ storage = storage_class->v.alloc();
+
+ storage->storage_class = storage_class;
+ storage->refcount = 1;
+ storage->svinst = svinst;
+ storage->flags = flags;
+ storage->data = p_strdup_empty(storage->pool, data);
+ storage->main_storage = main;
+
+ if (event != NULL) {
+ storage->event = event;
+ event_ref(storage->event);
+ } else {
+ storage->event =
+ sieve_storage_event_create(svinst, storage_class);
+ }
+
+ return storage;
+}
+
+static struct sieve_storage *
+sieve_storage_init(struct sieve_instance *svinst,
+ const struct sieve_storage *storage_class, const char *data,
+ enum sieve_storage_flags flags, bool main,
+ enum sieve_error *error_r)
+{
+ struct sieve_storage *storage;
+ const char *const *options;
+ const char *location;
+ struct event *event;
+ enum sieve_error error;
+
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NONE;
+ else
+ error_r = &error;
+
+ i_assert(storage_class->v.init != NULL);
+
+ event = sieve_storage_event_create(svinst, storage_class);
+
+ if ((flags & SIEVE_STORAGE_FLAG_SYNCHRONIZING) != 0 &&
+ !storage_class->allows_synchronization) {
+ e_debug(event, "Storage does not support synchronization");
+ *error_r = SIEVE_ERROR_NOT_POSSIBLE;
+ event_unref(&event);
+ return NULL;
+ }
+
+ if ((flags & SIEVE_STORAGE_FLAG_READWRITE) != 0 &&
+ storage_class->v.save_init == NULL) {
+ e_error(event, "Storage does not support write access");
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ event_unref(&event);
+ return NULL;
+ }
+
+ T_BEGIN {
+ storage = sieve_storage_alloc(svinst, event, storage_class,
+ data, flags, main);
+
+ if (sieve_storage_data_parse(storage, data,
+ &location, &options) < 0) {
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ sieve_storage_unref(&storage);
+ storage = NULL;
+ } else {
+ storage->location = p_strdup(storage->pool, location);
+
+ event_add_str(event, "script_location",
+ storage->location);
+
+ if (storage_class->v.init(storage, options,
+ error_r) < 0) {
+ sieve_storage_unref(&storage);
+ storage = NULL;
+ }
+ }
+ } T_END;
+
+ event_unref(&event);
+ return storage;
+}
+
+struct sieve_storage *
+sieve_storage_create(struct sieve_instance *svinst, const char *location,
+ enum sieve_storage_flags flags, enum sieve_error *error_r)
+{
+ const struct sieve_storage *storage_class;
+ enum sieve_error error;
+ const char *data;
+ int ret;
+
+ /* Dont use this function for creating a synchronizing storage */
+ i_assert((flags & SIEVE_STORAGE_FLAG_SYNCHRONIZING) == 0);
+
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NONE;
+ else
+ error_r = &error;
+
+ data = location;
+ if ((ret = sieve_storage_driver_parse(svinst, &data,
+ &storage_class)) < 0) {
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return NULL;
+ }
+
+ if (ret == 0)
+ storage_class = &sieve_file_storage;
+
+ return sieve_storage_init(svinst, storage_class, data, flags,
+ FALSE, error_r);
+}
+
+static struct sieve_storage *
+sieve_storage_do_create_main(struct sieve_instance *svinst,
+ struct mail_user *user,
+ enum sieve_storage_flags flags,
+ enum sieve_error *error_r)
+{
+ struct sieve_storage *storage = NULL;
+ const struct sieve_storage
+ *sieve_class = NULL,
+ *sieve_dir_class = NULL;
+ const char *set_sieve, *set_sieve_dir;
+ const char *data, *storage_path;
+ unsigned long long int uint_setting;
+ size_t size_setting;
+ int ret;
+
+ /* Sieve storage location */
+
+ set_sieve = sieve_setting_get(svinst, "sieve");
+
+ if (set_sieve != NULL) {
+ if (*set_sieve == '\0') {
+ /* disabled */
+ e_debug(svinst->event, "storage: "
+ "Personal storage is disabled (sieve=\"\")");
+ *error_r = SIEVE_ERROR_NOT_FOUND;
+ return NULL;
+ }
+
+ data = set_sieve;
+ if ((ret = sieve_storage_driver_parse(svinst, &data,
+ &sieve_class)) < 0) {
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return NULL;
+ }
+
+ if (ret > 0) {
+ /* The normal case: explicit driver name */
+ storage = sieve_storage_init(svinst, sieve_class, data,
+ flags, TRUE, error_r);
+ if (storage == NULL)
+ return NULL;
+ }
+
+ /* No driver name */
+ }
+
+ if (storage == NULL) {
+ /* Script storage directory configuration (deprecated) */
+
+ set_sieve_dir = sieve_setting_get(svinst, "sieve_dir");
+ if (set_sieve_dir == NULL) {
+ set_sieve_dir = sieve_setting_get(svinst,
+ "sieve_storage");
+ }
+
+ if (set_sieve_dir == NULL || *set_sieve_dir == '\0') {
+ storage_path = "";
+ } else {
+ const char *p;
+
+ /* Parse and check driver */
+ storage_path = set_sieve_dir;
+ if ((ret = sieve_storage_driver_parse(
+ svinst, &storage_path, &sieve_dir_class)) < 0) {
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return NULL;
+ }
+
+ if (ret > 0 && sieve_dir_class != &sieve_file_storage) {
+ e_error(svinst->event, "storage: "
+ "Cannot use deprecated sieve_dir= setting "
+ "with `%s' driver for main Sieve storage",
+ sieve_dir_class->driver_name);
+ }
+
+ /* Ignore any options */
+ p = strchr(storage_path, ';');
+ if (p != NULL)
+ storage_path = t_strdup_until(storage_path, p);
+ }
+
+ storage = sieve_file_storage_init_legacy(svinst, set_sieve,
+ storage_path, flags,
+ error_r);
+ }
+
+ if (storage == NULL)
+ return NULL;
+
+ (void)sieve_storage_sync_init(storage, user);
+
+ /* Get quota settings if storage driver provides none */
+
+ if (storage->max_storage == 0 &&
+ sieve_setting_get_size_value(svinst, "sieve_quota_max_storage",
+ &size_setting)) {
+ storage->max_storage = size_setting;
+ }
+
+ if (storage->max_scripts == 0 &&
+ sieve_setting_get_uint_value(svinst, "sieve_quota_max_scripts",
+ &uint_setting)) {
+ storage->max_scripts = uint_setting;
+ }
+
+ if (storage->max_storage > 0) {
+ e_debug(storage->event, "quota: "
+ "Storage limit: %llu bytes",
+ (unsigned long long int) storage->max_storage);
+ }
+ if (storage->max_scripts > 0) {
+ e_debug(storage->event, "quota: "
+ "Script count limit: %llu scripts",
+ (unsigned long long int) storage->max_scripts);
+ }
+ return storage;
+}
+
+struct sieve_storage *
+sieve_storage_create_main(struct sieve_instance *svinst, struct mail_user *user,
+ enum sieve_storage_flags flags,
+ enum sieve_error *error_r)
+{
+ struct sieve_storage *storage;
+ const char *set_enabled, *set_default, *set_default_name;
+ enum sieve_error error;
+
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NONE;
+ else
+ error_r = &error;
+
+ /* Check whether Sieve is disabled for this user */
+ if ((set_enabled = sieve_setting_get(svinst, "sieve_enabled")) != NULL &&
+ strcasecmp(set_enabled, "no") == 0) {
+ e_debug(svinst->event,
+ "Sieve is disabled for this user");
+ *error_r = SIEVE_ERROR_NOT_POSSIBLE;
+ return NULL;
+ }
+
+ /* Determine location for default script */
+ set_default = sieve_setting_get(svinst, "sieve_default");
+ if (set_default == NULL) {
+ /* For backwards compatibility */
+ set_default = sieve_setting_get(svinst, "sieve_global_path");
+ }
+
+ /* Attempt to locate user's main storage */
+ storage = sieve_storage_do_create_main(svinst, user, flags, error_r);
+ if (storage != NULL) {
+ /* Success; record default script location for later use */
+ storage->default_location =
+ p_strdup_empty(storage->pool, set_default);
+
+ set_default_name =
+ sieve_setting_get(svinst, "sieve_default_name");
+ if (set_default_name != NULL && *set_default_name != '\0' &&
+ !sieve_script_name_is_valid(set_default_name)) {
+ e_error(storage->event,
+ "Invalid script name `%s' for `sieve_default_name' setting.",
+ str_sanitize(set_default_name, 80));
+ set_default_name = NULL;
+ }
+ storage->default_name =
+ p_strdup_empty(storage->pool, set_default_name);
+
+ if (storage->default_location != NULL &&
+ storage->default_name != NULL) {
+ e_debug(storage->event,
+ "Default script at `%s' is visible by name `%s'",
+ storage->default_location, storage->default_name);
+ }
+ } else if (*error_r != SIEVE_ERROR_TEMP_FAILURE &&
+ (flags & SIEVE_STORAGE_FLAG_SYNCHRONIZING) == 0 &&
+ (flags & SIEVE_STORAGE_FLAG_READWRITE) == 0) {
+
+ /* Failed; try using default script location
+ (not for temporary failures, read/write access, or dsync) */
+ if (set_default == NULL) {
+ e_debug(svinst->event, "storage: "
+ "No default script location configured");
+ } else {
+ e_debug(svinst->event, "storage: "
+ "Trying default script location `%s'",
+ set_default);
+
+ storage = sieve_storage_create(svinst, set_default, 0,
+ error_r);
+ if (storage == NULL) {
+ switch (*error_r) {
+ case SIEVE_ERROR_NOT_FOUND:
+ e_debug(svinst->event, "storage: "
+ "Default script location `%s' not found",
+ set_default);
+ break;
+ case SIEVE_ERROR_TEMP_FAILURE:
+ e_error(svinst->event, "storage: "
+ "Failed to access default script location `%s' "
+ "(temporary failure)",
+ set_default);
+ break;
+ default:
+ e_error(svinst->event, "storage: "
+ "Failed to access default script location `%s'",
+ set_default);
+ break;
+ }
+ }
+ }
+ if (storage != NULL)
+ storage->is_default = TRUE;
+ }
+ return storage;
+}
+
+void sieve_storage_ref(struct sieve_storage *storage)
+{
+ storage->refcount++;
+}
+
+void sieve_storage_unref(struct sieve_storage **_storage)
+{
+ struct sieve_storage *storage = *_storage;
+
+ i_assert(storage->refcount > 0);
+
+ if (--storage->refcount != 0)
+ return;
+
+ if (storage->default_for != NULL) {
+ i_assert(storage->is_default);
+ sieve_storage_unref(&storage->default_for);
+ }
+
+ sieve_storage_sync_deinit(storage);
+
+ if (storage->v.destroy != NULL)
+ storage->v.destroy(storage);
+
+ i_free(storage->error);
+ event_unref(&storage->event);
+ pool_unref(&storage->pool);
+ *_storage = NULL;
+}
+
+int sieve_storage_setup_bindir(struct sieve_storage *storage, mode_t mode)
+{
+ const char *bin_dir = storage->bin_dir;
+ struct stat st;
+
+ if (bin_dir == NULL)
+ return -1;
+
+ if (stat(bin_dir, &st) == 0)
+ return 0;
+
+ if (errno == EACCES) {
+ e_error(storage->event,
+ "Failed to setup directory for binaries: "
+ "%s", eacces_error_get("stat", bin_dir));
+ return -1;
+ } else if (errno != ENOENT) {
+ e_error(storage->event,
+ "Failed to setup directory for binaries: "
+ "stat(%s) failed: %m",
+ bin_dir);
+ return -1;
+ }
+
+ if (mkdir_parents(bin_dir, mode) == 0) {
+ e_debug(storage->event,
+ "Created directory for binaries: %s", bin_dir);
+ return 1;
+ }
+
+ switch (errno) {
+ case EEXIST:
+ return 0;
+ case ENOENT:
+ e_error(storage->event,
+ "Directory for binaries was deleted while it was being created");
+ break;
+ case EACCES:
+ e_error(storage->event,
+ "%s", eacces_error_get_creating("mkdir_parents_chgrp", bin_dir));
+ break;
+ default:
+ e_error(storage->event,
+ "mkdir_parents_chgrp(%s) failed: %m", bin_dir);
+ break;
+ }
+
+ return -1;
+}
+
+int sieve_storage_is_singular(struct sieve_storage *storage)
+{
+ if (storage->v.is_singular == NULL)
+ return 1;
+ return storage->v.is_singular(storage);
+}
+
+int sieve_storage_get_last_change(struct sieve_storage *storage,
+ time_t *last_change_r)
+{
+ i_assert(storage->v.get_last_change != NULL);
+ return storage->v.get_last_change(storage, last_change_r);
+}
+
+void sieve_storage_set_modified(struct sieve_storage *storage, time_t mtime)
+{
+ if (storage->v.set_modified == NULL)
+ return;
+
+ storage->v.set_modified(storage, mtime);
+}
+
+/*
+ * Script access
+ */
+
+static struct sieve_script *
+sieve_storage_get_script_direct(struct sieve_storage *storage, const char *name,
+ enum sieve_error *error_r)
+{
+ struct sieve_script *script;
+
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NONE;
+ sieve_storage_clear_error(storage);
+
+ /* Validate script name */
+ if (name != NULL && !sieve_script_name_is_valid(name)) {
+ sieve_storage_set_error(storage,
+ SIEVE_ERROR_BAD_PARAMS,
+ "Invalid script name `%s'.",
+ str_sanitize(name, 80));
+ if (error_r != NULL)
+ *error_r = storage->error_code;
+ return NULL;
+ }
+
+ i_assert(storage->v.get_script != NULL);
+ script = storage->v.get_script(storage, name);
+ return script;
+}
+
+struct sieve_script *
+sieve_storage_get_script(struct sieve_storage *storage, const char *name,
+ enum sieve_error *error_r)
+{
+ struct sieve_instance *svinst = storage->svinst;
+ struct sieve_script *script;
+
+ script = sieve_storage_get_script_direct(storage, name, error_r);
+ if (script == NULL) {
+ /* Error */
+ if (storage->error_code == SIEVE_ERROR_NOT_FOUND &&
+ (storage->flags & SIEVE_STORAGE_FLAG_SYNCHRONIZING) == 0 &&
+ storage->default_name != NULL &&
+ storage->default_location != NULL &&
+ strcmp(storage->default_name, name) == 0) {
+ /* Not found; if this name maps to the default script,
+ try to access that instead */
+ i_assert(*storage->default_location != '\0');
+
+ e_debug(storage->event,
+ "Trying default script instead");
+
+ script = sieve_script_create(
+ svinst, storage->default_location, NULL,
+ error_r);
+ if (script != NULL) {
+ script->storage->is_default = TRUE;
+ script->storage->default_for = storage;
+ sieve_storage_ref(storage);
+ }
+
+ } else if (error_r != NULL) {
+ *error_r = storage->error_code;
+ }
+ }
+ return script;
+}
+
+struct sieve_script *
+sieve_storage_open_script(struct sieve_storage *storage, const char *name,
+ enum sieve_error *error_r)
+{
+ struct sieve_instance *svinst = storage->svinst;
+ struct sieve_script *script;
+
+ script = sieve_storage_get_script(storage, name, error_r);
+ if (script == NULL)
+ return NULL;
+
+ if (sieve_script_open(script, error_r) >= 0)
+ return script;
+
+ /* Error */
+ sieve_script_unref(&script);
+ script = NULL;
+
+ if (storage->error_code == SIEVE_ERROR_NOT_FOUND &&
+ (storage->flags & SIEVE_STORAGE_FLAG_SYNCHRONIZING) == 0 &&
+ storage->default_name != NULL &&
+ storage->default_location != NULL &&
+ strcmp(storage->default_name, name) == 0) {
+ /* Not found; if this name maps to the default script,
+ try to open that instead */
+ i_assert(*storage->default_location != '\0');
+
+ e_debug(storage->event, "Trying default script instead");
+
+ script = sieve_script_create_open(
+ svinst, storage->default_location, NULL, error_r);
+ if (script != NULL) {
+ script->storage->is_default = TRUE;
+ script->storage->default_for = storage;
+ sieve_storage_ref(storage);
+ }
+ }
+ return script;
+}
+
+static int
+sieve_storage_check_script_direct(struct sieve_storage *storage,
+ const char *name, enum sieve_error *error_r)
+ ATTR_NULL(3)
+{
+ struct sieve_script *script;
+ enum sieve_error error;
+ int ret;
+
+ if (error_r == NULL)
+ error_r = &error;
+
+ script = sieve_storage_get_script_direct(storage, name, error_r);
+ if (script == NULL)
+ return (*error_r == SIEVE_ERROR_NOT_FOUND ? 0 : -1);
+
+ ret = sieve_script_open(script, error_r);
+ sieve_script_unref(&script);
+ return (ret >= 0 ? 1 : (*error_r == SIEVE_ERROR_NOT_FOUND ? 0 : -1));
+}
+
+int sieve_storage_check_script(struct sieve_storage *storage, const char *name,
+ enum sieve_error *error_r)
+{
+ struct sieve_script *script;
+ enum sieve_error error;
+
+ if (error_r == NULL)
+ error_r = &error;
+
+ script = sieve_storage_open_script(storage, name, error_r);
+ if (script == NULL)
+ return (*error_r == SIEVE_ERROR_NOT_FOUND ? 0 : -1);
+
+ sieve_script_unref(&script);
+ return 1;
+}
+
+/*
+ * Script sequence
+ */
+
+struct sieve_script_sequence *
+sieve_storage_get_script_sequence(struct sieve_storage *storage,
+ enum sieve_error *error_r)
+{
+ enum sieve_error error;
+
+ if (error_r != NULL)
+ *error_r = SIEVE_ERROR_NONE;
+ else
+ error_r = &error;
+
+ i_assert(storage->v.get_script_sequence != NULL);
+ return storage->v.get_script_sequence(storage, error_r);
+}
+
+/*
+ * Active script
+ */
+
+static int
+sieve_storage_active_script_do_get_name(struct sieve_storage *storage,
+ const char **name_r, bool *default_r)
+ ATTR_NULL(3)
+{
+ struct sieve_instance *svinst = storage->svinst;
+ enum sieve_error error;
+ int ret;
+
+ if (default_r != NULL)
+ *default_r = FALSE;
+
+ i_assert(storage->v.active_script_get_name != NULL);
+ ret = storage->v.active_script_get_name(storage, name_r);
+
+ if (ret != 0 ||
+ (storage->flags & SIEVE_STORAGE_FLAG_SYNCHRONIZING) != 0 ||
+ storage->default_location == NULL ||
+ storage->default_name == NULL) {
+ return ret;
+ }
+
+ *name_r = storage->default_name;
+
+ ret = sieve_script_check(svinst, storage->default_location,
+ NULL, &error);
+ if (ret <= 0)
+ return ret;
+
+ if (default_r != NULL)
+ *default_r = TRUE;
+ return 1;
+}
+
+int sieve_storage_active_script_get_name(struct sieve_storage *storage,
+ const char **name_r)
+{
+ return sieve_storage_active_script_do_get_name(storage, name_r, NULL);
+}
+
+int sieve_storage_active_script_is_default(struct sieve_storage *storage)
+{
+ const char *name;
+ bool is_default = FALSE;
+ int ret;
+
+ ret = sieve_storage_active_script_do_get_name(storage, &name,
+ &is_default);
+ return (ret < 0 ? -1 : (is_default ? 1 : 0));
+}
+
+struct sieve_script *
+sieve_storage_active_script_open(struct sieve_storage *storage,
+ enum sieve_error *error_r)
+{
+ struct sieve_instance *svinst = storage->svinst;
+ struct sieve_script *script;
+
+ i_assert(storage->v.active_script_open != NULL);
+ script = storage->v.active_script_open(storage);
+
+ if (script != NULL ||
+ (storage->flags & SIEVE_STORAGE_FLAG_SYNCHRONIZING) != 0 ||
+ storage->default_location == NULL) {
+ if (error_r != NULL)
+ *error_r = storage->error_code;
+ return script;
+ }
+
+ /* Try default script location */
+ script = sieve_script_create_open(svinst, storage->default_location,
+ NULL, error_r);
+ if (script != NULL) {
+ script->storage->is_default = TRUE;
+ script->storage->default_for = storage;
+ sieve_storage_ref(storage);
+ }
+ return script;
+}
+
+int sieve_storage_deactivate(struct sieve_storage *storage, time_t mtime)
+{
+ int ret;
+
+ i_assert((storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0);
+
+ i_assert(storage->v.deactivate != NULL);
+ ret = storage->v.deactivate(storage);
+
+ if (ret >= 0) {
+ struct event_passthrough *e =
+ event_create_passthrough(storage->event)->
+ set_name("sieve_storage_deactivated");
+ e_debug(e->event(), "Storage activated");
+
+ sieve_storage_set_modified(storage, mtime);
+ (void)sieve_storage_sync_deactivate(storage);
+ } else {
+ struct event_passthrough *e =
+ event_create_passthrough(storage->event)->
+ add_str("error", storage->error)->
+ set_name("sieve_storage_deactivated");
+ e_debug(e->event(), "Failed to deactivate storage: %s",
+ storage->error);
+ }
+
+ return ret;
+}
+
+int sieve_storage_active_script_get_last_change(struct sieve_storage *storage,
+ time_t *last_change_r)
+{
+ i_assert(storage->v.active_script_get_last_change != NULL);
+
+ return storage->v.active_script_get_last_change(storage, last_change_r);
+}
+
+/*
+ * Listing scripts
+ */
+
+struct sieve_storage_list_context *
+sieve_storage_list_init(struct sieve_storage *storage)
+{
+ struct sieve_storage_list_context *lctx;
+
+ i_assert(storage->v.list_init != NULL);
+ lctx = storage->v.list_init(storage);
+
+ if (lctx != NULL)
+ lctx->storage = storage;
+
+ return lctx;
+}
+
+const char *
+sieve_storage_list_next(struct sieve_storage_list_context *lctx, bool *active_r)
+{
+ struct sieve_storage *storage = lctx->storage;
+ struct sieve_instance *svinst = storage->svinst;
+ const char *scriptname;
+ bool have_default, script_active = FALSE;
+
+ have_default = (storage->default_name != NULL &&
+ storage->default_location != NULL &&
+ (storage->flags &
+ SIEVE_STORAGE_FLAG_SYNCHRONIZING) == 0);
+
+ i_assert(storage->v.list_next != NULL);
+ scriptname = storage->v.list_next(lctx, &script_active);
+
+ i_assert(!script_active || !lctx->seen_active);
+ if (script_active)
+ lctx->seen_active = TRUE;
+
+ if (scriptname != NULL) {
+ /* Remember when we see that the storage has its own script for
+ default */
+ if (have_default &&
+ strcmp(scriptname, storage->default_name) == 0)
+ lctx->seen_default = TRUE;
+
+ } else if (have_default && !lctx->seen_default &&
+ sieve_script_check(svinst, storage->default_location,
+ NULL, NULL) > 0) {
+
+ /* Return default script at the end if it was not listed
+ thus far (storage backend has no script under default
+ name) */
+ scriptname = storage->default_name;
+ lctx->seen_default = TRUE;
+
+ /* Mark default as active if no normal script is active */
+ if (!lctx->seen_active) {
+ script_active = TRUE;
+ lctx->seen_active = TRUE;
+ }
+ }
+
+ if (active_r != NULL)
+ *active_r = script_active;
+ return scriptname;
+}
+
+int sieve_storage_list_deinit(struct sieve_storage_list_context **_lctx)
+{
+ struct sieve_storage_list_context *lctx = *_lctx;
+ struct sieve_storage *storage = lctx->storage;
+ int ret;
+
+ i_assert(storage->v.list_deinit != NULL);
+ ret = storage->v.list_deinit(lctx);
+
+ *_lctx = NULL;
+ return ret;
+}
+
+/*
+ * Saving scripts
+ */
+
+static struct event *
+sieve_storage_save_create_event(struct sieve_storage *storage,
+ const char *scriptname) ATTR_NULL(2)
+{
+ struct event *event;
+
+ event = event_create(storage->event);
+ event_add_str(event, "script_name", scriptname);
+ if (scriptname == NULL) {
+ event_set_append_log_prefix(event, "save: ");
+ } else {
+ event_set_append_log_prefix(
+ event, t_strdup_printf("script `%s': save: ",
+ scriptname));
+ }
+
+ return event;
+}
+
+static void sieve_storage_save_cleanup(struct sieve_storage_save_context *sctx)
+{
+ if (sctx->scriptobject != NULL)
+ sieve_script_unref(&sctx->scriptobject);
+}
+
+static void sieve_storage_save_deinit(struct sieve_storage_save_context **_sctx)
+{
+ struct sieve_storage_save_context *sctx = *_sctx;
+
+ *_sctx = NULL;
+ if (sctx == NULL)
+ return;
+
+ sieve_storage_save_cleanup(sctx);
+ event_unref(&sctx->event);
+ pool_unref(&sctx->pool);
+}
+
+struct sieve_storage_save_context *
+sieve_storage_save_init(struct sieve_storage *storage, const char *scriptname,
+ struct istream *input)
+{
+ struct sieve_storage_save_context *sctx;
+
+ if (scriptname != NULL) {
+ /* Validate script name */
+ if (!sieve_script_name_is_valid(scriptname)) {
+ sieve_storage_set_error(storage,
+ SIEVE_ERROR_BAD_PARAMS,
+ "Invalid Sieve script name `%s'.",
+ str_sanitize(scriptname, 80));
+ return NULL;
+ }
+ }
+
+ i_assert((storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0);
+
+ i_assert(storage->v.save_alloc != NULL);
+ sctx = storage->v.save_alloc(storage);
+ sctx->storage = storage;
+
+ sctx->event = sieve_storage_save_create_event(storage, scriptname);
+
+ struct event_passthrough *e =
+ event_create_passthrough(sctx->event)->
+ set_name("sieve_storage_save_started");
+ e_debug(e->event(), "Started saving script");
+
+ i_assert(storage->v.save_init != NULL);
+ if ((storage->v.save_init(sctx, scriptname, input)) < 0) {
+ struct event_passthrough *e =
+ event_create_passthrough(sctx->event)->
+ add_str("error", storage->error)->
+ set_name("sieve_storage_save_finished");
+ e_debug(e->event(), "Failed to save script: %s",
+ storage->error);
+
+ sieve_storage_save_deinit(&sctx);
+ return NULL;
+ }
+
+ sctx->mtime = (time_t)-1;
+
+ i_assert(sctx->input != NULL);
+
+ return sctx;
+}
+
+int sieve_storage_save_continue(struct sieve_storage_save_context *sctx)
+{
+ struct sieve_storage *storage = sctx->storage;
+ int ret;
+
+ i_assert(storage->v.save_continue != NULL);
+ ret = storage->v.save_continue(sctx);
+ if (ret < 0)
+ sctx->failed = TRUE;
+ return ret;
+}
+
+int sieve_storage_save_finish(struct sieve_storage_save_context *sctx)
+{
+ struct sieve_storage *storage = sctx->storage;
+ int ret;
+
+ i_assert(!sctx->finished);
+ sctx->finished = TRUE;
+
+ i_assert(storage->v.save_finish != NULL);
+ ret = storage->v.save_finish(sctx);
+ if (ret < 0) {
+ struct event_passthrough *e =
+ event_create_passthrough(sctx->event)->
+ add_str("error", storage->error)->
+ set_name("sieve_storage_save_finished");
+ e_debug(e->event(), "Failed to upload script: %s",
+ storage->error);
+
+ sctx->failed = TRUE;
+ }
+ return ret;
+}
+
+void sieve_storage_save_set_mtime(struct sieve_storage_save_context *sctx,
+ time_t mtime)
+{
+ sctx->mtime = mtime;
+}
+
+struct sieve_script *
+sieve_storage_save_get_tempscript(struct sieve_storage_save_context *sctx)
+{
+ struct sieve_storage *storage = sctx->storage;
+
+ if (sctx->failed)
+ return NULL;
+
+ if (sctx->scriptobject != NULL)
+ return sctx->scriptobject;
+
+ i_assert(storage->v.save_get_tempscript != NULL);
+ sctx->scriptobject = storage->v.save_get_tempscript(sctx);
+
+ i_assert(sctx->scriptobject != NULL ||
+ storage->error_code != SIEVE_ERROR_NONE);
+ return sctx->scriptobject;
+}
+
+bool sieve_storage_save_will_activate(struct sieve_storage_save_context *sctx)
+{
+ if (sctx->scriptname == NULL)
+ return FALSE;
+
+ if (sctx->active_scriptname == NULL) {
+ const char *scriptname;
+
+ if (sieve_storage_active_script_get_name(sctx->storage,
+ &scriptname) > 0) {
+ sctx->active_scriptname =
+ p_strdup(sctx->pool, scriptname);
+ }
+ }
+
+ /* Is the requested script active? */
+ return (sctx->active_scriptname != NULL &&
+ strcmp(sctx->scriptname, sctx->active_scriptname) == 0);
+}
+
+int sieve_storage_save_commit(struct sieve_storage_save_context **_sctx)
+{
+ struct sieve_storage_save_context *sctx = *_sctx;
+ struct sieve_storage *storage;
+ const char *scriptname;
+ bool default_activate = FALSE;
+ int ret;
+
+ *_sctx = NULL;
+ if (sctx == NULL)
+ return 0;
+
+ storage = sctx->storage;
+ scriptname = sctx->scriptname;
+
+ i_assert(!sctx->failed);
+ i_assert(sctx->finished);
+ i_assert(sctx->scriptname != NULL);
+
+ /* Check whether we're replacing the default active script */
+ if (storage->default_name != NULL &&
+ storage->default_location != NULL &&
+ (storage->flags & SIEVE_STORAGE_FLAG_SYNCHRONIZING) == 0 &&
+ strcmp(sctx->scriptname, storage->default_name) == 0 &&
+ sieve_storage_save_will_activate(sctx) &&
+ sieve_storage_check_script_direct(storage, storage->default_name,
+ NULL) <= 0)
+ default_activate = TRUE;
+
+ sieve_storage_save_cleanup(sctx);
+
+ i_assert(storage->v.save_commit != NULL);
+ ret = storage->v.save_commit(sctx);
+
+ /* Implicitly activate it when we're replacing the default
+ active script */
+ if (ret >= 0 && default_activate) {
+ struct sieve_script *script;
+ enum sieve_error error;
+
+ script = sieve_storage_open_script(storage, scriptname, &error);
+ if (script == NULL) {
+ /* Somehow not actually saved */
+ ret = (error == SIEVE_ERROR_NOT_FOUND ? 0 : -1);
+ } else if (sieve_script_activate(script, (time_t)-1) < 0) {
+ /* Failed to activate; roll back */
+ ret = -1;
+ (void)sieve_script_delete(script, TRUE);
+ }
+ if (script != NULL)
+ sieve_script_unref(&script);
+
+ if (ret < 0) {
+ e_error(sctx->event,
+ "Failed to implicitly activate script `%s' "
+ "while replacing the default active script",
+ scriptname);
+ }
+ }
+
+ if (ret >= 0) {
+ struct event_passthrough *e =
+ event_create_passthrough(sctx->event)->
+ set_name("sieve_storage_save_finished");
+ e_debug(e->event(), "Finished saving script");
+
+ /* set INBOX mailbox attribute */
+ (void)sieve_storage_sync_script_save(storage, scriptname);
+ } else {
+ struct event_passthrough *e =
+ event_create_passthrough(sctx->event)->
+ add_str("error", storage->error)->
+ set_name("sieve_storage_save_finished");
+
+ e_debug(e->event(), "Failed to save script: %s",
+ storage->error);
+ }
+
+ sieve_storage_save_deinit(&sctx);
+ return ret;
+}
+
+void sieve_storage_save_cancel(struct sieve_storage_save_context **_sctx)
+{
+ struct sieve_storage_save_context *sctx = *_sctx;
+ struct sieve_storage *storage;
+
+ *_sctx = NULL;
+ if (sctx == NULL)
+ return;
+
+ storage = sctx->storage;
+
+ sctx->failed = TRUE;
+
+ sieve_storage_save_cleanup(sctx);
+
+ if (!sctx->finished)
+ (void)sieve_storage_save_finish(sctx);
+
+ struct event_passthrough *e =
+ event_create_passthrough(sctx->event)->
+ add_str("error", "Canceled")->
+ set_name("sieve_storage_save_finished");
+ e_debug(e->event(), "Canceled saving script");
+
+ i_assert(storage->v.save_cancel != NULL);
+ storage->v.save_cancel(sctx);
+
+ sieve_storage_save_deinit(&sctx);
+}
+
+int sieve_storage_save_as_active(struct sieve_storage *storage,
+ struct istream *input, time_t mtime)
+{
+ struct event *event;
+ int ret;
+
+ event = event_create(storage->event);
+ event_set_append_log_prefix(event, "active script: save: ");
+
+ struct event_passthrough *e =
+ event_create_passthrough(event)->
+ set_name("sieve_storage_save_started");
+ e_debug(e->event(), "Started saving active script");
+
+ i_assert(storage->v.save_as_active != NULL);
+ ret = storage->v.save_as_active(storage, input, mtime);
+
+ if (ret >= 0) {
+ struct event_passthrough *e =
+ event_create_passthrough(event)->
+ set_name("sieve_storage_save_finished");
+ e_debug(e->event(), "Finished saving active script");
+ } else {
+ struct event_passthrough *e =
+ event_create_passthrough(event)->
+ add_str("error", storage->error)->
+ set_name("sieve_storage_save_finished");
+ e_debug(e->event(), "Failed to save active script: %s",
+ storage->error);
+ }
+
+ event_unref(&event);
+ return ret;
+}
+
+int sieve_storage_save_as(struct sieve_storage *storage, struct istream *input,
+ const char *name)
+{
+ struct event *event;
+ int ret;
+
+ event = sieve_storage_save_create_event(storage, name);
+
+ struct event_passthrough *e =
+ event_create_passthrough(event)->
+ set_name("sieve_storage_save_started");
+ e_debug(e->event(), "Started saving script");
+
+ i_assert(storage->v.save_as != NULL);
+ ret = storage->v.save_as(storage, input, name);
+
+ if (ret >= 0) {
+ struct event_passthrough *e =
+ event_create_passthrough(event)->
+ set_name("sieve_storage_save_finished");
+ e_debug(e->event(), "Finished saving sieve script");
+ } else {
+ struct event_passthrough *e =
+ event_create_passthrough(event)->
+ add_str("error", storage->error)->
+ set_name("sieve_storage_save_finished");
+ e_debug(e->event(), "Failed to save script: %s",
+ storage->error);
+ }
+
+ event_unref(&event);
+ return ret;
+}
+
+/*
+ * Checking quota
+ */
+
+bool sieve_storage_quota_validsize(struct sieve_storage *storage, size_t size,
+ uint64_t *limit_r)
+{
+ uint64_t max_size;
+
+ max_size = sieve_max_script_size(storage->svinst);
+ if (max_size > 0 && size > max_size) {
+ *limit_r = max_size;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+uint64_t sieve_storage_quota_max_script_size(struct sieve_storage *storage)
+{
+ return sieve_max_script_size(storage->svinst);
+}
+
+int sieve_storage_quota_havespace(struct sieve_storage *storage,
+ const char *scriptname, size_t size,
+ enum sieve_storage_quota *quota_r,
+ uint64_t *limit_r)
+{
+ *quota_r = SIEVE_STORAGE_QUOTA_NONE;
+ *limit_r = 0;
+
+ /* Check the script size */
+ if (!sieve_storage_quota_validsize(storage, size, limit_r)) {
+ *quota_r = SIEVE_STORAGE_QUOTA_MAXSIZE;
+ return 0;
+ }
+
+ /* Do we need to scan the storage (quota enabled) ? */
+ if (storage->max_scripts == 0 && storage->max_storage == 0)
+ return 1;
+
+ if (storage->v.quota_havespace == NULL)
+ return 1;
+
+ return storage->v.quota_havespace(storage, scriptname, size,
+ quota_r, limit_r);
+}
+
+/*
+ * Properties
+ */
+
+const char *sieve_storage_location(const struct sieve_storage *storage)
+{
+ return storage->location;
+}
+
+bool sieve_storage_is_default(const struct sieve_storage *storage)
+{
+ return storage->is_default;
+}
+
+/*
+ * Error handling
+ */
+
+void sieve_storage_clear_error(struct sieve_storage *storage)
+{
+ i_free(storage->error);
+ storage->error_code = SIEVE_ERROR_NONE;
+ storage->error = NULL;
+}
+
+void sieve_storage_set_error(struct sieve_storage *storage,
+ enum sieve_error error, const char *fmt, ...)
+{
+ va_list va;
+
+ sieve_storage_clear_error(storage);
+
+ if (fmt != NULL) {
+ va_start(va, fmt);
+ storage->error = i_strdup_vprintf(fmt, va);
+ va_end(va);
+ }
+
+ storage->error_code = error;
+}
+
+void sieve_storage_copy_error(struct sieve_storage *storage,
+ const struct sieve_storage *source)
+{
+ sieve_storage_clear_error(storage);
+ storage->error = i_strdup(source->error);
+ storage->error_code = source->error_code;
+}
+
+void sieve_storage_set_internal_error(struct sieve_storage *storage)
+{
+ struct tm *tm;
+ char str[256];
+
+ sieve_storage_clear_error(storage);
+
+ /* critical errors may contain sensitive data, so let user
+ see only "Internal error" with a timestamp to make it
+ easier to look from log files the actual error message. */
+ tm = localtime(&ioloop_time);
+
+ storage->error =
+ (strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ?
+ i_strdup(str) : i_strdup(CRITICAL_MSG));
+
+ storage->error_code = SIEVE_ERROR_TEMP_FAILURE;
+}
+
+void sieve_storage_set_critical(struct sieve_storage *storage,
+ const char *fmt, ...)
+{
+ va_list va;
+
+ if (fmt != NULL) {
+ if ((storage->flags & SIEVE_STORAGE_FLAG_SYNCHRONIZING) == 0) {
+ va_start(va, fmt);
+ e_error(storage->svinst->event, "%s storage: %s",
+ storage->driver_name,
+ t_strdup_vprintf(fmt, va));
+ va_end(va);
+
+ sieve_storage_set_internal_error(storage);
+
+ } else {
+ sieve_storage_clear_error(storage);
+
+ /* no user is involved while synchronizing, so do it the
+ normal way */
+ va_start(va, fmt);
+ storage->error = i_strdup_vprintf(fmt, va);
+ va_end(va);
+
+ storage->error_code = SIEVE_ERROR_TEMP_FAILURE;
+ }
+ }
+}
+
+const char *
+sieve_storage_get_last_error(struct sieve_storage *storage,
+ enum sieve_error *error_r)
+{
+ /* We get here only in error situations, so we have to return some
+ error. If storage->error is NULL, it means we forgot to set it at
+ some point..
+ */
+
+ if (error_r != NULL)
+ *error_r = storage->error_code;
+
+ return storage->error != NULL ? storage->error : "Unknown error";
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-storage.h b/pigeonhole/src/lib-sieve/sieve-storage.h
new file mode 100644
index 0000000..125a86e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-storage.h
@@ -0,0 +1,187 @@
+#ifndef SIEVE_STORAGE_H
+#define SIEVE_STORAGE_H
+
+#define MAILBOX_ATTRIBUTE_PREFIX_SIEVE \
+ MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER"sieve/"
+#define MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES \
+ MAILBOX_ATTRIBUTE_PREFIX_SIEVE"files/"
+#define MAILBOX_ATTRIBUTE_SIEVE_DEFAULT \
+ MAILBOX_ATTRIBUTE_PREFIX_SIEVE"default"
+
+#define MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_LINK 'L'
+#define MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_SCRIPT 'S'
+
+/*
+ * Storage object
+ */
+
+enum sieve_storage_flags {
+ /* Storage is opened for read/write access (e.g. ManageSieve) */
+ SIEVE_STORAGE_FLAG_READWRITE = 0x01,
+ /* This storage is used for synchronization (and not normal ManageSieve)
+ */
+ SIEVE_STORAGE_FLAG_SYNCHRONIZING = 0x02
+};
+
+struct sieve_storage;
+
+struct sieve_storage *
+sieve_storage_create(struct sieve_instance *svinst, const char *location,
+ enum sieve_storage_flags flags, enum sieve_error *error_r)
+ ATTR_NULL(4);
+struct sieve_storage *
+sieve_storage_create_main(struct sieve_instance *svinst, struct mail_user *user,
+ enum sieve_storage_flags flags,
+ enum sieve_error *error_r) ATTR_NULL(4);
+
+void sieve_storage_ref(struct sieve_storage *storage);
+void sieve_storage_unref(struct sieve_storage **_storage);
+
+/*
+ * Script access
+ */
+
+struct sieve_script *
+sieve_storage_get_script(struct sieve_storage *storage, const char *name,
+ enum sieve_error *error_r) ATTR_NULL(3);
+struct sieve_script *
+sieve_storage_open_script(struct sieve_storage *storage, const char *name,
+ enum sieve_error *error_r) ATTR_NULL(3);
+int sieve_storage_check_script(struct sieve_storage *storage, const char *name,
+ enum sieve_error *error_r) ATTR_NULL(3);
+
+/*
+ * Script sequence
+ */
+
+struct sieve_script_sequence *
+sieve_storage_get_script_sequence(struct sieve_storage *storage,
+ enum sieve_error *error_r);
+
+/*
+ * Active script
+ */
+
+int sieve_storage_active_script_get_name(struct sieve_storage *storage,
+ const char **name_r);
+
+struct sieve_script *
+sieve_storage_active_script_open(struct sieve_storage *storage,
+ enum sieve_error *error_r) ATTR_NULL(2);
+
+int sieve_storage_active_script_get_last_change(struct sieve_storage *storage,
+ time_t *last_change_r);
+
+/*
+ * Listing scripts in storage
+ */
+
+struct sieve_storage_list_context;
+
+/* Create a context for listing the scripts in the storage */
+struct sieve_storage_list_context *
+sieve_storage_list_init(struct sieve_storage *storage);
+/* Get the next script in the storage. */
+const char *sieve_storage_list_next(struct sieve_storage_list_context *lctx,
+ bool *active_r) ATTR_NULL(2);
+/* Destroy the listing context */
+int sieve_storage_list_deinit(struct sieve_storage_list_context **lctx);
+
+/*
+ * Saving scripts in storage
+ */
+
+struct sieve_storage_save_context;
+
+struct sieve_storage_save_context *
+sieve_storage_save_init(struct sieve_storage *storage, const char *scriptname,
+ struct istream *input);
+
+int sieve_storage_save_continue(struct sieve_storage_save_context *sctx);
+
+int sieve_storage_save_finish(struct sieve_storage_save_context *sctx);
+
+struct sieve_script *
+sieve_storage_save_get_tempscript(struct sieve_storage_save_context *sctx);
+
+bool sieve_storage_save_will_activate(struct sieve_storage_save_context *sctx);
+
+void sieve_storage_save_set_mtime(struct sieve_storage_save_context *sctx,
+ time_t mtime);
+
+void sieve_storage_save_cancel(struct sieve_storage_save_context **sctx);
+
+int sieve_storage_save_commit(struct sieve_storage_save_context **sctx);
+
+int sieve_storage_save_as(struct sieve_storage *storage, struct istream *input,
+ const char *name);
+
+/* Saves input directly as a regular file at the active script path.
+ * This is needed for the doveadm-sieve plugin.
+ */
+int sieve_storage_save_as_active(struct sieve_storage *storage,
+ struct istream *input, time_t mtime);
+
+/*
+ * Management
+ */
+
+int sieve_storage_deactivate(struct sieve_storage *storage, time_t mtime);
+
+/*
+ * Storage quota
+ */
+
+enum sieve_storage_quota {
+ SIEVE_STORAGE_QUOTA_NONE,
+ SIEVE_STORAGE_QUOTA_MAXSIZE,
+ SIEVE_STORAGE_QUOTA_MAXSCRIPTS,
+ SIEVE_STORAGE_QUOTA_MAXSTORAGE
+};
+
+bool sieve_storage_quota_validsize(struct sieve_storage *storage, size_t size,
+ uint64_t *limit_r);
+
+uint64_t sieve_storage_quota_max_script_size(struct sieve_storage *storage);
+
+int sieve_storage_quota_havespace(struct sieve_storage *storage,
+ const char *scriptname, size_t size,
+ enum sieve_storage_quota *quota_r,
+ uint64_t *limit_r);
+
+/*
+ * Properties
+ */
+
+const char *sieve_storage_location(const struct sieve_storage *storage)
+ ATTR_PURE;
+bool sieve_storage_is_default(const struct sieve_storage *storage) ATTR_PURE;
+
+int sieve_storage_is_singular(struct sieve_storage *storage);
+
+/*
+ * Error handling
+ */
+
+void sieve_storage_clear_error(struct sieve_storage *storage);
+
+void sieve_storage_set_error(struct sieve_storage *storage,
+ enum sieve_error error, const char *fmt, ...)
+ ATTR_FORMAT(3, 4);
+void sieve_storage_set_critical(struct sieve_storage *storage,
+ const char *fmt, ...) ATTR_FORMAT(2, 3);
+
+const char *sieve_storage_get_last_error(struct sieve_storage *storage,
+ enum sieve_error *error_r)
+ ATTR_NULL(2);
+
+/*
+ *
+ */
+
+int sieve_storage_get_last_change(struct sieve_storage *storage,
+ time_t *last_change_r);
+void sieve_storage_set_modified(struct sieve_storage *storage,
+ time_t mtime);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-stringlist.c b/pigeonhole/src/lib-sieve/sieve-stringlist.c
new file mode 100644
index 0000000..17b7d5c
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-stringlist.c
@@ -0,0 +1,276 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+
+/*
+ * Default implementation
+ */
+
+int sieve_stringlist_read_all
+(struct sieve_stringlist *strlist, pool_t pool,
+ const char * const **list_r)
+{
+ if ( strlist->read_all == NULL ) {
+ ARRAY(const char *) items;
+ string_t *item;
+ int ret;
+
+ sieve_stringlist_reset(strlist);
+
+ p_array_init(&items, pool, 4);
+
+ item = NULL;
+ while ( (ret=sieve_stringlist_next_item(strlist, &item)) > 0 ) {
+ const char *stritem = p_strdup(pool, str_c(item));
+
+ array_append(&items, &stritem, 1);
+ }
+
+ (void)array_append_space(&items);
+ *list_r = array_idx(&items, 0);
+
+ return ( ret < 0 ? -1 : 1 );
+ }
+
+ return strlist->read_all(strlist, pool, list_r);
+}
+
+int sieve_stringlist_get_length
+(struct sieve_stringlist *strlist)
+{
+ if ( strlist->get_length == NULL ) {
+ string_t *item;
+ int count = 0;
+ int ret;
+
+ sieve_stringlist_reset(strlist);
+ while ( (ret=sieve_stringlist_next_item(strlist, &item)) > 0 ) {
+ count++;
+ }
+ sieve_stringlist_reset(strlist);
+
+ return ( ret < 0 ? -1 : count );
+ }
+
+ return strlist->get_length(strlist);
+}
+
+/*
+ * Single Stringlist
+ */
+
+/* Object */
+
+static int sieve_single_stringlist_next_item
+ (struct sieve_stringlist *_strlist, string_t **str_r);
+static void sieve_single_stringlist_reset
+ (struct sieve_stringlist *_strlist);
+static int sieve_single_stringlist_get_length
+ (struct sieve_stringlist *_strlist);
+
+struct sieve_single_stringlist {
+ struct sieve_stringlist strlist;
+
+ string_t *value;
+
+ bool end:1;
+ bool count_empty:1;
+};
+
+struct sieve_stringlist *sieve_single_stringlist_create
+(const struct sieve_runtime_env *renv, string_t *str, bool count_empty)
+{
+ struct sieve_single_stringlist *strlist;
+
+ strlist = t_new(struct sieve_single_stringlist, 1);
+ strlist->strlist.runenv = renv;
+ strlist->strlist.exec_status = SIEVE_EXEC_OK;
+ strlist->strlist.next_item = sieve_single_stringlist_next_item;
+ strlist->strlist.reset = sieve_single_stringlist_reset;
+ strlist->strlist.get_length = sieve_single_stringlist_get_length;
+ strlist->count_empty = count_empty;
+ strlist->value = str;
+
+ return &strlist->strlist;
+}
+
+struct sieve_stringlist *sieve_single_stringlist_create_cstr
+(const struct sieve_runtime_env *renv, const char *cstr, bool count_empty)
+{
+ string_t *str = t_str_new_const(cstr, strlen(cstr));
+
+ return sieve_single_stringlist_create(renv, str, count_empty);
+}
+
+/* Implementation */
+
+static int sieve_single_stringlist_next_item
+(struct sieve_stringlist *_strlist, string_t **str_r)
+{
+ struct sieve_single_stringlist *strlist =
+ (struct sieve_single_stringlist *)_strlist;
+
+ if ( strlist->end ) {
+ *str_r = NULL;
+ return 0;
+ }
+
+ *str_r = strlist->value;
+ strlist->end = TRUE;
+ return 1;
+}
+
+static void sieve_single_stringlist_reset
+(struct sieve_stringlist *_strlist)
+{
+ struct sieve_single_stringlist *strlist =
+ (struct sieve_single_stringlist *)_strlist;
+
+ strlist->end = FALSE;
+}
+
+static int sieve_single_stringlist_get_length
+(struct sieve_stringlist *_strlist)
+{
+ struct sieve_single_stringlist *strlist =
+ (struct sieve_single_stringlist *)_strlist;
+
+ return ( strlist->count_empty || str_len(strlist->value) > 0 ? 1 : 0 );
+}
+
+/*
+ * Index Stringlist
+ */
+
+/* Object */
+
+static int sieve_index_stringlist_next_item
+ (struct sieve_stringlist *_strlist, string_t **str_r);
+static void sieve_index_stringlist_reset
+ (struct sieve_stringlist *_strlist);
+static int sieve_index_stringlist_get_length
+ (struct sieve_stringlist *_strlist);
+static void sieve_index_stringlist_set_trace
+ (struct sieve_stringlist *strlist, bool trace);
+
+struct sieve_index_stringlist {
+ struct sieve_stringlist strlist;
+
+ struct sieve_stringlist *source;
+
+ int index;
+ bool end:1;
+};
+
+struct sieve_stringlist *sieve_index_stringlist_create
+(const struct sieve_runtime_env *renv, struct sieve_stringlist *source,
+ int index)
+{
+ struct sieve_index_stringlist *strlist;
+
+ strlist = t_new(struct sieve_index_stringlist, 1);
+ strlist->strlist.runenv = renv;
+ strlist->strlist.exec_status = SIEVE_EXEC_OK;
+ strlist->strlist.next_item = sieve_index_stringlist_next_item;
+ strlist->strlist.reset = sieve_index_stringlist_reset;
+ strlist->strlist.get_length = sieve_index_stringlist_get_length;
+ strlist->strlist.set_trace = sieve_index_stringlist_set_trace;
+ strlist->source = source;
+ strlist->index = index;
+
+ return &strlist->strlist;
+}
+
+/* Implementation */
+
+static int sieve_index_stringlist_next_item
+(struct sieve_stringlist *_strlist, string_t **str_r)
+{
+ struct sieve_index_stringlist *strlist =
+ (struct sieve_index_stringlist *)_strlist;
+ int index, ret;
+
+ if ( strlist->end ) {
+ *str_r = NULL;
+ return 0;
+ }
+
+ if ( strlist->index < 0 ) {
+ int len = sieve_stringlist_get_length(strlist->source);
+ if (len < 0) {
+ _strlist->exec_status = strlist->source->exec_status;
+ return -1;
+ }
+
+ if (len < -strlist->index) {
+ *str_r = NULL;
+ strlist->end = TRUE;
+ return 0;
+ }
+ index = len + 1 + strlist->index;
+ } else {
+ index = strlist->index;
+ }
+
+ i_assert(index > 0);
+ while ( index > 0 ) {
+ if ( (ret=sieve_stringlist_next_item(strlist->source, str_r)) <= 0 ) {
+ if (ret < 0)
+ _strlist->exec_status = strlist->source->exec_status;
+ return ret;
+ }
+
+ index--;
+ }
+
+ strlist->end = TRUE;
+ return 1;
+}
+
+static void sieve_index_stringlist_reset
+(struct sieve_stringlist *_strlist)
+{
+ struct sieve_index_stringlist *strlist =
+ (struct sieve_index_stringlist *)_strlist;
+
+ sieve_stringlist_reset(strlist->source);
+ strlist->end = FALSE;
+}
+
+static int sieve_index_stringlist_get_length
+(struct sieve_stringlist *_strlist)
+{
+ struct sieve_index_stringlist *strlist =
+ (struct sieve_index_stringlist *)_strlist;
+ int len;
+
+ len = sieve_stringlist_get_length(strlist->source);
+ if (len < 0) {
+ _strlist->exec_status = strlist->source->exec_status;
+ return -1;
+ }
+
+ if ( strlist->index < 0 ) {
+ if ( -strlist->index >= len )
+ return 0;
+ } else if ( strlist->index >= len ) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static void sieve_index_stringlist_set_trace
+(struct sieve_stringlist *_strlist, bool trace)
+{
+ struct sieve_index_stringlist *strlist =
+ (struct sieve_index_stringlist *)_strlist;
+
+ sieve_stringlist_set_trace(strlist->source, trace);
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-stringlist.h b/pigeonhole/src/lib-sieve/sieve-stringlist.h
new file mode 100644
index 0000000..1909b7a
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-stringlist.h
@@ -0,0 +1,74 @@
+#ifndef SIEVE_STRINGLIST_H
+#define SIEVE_STRINGLIST_H
+
+/*
+ * Stringlist API
+ */
+
+struct sieve_stringlist {
+ int (*next_item)
+ (struct sieve_stringlist *strlist, string_t **str_r);
+ void (*reset)
+ (struct sieve_stringlist *strlist);
+ int (*get_length)
+ (struct sieve_stringlist *strlist);
+
+ int (*read_all)
+ (struct sieve_stringlist *strlist, pool_t pool,
+ const char * const **list_r);
+
+ void (*set_trace)
+ (struct sieve_stringlist *strlist, bool trace);
+
+ const struct sieve_runtime_env *runenv;
+ int exec_status;
+
+ bool trace:1;
+};
+
+static inline void sieve_stringlist_set_trace
+(struct sieve_stringlist *strlist, bool trace)
+{
+ strlist->trace = trace;
+
+ if ( strlist->set_trace != NULL )
+ strlist->set_trace(strlist, trace);
+}
+
+static inline int sieve_stringlist_next_item
+(struct sieve_stringlist *strlist, string_t **str_r)
+{
+ return strlist->next_item(strlist, str_r);
+}
+
+static inline void sieve_stringlist_reset
+(struct sieve_stringlist *strlist)
+{
+ strlist->reset(strlist);
+}
+
+int sieve_stringlist_get_length
+ (struct sieve_stringlist *strlist);
+
+int sieve_stringlist_read_all
+ (struct sieve_stringlist *strlist, pool_t pool,
+ const char * const **list_r);
+
+/*
+ * Single Stringlist
+ */
+
+struct sieve_stringlist *sieve_single_stringlist_create
+ (const struct sieve_runtime_env *renv, string_t *str, bool count_empty);
+struct sieve_stringlist *sieve_single_stringlist_create_cstr
+(const struct sieve_runtime_env *renv, const char *cstr, bool count_empty);
+
+/*
+ * Index Stringlist
+ */
+
+struct sieve_stringlist *sieve_index_stringlist_create
+ (const struct sieve_runtime_env *renv, struct sieve_stringlist *source,
+ int index);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-types.h b/pigeonhole/src/lib-sieve/sieve-types.h
new file mode 100644
index 0000000..439b26e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-types.h
@@ -0,0 +1,316 @@
+#ifndef SIEVE_TYPES_H
+#define SIEVE_TYPES_H
+
+#include "lib.h"
+#include "smtp-address.h"
+
+#include <stdio.h>
+
+/*
+ * Forward declarations
+ */
+
+struct smtp_params_mail;
+struct smtp_params_rcpt;
+
+struct sieve_instance;
+struct sieve_callbacks;
+
+struct sieve_script;
+struct sieve_binary;
+
+struct sieve_message_data;
+struct sieve_script_env;
+struct sieve_exec_status;
+struct sieve_trace_log;
+
+/*
+ * System environment
+ */
+
+enum sieve_flag {
+ /* Relative paths are resolved to HOME */
+ SIEVE_FLAG_HOME_RELATIVE = (1 << 0)
+};
+
+/* Sieve evaluation can be performed at various different points as messages
+ are processed. */
+enum sieve_env_location {
+ /* Unknown */
+ SIEVE_ENV_LOCATION_UNKNOWN = 0,
+ /* "MDA" - evaluation is being performed by a Mail Delivery Agent */
+ SIEVE_ENV_LOCATION_MDA,
+ /* "MTA" - the Sieve script is being evaluated by a Message Transfer Agent */
+ SIEVE_ENV_LOCATION_MTA,
+ /* "MS" - evaluation is being performed by a Message Store */
+ SIEVE_ENV_LOCATION_MS
+};
+
+/* The point relative to final delivery where the Sieve script is being
+ evaluated. */
+enum sieve_delivery_phase {
+ SIEVE_DELIVERY_PHASE_UNKNOWN = 0,
+ SIEVE_DELIVERY_PHASE_PRE,
+ SIEVE_DELIVERY_PHASE_DURING,
+ SIEVE_DELIVERY_PHASE_POST,
+};
+
+struct sieve_environment {
+ const char *hostname;
+ const char *domainname;
+
+ const char *base_dir;
+ const char *username;
+ const char *home_dir;
+ const char *temp_dir;
+
+ struct event *event_parent;
+
+ enum sieve_flag flags;
+ enum sieve_env_location location;
+ enum sieve_delivery_phase delivery_phase;
+};
+
+/*
+ * Callbacks
+ */
+
+struct sieve_callbacks {
+ const char *(*get_homedir)(void *context);
+ const char *(*get_setting)(void *context, const char *identifier);
+};
+
+/*
+ * Errors
+ */
+
+enum sieve_error {
+ SIEVE_ERROR_NONE = 0,
+
+ /* Temporary internal error */
+ SIEVE_ERROR_TEMP_FAILURE,
+ /* It's not possible to do the wanted operation */
+ SIEVE_ERROR_NOT_POSSIBLE,
+ /* Invalid parameters (eg. script name not valid) */
+ SIEVE_ERROR_BAD_PARAMS,
+ /* No permission to do the request */
+ SIEVE_ERROR_NO_PERMISSION,
+ /* Out of disk space */
+ SIEVE_ERROR_NO_QUOTA,
+ /* Item (e.g. script or binary) cannot be found */
+ SIEVE_ERROR_NOT_FOUND,
+ /* Item (e.g. script or binary) already exists */
+ SIEVE_ERROR_EXISTS,
+ /* Referenced item (e.g. script or binary) is not valid or currupt */
+ SIEVE_ERROR_NOT_VALID,
+ /* Not allowed to perform the operation because the item is in active use */
+ SIEVE_ERROR_ACTIVE,
+ /* Operation exceeds resource limit */
+ SIEVE_ERROR_RESOURCE_LIMIT,
+};
+
+/*
+ * Compile flags
+ */
+
+enum sieve_compile_flags {
+ /* No global extensions are allowed
+ * (as marked by sieve_global_extensions setting)
+ */
+ SIEVE_COMPILE_FLAG_NOGLOBAL = (1<<0),
+ /* Script is being uploaded (usually through ManageSieve) */
+ SIEVE_COMPILE_FLAG_UPLOADED = (1<<1),
+ /* Script is being activated (usually through ManageSieve) */
+ SIEVE_COMPILE_FLAG_ACTIVATED = (1<<2),
+ /* Compiled for environment with no access to envelope */
+ SIEVE_COMPILE_FLAG_NO_ENVELOPE = (1<<3)
+};
+
+/*
+ * Message data
+ *
+ * - The mail message + envelope data
+ */
+
+struct sieve_message_data {
+ struct mail *mail;
+
+ const char *auth_user;
+ const char *id;
+
+ struct {
+ const struct smtp_address *mail_from;
+ const struct smtp_params_mail *mail_params;
+
+ const struct smtp_address *rcpt_to;
+ const struct smtp_params_rcpt *rcpt_params;
+ } envelope;
+};
+
+/*
+ * Runtime flags
+ */
+
+enum sieve_execute_flags {
+ /* No global extensions are allowed
+ * (as marked by sieve_global_extensions setting)
+ */
+ SIEVE_EXECUTE_FLAG_NOGLOBAL = (1<<0),
+ /* Do not execute (implicit keep) at the end */
+ SIEVE_EXECUTE_FLAG_DEFER_KEEP = (1<<1),
+ /* There is no envelope */
+ SIEVE_EXECUTE_FLAG_NO_ENVELOPE = (1<<2),
+ /* Skip sending responses */
+ SIEVE_EXECUTE_FLAG_SKIP_RESPONSES = (1<<3),
+ /* Log result as info (when absent, only debug logging is performed) */
+ SIEVE_EXECUTE_FLAG_LOG_RESULT = (1<<4),
+};
+
+/*
+ * Runtime trace settings
+ */
+
+typedef enum {
+ SIEVE_TRLVL_NONE = 0,
+ SIEVE_TRLVL_ACTIONS,
+ SIEVE_TRLVL_COMMANDS,
+ SIEVE_TRLVL_TESTS,
+ SIEVE_TRLVL_MATCHING
+} sieve_trace_level_t;
+
+enum {
+ SIEVE_TRFLG_DEBUG = (1 << 0),
+ SIEVE_TRFLG_ADDRESSES = (1 << 1)
+};
+
+struct sieve_trace_config {
+ sieve_trace_level_t level;
+ unsigned int flags;
+};
+
+/*
+ * Duplicate checking
+ */
+
+enum sieve_duplicate_check_result {
+ SIEVE_DUPLICATE_CHECK_RESULT_EXISTS = 1,
+ SIEVE_DUPLICATE_CHECK_RESULT_NOT_FOUND = 0,
+ SIEVE_DUPLICATE_CHECK_RESULT_FAILURE = -1,
+ SIEVE_DUPLICATE_CHECK_RESULT_TEMP_FAILURE = -2,
+};
+
+/*
+ * Script environment
+ *
+ * - Environment for currently executing script
+ */
+
+struct sieve_script_env {
+ /* Mail-related */
+ struct mail_user *user;
+ const struct message_address *postmaster_address;
+ const char *default_mailbox;
+ bool mailbox_autocreate;
+ bool mailbox_autosubscribe;
+
+ /* External context data */
+
+ void *script_context;
+
+ /* Callbacks */
+
+ /* Interface for sending mail */
+ void *(*smtp_start)
+ (const struct sieve_script_env *senv,
+ const struct smtp_address *mail_from);
+ /* Add a new recipient */
+ void (*smtp_add_rcpt)
+ (const struct sieve_script_env *senv, void *handle,
+ const struct smtp_address *rcpt_to);
+ /* Get an output stream where the message can be written to. The recipients
+ must already be added before calling this. */
+ struct ostream *(*smtp_send)
+ (const struct sieve_script_env *senv, void *handle);
+ /* Abort the SMTP transaction after smtp_send() is already issued */
+ void (*smtp_abort)
+ (const struct sieve_script_env *senv, void *handle);
+ /* Returns 1 on success, 0 on permanent failure, -1 on temporary failure. */
+ int (*smtp_finish)
+ (const struct sieve_script_env *senv, void *handle,
+ const char **error_r);
+
+ /* Interface for marking and checking duplicates */
+ void *(*duplicate_transaction_begin)(
+ const struct sieve_script_env *senv);
+ void (*duplicate_transaction_commit)(void **_dup_trans);
+ void (*duplicate_transaction_rollback)(void **_dup_trans);
+
+ enum sieve_duplicate_check_result
+ (*duplicate_check)(void *dup_trans, const struct sieve_script_env *senv,
+ const void *id, size_t id_size);
+ void (*duplicate_mark)(void *dup_trans,
+ const struct sieve_script_env *senv,
+ const void *id, size_t id_size, time_t time);
+
+ /* Interface for rejecting mail */
+ int (*reject_mail)(const struct sieve_script_env *senv,
+ const struct smtp_address *recipient, const char *reason);
+
+ /* Interface for amending result messages */
+ const char *
+ (*result_amend_log_message)(const struct sieve_script_env *senv,
+ enum log_type log_type,
+ const char *message);
+
+ /* Execution status record */
+ struct sieve_exec_status *exec_status;
+
+ /* Runtime trace*/
+ struct sieve_trace_log *trace_log;
+ struct sieve_trace_config trace_config;
+};
+
+#define SIEVE_SCRIPT_DEFAULT_MAILBOX(senv) \
+ (senv->default_mailbox == NULL ? "INBOX" : senv->default_mailbox )
+
+/*
+ * Resource usage
+ */
+
+struct sieve_resource_usage {
+ /* The total amount of system + user CPU time consumed while executing
+ the Sieve script. */
+ unsigned int cpu_time_msecs;
+};
+
+/*
+ * Script execution status
+ */
+
+struct sieve_exec_status {
+ struct mail_storage *last_storage;
+
+ struct sieve_resource_usage resource_usage;
+
+ bool message_saved:1;
+ bool message_forwarded:1;
+ bool tried_default_save:1;
+ bool keep_original:1;
+ bool store_failed:1;
+ bool significant_action_executed:1;
+};
+
+/*
+ * Execution exit codes
+ */
+
+enum sieve_execution_exitcode {
+ SIEVE_EXEC_OK = 1,
+ SIEVE_EXEC_FAILURE = 0,
+ SIEVE_EXEC_TEMP_FAILURE = -1,
+ SIEVE_EXEC_BIN_CORRUPT = -2,
+ SIEVE_EXEC_KEEP_FAILED = -3,
+ SIEVE_EXEC_RESOURCE_LIMIT = -4,
+};
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve-validator.c b/pigeonhole/src/lib-sieve/sieve-validator.c
new file mode 100644
index 0000000..bef4a7d
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-validator.c
@@ -0,0 +1,1706 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "array.h"
+#include "buffer.h"
+#include "mempool.h"
+#include "hash.h"
+
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+#include "sieve-script.h"
+#include "sieve-ast.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+
+#include "sieve-comparators.h"
+#include "sieve-address-parts.h"
+
+/*
+ * Forward declarations
+ */
+
+static void
+sieve_validator_register_core_commands(struct sieve_validator *valdtr);
+static void
+sieve_validator_register_core_tests(struct sieve_validator *valdtr);
+
+/*
+ * Types
+ */
+
+/* Tag registration */
+
+struct sieve_tag_registration {
+ const struct sieve_argument_def *tag_def;
+ const struct sieve_extension *ext;
+
+ const char *identifier;
+ int id_code;
+};
+
+/* Command registration */
+
+struct sieve_command_registration {
+ const struct sieve_command_def *cmd_def;
+ const struct sieve_extension *ext;
+
+ ARRAY(struct sieve_tag_registration *) normal_tags;
+ ARRAY(struct sieve_tag_registration *) instanced_tags;
+ ARRAY(struct sieve_tag_registration *) persistent_tags;
+};
+
+/* Default (literal) arguments */
+
+struct sieve_default_argument {
+ const struct sieve_argument_def *arg_def;
+ const struct sieve_extension *ext;
+
+ struct sieve_default_argument *overrides;
+};
+
+/*
+ * Validator extension
+ */
+
+struct sieve_validator_extension_reg {
+ const struct sieve_validator_extension *valext;
+ const struct sieve_extension *ext;
+ struct sieve_ast_argument *arg;
+ void *context;
+
+ bool loaded:1;
+ bool required:1;
+};
+
+/*
+ * Validator
+ */
+
+struct sieve_validator {
+ pool_t pool;
+
+ struct sieve_instance *svinst;
+ struct sieve_ast *ast;
+ struct sieve_script *script;
+ enum sieve_compile_flags flags;
+
+ struct sieve_error_handler *ehandler;
+
+ bool finished_require;
+
+ /* Registries */
+
+ HASH_TABLE(const char *, struct sieve_command_registration *) commands;
+
+ ARRAY(struct sieve_validator_extension_reg) extensions;
+
+ /* This is currently a wee bit ugly and needs more thought */
+ struct sieve_default_argument default_arguments[SAT_COUNT];
+
+ /* Default argument processing state (FIXME: ugly) */
+ struct sieve_default_argument *current_defarg;
+ enum sieve_argument_type current_defarg_type;
+ bool current_defarg_constant;
+};
+
+/*
+ * Validator object
+ */
+
+struct sieve_validator *
+sieve_validator_create(struct sieve_ast *ast,
+ struct sieve_error_handler *ehandler,
+ enum sieve_compile_flags flags)
+{
+ pool_t pool;
+ struct sieve_validator *valdtr;
+ const struct sieve_extension *const *ext_preloaded;
+ unsigned int i, ext_count;
+
+ pool = pool_alloconly_create("sieve_validator", 16384);
+ valdtr = p_new(pool, struct sieve_validator, 1);
+ valdtr->pool = pool;
+
+ valdtr->ehandler = ehandler;
+ sieve_error_handler_ref(ehandler);
+
+ valdtr->ast = ast;
+ sieve_ast_ref(ast);
+
+ valdtr->script = sieve_ast_script(ast);
+ valdtr->svinst = sieve_script_svinst(valdtr->script);
+ valdtr->flags = flags;
+
+ /* Setup default arguments */
+ valdtr->default_arguments[SAT_NUMBER].arg_def = &number_argument;
+ valdtr->default_arguments[SAT_NUMBER].ext = NULL;
+ valdtr->default_arguments[SAT_VAR_STRING].arg_def = &string_argument;
+ valdtr->default_arguments[SAT_VAR_STRING].ext = NULL;
+ valdtr->default_arguments[SAT_CONST_STRING].arg_def = &string_argument;
+ valdtr->default_arguments[SAT_CONST_STRING].ext = NULL;
+ valdtr->default_arguments[SAT_STRING_LIST].arg_def = &string_list_argument;
+ valdtr->default_arguments[SAT_STRING_LIST].ext = NULL;
+
+ /* Setup storage for extension contexts */
+ p_array_init(&valdtr->extensions, pool,
+ sieve_extensions_get_count(valdtr->svinst));
+
+ /* Setup command registry */
+ hash_table_create(&valdtr->commands, pool, 0, strcase_hash, strcasecmp);
+ sieve_validator_register_core_commands(valdtr);
+ sieve_validator_register_core_tests(valdtr);
+
+ /* Pre-load core language features implemented as 'extensions' */
+ ext_preloaded =
+ sieve_extensions_get_preloaded(valdtr->svinst, &ext_count);
+ for (i = 0; i < ext_count; i++) {
+ const struct sieve_extension_def *ext_def =
+ ext_preloaded[i]->def;
+
+ if (ext_def != NULL && ext_def->validator_load != NULL)
+ (void)ext_def->validator_load(ext_preloaded[i], valdtr);
+ }
+
+ return valdtr;
+}
+
+void sieve_validator_free(struct sieve_validator **valdtr)
+{
+ const struct sieve_validator_extension_reg *extrs;
+ unsigned int ext_count, i;
+
+ hash_table_destroy(&(*valdtr)->commands);
+ sieve_ast_unref(&(*valdtr)->ast);
+
+ sieve_error_handler_unref(&(*valdtr)->ehandler);
+
+ /* Signal registered extensions that the validator is being destroyed */
+ extrs = array_get(&(*valdtr)->extensions, &ext_count);
+ for (i = 0; i < ext_count; i++) {
+ if (extrs[i].valext != NULL && extrs[i].valext->free != NULL)
+ extrs[i].valext->free(extrs[i].ext, *valdtr,
+ extrs[i].context);
+ }
+
+ pool_unref(&(*valdtr)->pool);
+
+ *valdtr = NULL;
+}
+
+/*
+ * Accessors
+ */
+
+// FIXME: build validate environment
+
+pool_t sieve_validator_pool(struct sieve_validator *valdtr)
+{
+ return valdtr->pool;
+}
+
+struct sieve_error_handler *
+sieve_validator_error_handler(struct sieve_validator *valdtr)
+{
+ return valdtr->ehandler;
+}
+
+struct sieve_ast *sieve_validator_ast(struct sieve_validator *valdtr)
+{
+ return valdtr->ast;
+}
+
+struct sieve_script *sieve_validator_script(struct sieve_validator *valdtr)
+{
+ return valdtr->script;
+}
+
+struct sieve_instance *sieve_validator_svinst(struct sieve_validator *valdtr)
+{
+ return valdtr->svinst;
+}
+
+enum sieve_compile_flags
+sieve_validator_compile_flags(struct sieve_validator *valdtr)
+{
+ return valdtr->flags;
+}
+
+/*
+ * Command registry
+ */
+
+/* Dummy command object to mark unknown commands in the registry */
+
+static bool _cmd_unknown_validate(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ i_unreached();
+ return FALSE;
+}
+
+static const struct sieve_command_def unknown_command = {
+ .identifier = "",
+ .type = SCT_NONE,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = _cmd_unknown_validate
+};
+
+/* Registration of the core commands of the language */
+
+static void
+sieve_validator_register_core_tests(struct sieve_validator *valdtr)
+{
+ unsigned int i;
+
+ for (i = 0; i < sieve_core_tests_count; i++) {
+ sieve_validator_register_command(valdtr, NULL,
+ sieve_core_tests[i]);
+ }
+}
+
+static void
+sieve_validator_register_core_commands(struct sieve_validator *valdtr)
+{
+ unsigned int i;
+
+ for (i = 0; i < sieve_core_commands_count; i++) {
+ sieve_validator_register_command(valdtr, NULL,
+ sieve_core_commands[i]);
+ }
+}
+
+/* Registry functions */
+
+static struct sieve_command_registration *
+sieve_validator_find_command_registration(struct sieve_validator *valdtr,
+ const char *command)
+{
+ return hash_table_lookup(valdtr->commands, command);
+}
+
+static struct sieve_command_registration *
+_sieve_validator_register_command(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ const struct sieve_command_def *cmd_def,
+ const char *identifier)
+{
+ struct sieve_command_registration *cmd_reg =
+ p_new(valdtr->pool, struct sieve_command_registration, 1);
+
+ cmd_reg->cmd_def = cmd_def;
+ cmd_reg->ext = ext;
+
+ hash_table_insert(valdtr->commands, identifier, cmd_reg);
+
+ return cmd_reg;
+}
+
+void sieve_validator_register_command(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ const struct sieve_command_def *cmd_def)
+{
+ struct sieve_command_registration *cmd_reg =
+ sieve_validator_find_command_registration(
+ valdtr, cmd_def->identifier);
+
+ if (cmd_reg == NULL) {
+ cmd_reg = _sieve_validator_register_command(
+ valdtr, ext, cmd_def, cmd_def->identifier);
+ } else {
+ cmd_reg->cmd_def = cmd_def;
+ cmd_reg->ext = ext;
+ }
+
+ if (cmd_def->registered != NULL)
+ cmd_def->registered(valdtr, ext, cmd_reg);
+}
+
+static void
+sieve_validator_register_unknown_command(struct sieve_validator *valdtr,
+ const char *command)
+{
+ struct sieve_command_registration *cmd_reg =
+ sieve_validator_find_command_registration(valdtr, command);
+
+ if (cmd_reg == NULL) {
+ (void)_sieve_validator_register_command(
+ valdtr, NULL, &unknown_command, command);
+ } else {
+ i_assert(cmd_reg->cmd_def == NULL);
+ cmd_reg->cmd_def = &unknown_command;
+ }
+}
+
+/*const struct sieve_command *sieve_validator_find_command
+(struct sieve_validator *valdtr, const char *command)
+{
+ struct sieve_command_registration *cmd_reg =
+ sieve_validator_find_command_registration(valdtr, command);
+
+ return ( record == NULL ? NULL : record->command );
+}*/
+
+/*
+ * Per-command tagged argument registry
+ */
+
+/* Dummy argument object to mark unknown arguments in the registry */
+
+static bool
+_unknown_tag_validate(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_ast_argument **arg ATTR_UNUSED,
+ struct sieve_command *tst ATTR_UNUSED)
+{
+ i_unreached();
+ return FALSE;
+}
+
+static const struct sieve_argument_def _unknown_tag = {
+ .identifier = "",
+ .validate = _unknown_tag_validate,
+};
+
+static inline bool
+_tag_registration_is_unknown(struct sieve_tag_registration *tag_reg)
+{
+ return (tag_reg != NULL && tag_reg->tag_def == &_unknown_tag);
+}
+
+/* Registry functions */
+
+static void
+_sieve_validator_register_tag(struct sieve_validator *valdtr,
+ struct sieve_command_registration *cmd_reg,
+ const struct sieve_extension *ext,
+ const struct sieve_argument_def *tag_def,
+ const char *identifier, int id_code)
+{
+ struct sieve_tag_registration *reg;
+
+ reg = p_new(valdtr->pool, struct sieve_tag_registration, 1);
+ reg->ext = ext;
+ reg->tag_def = tag_def;
+ reg->id_code = id_code;
+ if (identifier == NULL)
+ reg->identifier = tag_def->identifier;
+ else
+ reg->identifier = p_strdup(valdtr->pool, identifier);
+
+ if (!array_is_created(&cmd_reg->normal_tags))
+ p_array_init(&cmd_reg->normal_tags, valdtr->pool, 4);
+
+ array_append(&cmd_reg->normal_tags, &reg, 1);
+}
+
+void sieve_validator_register_persistent_tag(
+ struct sieve_validator *valdtr, const char *command,
+ const struct sieve_extension *ext,
+ const struct sieve_argument_def *tag_def)
+{
+ /* Add the tag to the persistent tags list if necessary */
+ if (tag_def->validate_persistent != NULL) {
+ struct sieve_command_registration *cmd_reg =
+ sieve_validator_find_command_registration(
+ valdtr, command);
+
+ if (cmd_reg == NULL) {
+ cmd_reg = _sieve_validator_register_command(
+ valdtr, NULL, NULL, command);
+ }
+
+ struct sieve_tag_registration *reg;
+
+ if (!array_is_created(&cmd_reg->persistent_tags)) {
+ p_array_init(&cmd_reg->persistent_tags,
+ valdtr->pool, 4);
+ } else {
+ struct sieve_tag_registration *reg_idx;
+
+ /* Avoid dupplicate registration */
+ array_foreach_elem(&cmd_reg->persistent_tags, reg_idx) {
+ if (reg_idx->tag_def == tag_def)
+ return;
+ }
+ }
+
+ reg = p_new(valdtr->pool, struct sieve_tag_registration, 1);
+ reg->ext = ext;
+ reg->tag_def = tag_def;
+ reg->id_code = -1;
+
+ array_append(&cmd_reg->persistent_tags, &reg, 1);
+ }
+}
+
+void sieve_validator_register_external_tag(
+ struct sieve_validator *valdtr, const char *command,
+ const struct sieve_extension *ext,
+ const struct sieve_argument_def *tag_def, int id_code)
+{
+ struct sieve_command_registration *cmd_reg =
+ sieve_validator_find_command_registration(valdtr, command);
+
+ if (cmd_reg == NULL) {
+ cmd_reg = _sieve_validator_register_command(
+ valdtr, NULL, NULL, command);
+ }
+
+ _sieve_validator_register_tag(valdtr, cmd_reg, ext, tag_def,
+ NULL, id_code);
+}
+
+void sieve_validator_register_tag(
+ struct sieve_validator *valdtr,
+ struct sieve_command_registration *cmd_reg,
+ const struct sieve_extension *ext,
+ const struct sieve_argument_def *tag_def, int id_code)
+{
+ if (tag_def->is_instance_of == NULL) {
+ _sieve_validator_register_tag(valdtr, cmd_reg, ext, tag_def,
+ NULL, id_code);
+ } else {
+ struct sieve_tag_registration *reg =
+ p_new(valdtr->pool, struct sieve_tag_registration, 1);
+ reg->ext = ext;
+ reg->tag_def = tag_def;
+ reg->id_code = id_code;
+
+ if (!array_is_created(&cmd_reg->instanced_tags))
+ p_array_init(&cmd_reg->instanced_tags, valdtr->pool, 4);
+
+ array_append(&cmd_reg->instanced_tags, &reg, 1);
+ }
+}
+
+static void
+sieve_validator_register_unknown_tag(struct sieve_validator *valdtr,
+ struct sieve_command_registration *cmd_reg,
+ const char *tag)
+{
+ _sieve_validator_register_tag(valdtr, cmd_reg, NULL,
+ &_unknown_tag, tag, 0);
+}
+
+static struct sieve_tag_registration *
+_sieve_validator_command_tag_get(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ const char *tag, void **data)
+{
+ struct sieve_command_registration *cmd_reg = cmd->reg;
+ struct sieve_tag_registration * const *regs;
+ unsigned int i, reg_count;
+
+ /* First check normal tags */
+ if (array_is_created(&cmd_reg->normal_tags)) {
+ regs = array_get(&cmd_reg->normal_tags, &reg_count);
+
+ for (i = 0; i < reg_count; i++) {
+ if (regs[i]->tag_def != NULL &&
+ strcasecmp(regs[i]->identifier, tag) == 0) {
+
+ return regs[i];
+ }
+ }
+ }
+
+ /* Not found so far, try the instanced tags */
+ if (array_is_created(&cmd_reg->instanced_tags)) {
+ regs = array_get(&cmd_reg->instanced_tags, &reg_count);
+
+ for (i = 0; i < reg_count; i++) {
+ if (regs[i]->tag_def != NULL) {
+ if (regs[i]->tag_def->is_instance_of(
+ valdtr, cmd, regs[i]->ext, tag, data))
+ return regs[i];
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static bool
+sieve_validator_command_tag_exists(struct sieve_validator *valdtr,
+ struct sieve_command *cmd, const char *tag)
+{
+ return (_sieve_validator_command_tag_get(valdtr, cmd,
+ tag, NULL) != NULL);
+}
+
+static struct sieve_tag_registration *
+sieve_validator_command_tag_get(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument *arg, void **data)
+{
+ const char *tag = sieve_ast_argument_tag(arg);
+
+ return _sieve_validator_command_tag_get(valdtr, cmd, tag, data);
+}
+
+/*
+ * Extension support
+ */
+
+static bool
+sieve_validator_extensions_check_conficts(struct sieve_validator *valdtr,
+ struct sieve_ast_argument *ext_arg,
+ const struct sieve_extension *ext)
+{
+ struct sieve_validator_extension_reg *ext_reg;
+ struct sieve_validator_extension_reg *regs;
+ unsigned int count, i;
+
+ if (ext->id < 0)
+ return TRUE;
+
+ ext_reg = array_idx_get_space(&valdtr->extensions,
+ (unsigned int) ext->id);
+
+ regs = array_get_modifiable(&valdtr->extensions, &count);
+ for (i = 0; i < count; i++) {
+ bool required = ext_reg->required && regs[i].required;
+
+ if (regs[i].ext == NULL)
+ continue;
+ if (regs[i].ext == ext)
+ continue;
+ if (!regs[i].loaded)
+ continue;
+
+ /* Check this extension vs other extension */
+ if (ext_reg->valext != NULL &&
+ ext_reg->valext->check_conflict != NULL) {
+ struct sieve_ast_argument *this_ext_arg =
+ (ext_arg == NULL ? regs[i].arg : ext_arg);
+
+ if (!ext_reg->valext->check_conflict(
+ ext, valdtr, ext_reg->context, this_ext_arg,
+ regs[i].ext, required))
+ return FALSE;
+ }
+
+ /* Check other extension vs this extension */
+ if (regs[i].valext != NULL &&
+ regs[i].valext->check_conflict != NULL) {
+ if (!regs[i].valext->check_conflict(
+ regs[i].ext, valdtr, regs[i].context,
+ regs[i].arg, ext, required))
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+bool sieve_validator_extension_load(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument *ext_arg,
+ const struct sieve_extension *ext,
+ bool required)
+{
+ const struct sieve_extension_def *extdef = ext->def;
+ struct sieve_validator_extension_reg *reg = NULL;
+
+ if (ext->global &&
+ (valdtr->flags & SIEVE_COMPILE_FLAG_NOGLOBAL) != 0) {
+ const char *cmd_prefix = (cmd == NULL ? "" :
+ t_strdup_printf("%s %s: ",
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd)));
+ sieve_argument_validate_error(
+ valdtr, ext_arg,
+ "%sfailed to load Sieve capability `%s': "
+ "its use is restricted to global scripts",
+ cmd_prefix, sieve_extension_name(ext));
+ return FALSE;
+ }
+
+ /* Register extension no matter what and store the
+ * AST argument registering it */
+ if (ext->id >= 0) {
+ reg = array_idx_get_space(&valdtr->extensions,
+ (unsigned int)ext->id);
+ i_assert(reg->ext == NULL || reg->ext == ext);
+ reg->ext = ext;
+ reg->required = reg->required || required;
+ if (reg->arg == NULL)
+ reg->arg = ext_arg;
+ }
+
+ if (extdef->validator_load != NULL &&
+ !extdef->validator_load(ext, valdtr)) {
+ const char *cmd_prefix = (cmd == NULL ? "" :
+ t_strdup_printf("%s %s: ",
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd)));
+ sieve_argument_validate_error(
+ valdtr, ext_arg,
+ "%sfailed to load Sieve capability `%s'",
+ cmd_prefix, sieve_extension_name(ext));
+ return FALSE;
+ }
+
+ /* Check conflicts with other extensions */
+ if (!sieve_validator_extensions_check_conficts(valdtr, ext_arg, ext))
+ return FALSE;
+
+ /* Link extension to AST for use at code generation */
+ if (reg != NULL) {
+ sieve_ast_extension_link(valdtr->ast, ext, reg->required);
+ reg->loaded = TRUE;
+ }
+
+ return TRUE;
+}
+
+const struct sieve_extension *
+sieve_validator_extension_load_by_name(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument *ext_arg,
+ const char *ext_name)
+{
+ const struct sieve_extension *ext;
+
+ ext = sieve_extension_get_by_name(valdtr->svinst, ext_name);
+
+ if (ext == NULL || ext->def == NULL || !ext->enabled) {
+ unsigned int i;
+ bool core_test = FALSE;
+ bool core_command = FALSE;
+
+ for (i = 0; !core_command && i < sieve_core_commands_count;
+ i++) {
+ if (strcasecmp(sieve_core_commands[i]->identifier,
+ ext_name) == 0)
+ core_command = TRUE;
+ }
+
+ for (i = 0; !core_test && i < sieve_core_tests_count; i++) {
+ if (strcasecmp(sieve_core_tests[i]->identifier,
+ ext_name) == 0)
+ core_test = TRUE;
+ }
+
+ if (core_test || core_command) {
+ sieve_argument_validate_error(
+ valdtr, ext_arg,
+ "%s %s: `%s' is not known as a Sieve capability, "
+ "but it is known as a Sieve %s that is always available",
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd),
+ str_sanitize(ext_name, 128),
+ (core_test ? "test" : "command"));
+ } else {
+ sieve_argument_validate_error(
+ valdtr, ext_arg,
+ "%s %s: unknown Sieve capability `%s'",
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd),
+ str_sanitize(ext_name, 128));
+ }
+ return NULL;
+ }
+
+ if (!sieve_validator_extension_load(valdtr, cmd, ext_arg, ext, TRUE))
+ return NULL;
+
+ return ext;
+}
+
+const struct sieve_extension *
+sieve_validator_extension_load_implicit(struct sieve_validator *valdtr,
+ const char *ext_name)
+{
+ const struct sieve_extension *ext;
+
+ ext = sieve_extension_get_by_name(valdtr->svinst, ext_name);
+
+ if (ext == NULL || ext->def == NULL)
+ return NULL;
+
+ if (!sieve_validator_extension_load(valdtr, NULL, NULL, ext, TRUE))
+ return NULL;
+
+ return ext;
+}
+
+void sieve_validator_extension_register(
+ struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ const struct sieve_validator_extension *valext, void *context)
+{
+ struct sieve_validator_extension_reg *reg;
+
+ if (ext->id < 0)
+ return;
+
+ reg = array_idx_get_space(&valdtr->extensions, (unsigned int) ext->id);
+ i_assert(reg->ext == NULL || reg->ext == ext);
+ reg->ext = ext;
+ reg->valext = valext;
+ reg->context = context;
+}
+
+bool sieve_validator_extension_loaded(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext)
+{
+ const struct sieve_validator_extension_reg *reg;
+
+ if (ext->id < 0 || ext->id >= (int) array_count(&valdtr->extensions))
+ return FALSE;
+
+ reg = array_idx(&valdtr->extensions, (unsigned int) ext->id);
+
+ return (reg->loaded);
+}
+
+void sieve_validator_extension_set_context(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ void *context)
+{
+ struct sieve_validator_extension_reg *reg;
+
+ if (ext->id < 0)
+ return;
+
+ reg = array_idx_get_space(&valdtr->extensions, (unsigned int) ext->id);
+ reg->context = context;
+}
+
+void *sieve_validator_extension_get_context(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext)
+{
+ const struct sieve_validator_extension_reg *reg;
+
+ if (ext->id < 0 || ext->id >= (int) array_count(&valdtr->extensions))
+ return NULL;
+
+ reg = array_idx(&valdtr->extensions, (unsigned int) ext->id);
+
+ return reg->context;
+}
+
+/*
+ * Overriding the default literal arguments
+ */
+
+void sieve_validator_argument_override(struct sieve_validator *valdtr,
+ enum sieve_argument_type type,
+ const struct sieve_extension *ext,
+ const struct sieve_argument_def *arg_def)
+{
+ struct sieve_default_argument *arg;
+
+ if (valdtr->default_arguments[type].arg_def != NULL) {
+ arg = p_new(valdtr->pool, struct sieve_default_argument, 1);
+ *arg = valdtr->default_arguments[type];
+
+ valdtr->default_arguments[type].overrides = arg;
+ }
+
+ valdtr->default_arguments[type].arg_def = arg_def;
+ valdtr->default_arguments[type].ext = ext;
+}
+
+static bool
+sieve_validator_argument_default_activate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ struct sieve_default_argument *defarg,
+ struct sieve_ast_argument *arg)
+{
+ bool result = TRUE;
+ struct sieve_default_argument *prev_defarg;
+
+ prev_defarg = valdtr->current_defarg;
+ valdtr->current_defarg = defarg;
+
+ if (arg->argument == NULL) {
+ arg->argument = sieve_argument_create(arg->ast, defarg->arg_def,
+ defarg->ext, 0);
+ } else {
+ arg->argument->def = defarg->arg_def;
+ arg->argument->ext = defarg->ext;
+ }
+
+ if (defarg->arg_def != NULL && defarg->arg_def->validate != NULL)
+ result = defarg->arg_def->validate(valdtr, &arg, cmd);
+
+ valdtr->current_defarg = prev_defarg;
+
+ return result;
+}
+
+bool sieve_validator_argument_activate_super(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument *arg,
+ bool constant ATTR_UNUSED)
+{
+ struct sieve_default_argument *defarg;
+
+ if (valdtr->current_defarg == NULL ||
+ valdtr->current_defarg->overrides == NULL)
+ return FALSE;
+
+ if (valdtr->current_defarg->overrides->arg_def == &string_argument) {
+ switch (valdtr->current_defarg_type) {
+ case SAT_CONST_STRING:
+ if (!valdtr->current_defarg_constant) {
+ valdtr->current_defarg_type = SAT_VAR_STRING;
+ defarg = &valdtr->default_arguments[SAT_VAR_STRING];
+ } else {
+ defarg = valdtr->current_defarg->overrides;
+ }
+ break;
+ case SAT_VAR_STRING:
+ defarg = valdtr->current_defarg->overrides;
+ break;
+ default:
+ return FALSE;
+ }
+ } else {
+ defarg = valdtr->current_defarg->overrides;
+ }
+
+ return sieve_validator_argument_default_activate(valdtr, cmd,
+ defarg, arg);
+}
+
+/*
+ * Argument Validation API
+ */
+
+bool sieve_validator_argument_activate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument *arg,
+ bool constant)
+{
+ struct sieve_default_argument *defarg;
+
+ switch (sieve_ast_argument_type(arg)) {
+ case SAAT_NUMBER:
+ valdtr->current_defarg_type = SAT_NUMBER;
+ break;
+ case SAAT_STRING:
+ valdtr->current_defarg_type = SAT_CONST_STRING;
+ break;
+ case SAAT_STRING_LIST:
+ valdtr->current_defarg_type = SAT_STRING_LIST;
+ break;
+ default:
+ return FALSE;
+ }
+
+ valdtr->current_defarg_constant = constant;
+ defarg = &valdtr->default_arguments[valdtr->current_defarg_type];
+
+ if (!constant && defarg->arg_def == &string_argument) {
+ valdtr->current_defarg_type = SAT_VAR_STRING;
+ defarg = &valdtr->default_arguments[SAT_VAR_STRING];
+ }
+
+ return sieve_validator_argument_default_activate(valdtr, cmd,
+ defarg, arg);
+}
+
+bool sieve_validate_positional_argument(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument *arg,
+ const char *arg_name,
+ unsigned int arg_pos,
+ enum sieve_ast_argument_type req_type)
+{
+ i_assert(arg != NULL);
+
+ if (sieve_ast_argument_type(arg) != req_type &&
+ (sieve_ast_argument_type(arg) != SAAT_STRING ||
+ req_type != SAAT_STRING_LIST))
+ {
+ sieve_argument_validate_error(
+ valdtr, arg,
+ "the %s %s expects %s as argument %d (%s), "
+ "but %s was found",
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd),
+ sieve_ast_argument_type_name(req_type),
+ arg_pos, arg_name, sieve_ast_argument_name(arg));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+bool sieve_validate_tag_parameter(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument *tag,
+ struct sieve_ast_argument *param,
+ const char *arg_name, unsigned int arg_pos,
+ enum sieve_ast_argument_type req_type,
+ bool constant)
+{
+ i_assert(tag != NULL);
+
+ if (param == NULL) {
+ const char *position = (arg_pos == 0 ? "" :
+ t_strdup_printf(" %d (%s)", arg_pos, arg_name));
+
+ sieve_argument_validate_error(
+ valdtr, tag,
+ "the :%s tag for the %s %s requires %s as parameter%s, "
+ "but no parameters were found",
+ sieve_ast_argument_tag(tag),
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd),
+ sieve_ast_argument_type_name(req_type), position);
+ return FALSE;
+ }
+
+ if (sieve_ast_argument_type(param) != req_type &&
+ (sieve_ast_argument_type(param) != SAAT_STRING ||
+ req_type != SAAT_STRING_LIST))
+ {
+ const char *position = (arg_pos == 0 ? "" :
+ t_strdup_printf(" %d (%s)", arg_pos, arg_name));
+
+ sieve_argument_validate_error(
+ valdtr, param,
+ "the :%s tag for the %s %s requires %s as parameter%s, "
+ "but %s was found",
+ sieve_ast_argument_tag(tag),
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd),
+ sieve_ast_argument_type_name(req_type), position,
+ sieve_ast_argument_name(param));
+ return FALSE;
+ }
+
+ if (!sieve_validator_argument_activate(valdtr, cmd, param, constant))
+ return FALSE;
+
+ param->argument->id_code = tag->argument->id_code;
+
+ return TRUE;
+}
+
+/*
+ * Command argument validation
+ */
+
+static bool
+sieve_validate_command_arguments(struct sieve_validator *valdtr,
+ struct sieve_command *cmd)
+{
+ int arg_count = cmd->def->positional_args;
+ int real_count = 0;
+ struct sieve_ast_argument *arg;
+ struct sieve_command_registration *cmd_reg = cmd->reg;
+
+ /* Resolve tagged arguments */
+ arg = sieve_ast_argument_first(cmd->ast_node);
+ while (arg != NULL) {
+ void *arg_data = NULL;
+ struct sieve_tag_registration *tag_reg;
+ const struct sieve_argument_def *tag_def;
+
+ if (sieve_ast_argument_type(arg) != SAAT_TAG) {
+ arg = sieve_ast_argument_next(arg);
+ continue;
+ }
+
+ tag_reg = sieve_validator_command_tag_get(valdtr, cmd,
+ arg, &arg_data);
+
+ if (tag_reg == NULL) {
+ sieve_argument_validate_error(
+ valdtr, arg,
+ "unknown tagged argument ':%s' for the %s %s "
+ "(reported only once at first occurrence)",
+ sieve_ast_argument_tag(arg),
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd));
+ sieve_validator_register_unknown_tag(
+ valdtr, cmd_reg, sieve_ast_argument_tag(arg));
+ return FALSE;
+ }
+
+ /* Check whether previously tagged as unknown */
+ if (_tag_registration_is_unknown(tag_reg))
+ return FALSE;
+
+ tag_def = tag_reg->tag_def;
+
+ /* Assign the tagged argument type to the ast for later
+ reference */
+ arg->argument = sieve_argument_create(
+ arg->ast, tag_def, tag_reg->ext, tag_reg->id_code);
+ arg->argument->data = arg_data;
+
+ arg = sieve_ast_argument_next(arg);
+ }
+
+ /* Validate tagged arguments */
+ arg = sieve_ast_argument_first(cmd->ast_node);
+ while (arg != NULL && sieve_ast_argument_type(arg) == SAAT_TAG) {
+ const struct sieve_argument_def *tag_def = arg->argument->def;
+ struct sieve_ast_argument *parg;
+
+ /* Scan backwards for any duplicates */
+ if ((tag_def->flags & SIEVE_ARGUMENT_FLAG_MULTIPLE) == 0) {
+ parg = sieve_ast_argument_prev(arg);
+ while (parg != NULL) {
+ if ((sieve_ast_argument_type(parg) == SAAT_TAG &&
+ parg->argument->def == tag_def) ||
+ (arg->argument->id_code > 0 &&
+ parg->argument != NULL &&
+ parg->argument->id_code == arg->argument->id_code))
+ {
+ const char *tag_id = sieve_ast_argument_tag(arg);
+ const char *tag_desc =
+ strcmp(tag_def->identifier, tag_id) != 0 ?
+ t_strdup_printf("%s argument (:%s)",
+ tag_def->identifier, tag_id) :
+ t_strdup_printf(":%s argument",
+ tag_def->identifier);
+
+ sieve_argument_validate_error(
+ valdtr, arg,
+ "encountered duplicate %s for the %s %s",
+ tag_desc, sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd));
+
+ return FALSE;
+ }
+
+ parg = sieve_ast_argument_prev(parg);
+ }
+ }
+
+ /* Call the validation function for the tag (if present)
+ Fail if the validation fails:
+ Let's not whine multiple times about a single command
+ having multiple bad arguments...
+ */
+ if (tag_def->validate != NULL) {
+ if (!tag_def->validate(valdtr, &arg, cmd))
+ return FALSE;
+ } else {
+ arg = sieve_ast_argument_next(arg);
+ }
+ }
+
+ /* Remaining arguments should be positional (tags are not allowed
+ here) */
+ cmd->first_positional = arg;
+
+ while (arg != NULL) {
+ if (sieve_ast_argument_type(arg) == SAAT_TAG) {
+ sieve_argument_validate_error(
+ valdtr, arg,
+ "encountered an unexpected tagged argument ':%s' "
+ "while validating positional arguments for the %s %s",
+ sieve_ast_argument_tag(arg),
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd));
+ return FALSE;
+ }
+
+ real_count++;
+
+ arg = sieve_ast_argument_next(arg);
+ }
+
+ /* Check the required count versus the real number of arguments */
+ if (arg_count >= 0 && real_count != arg_count) {
+ sieve_command_validate_error(
+ valdtr, cmd,
+ "the %s %s requires %d positional argument(s), "
+ "but %d is/are specified",
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd),
+ arg_count, real_count);
+ return FALSE;
+ }
+
+ /* Call initial validation for persistent arguments */
+ if (array_is_created(&cmd_reg->persistent_tags)) {
+ struct sieve_tag_registration * const *regs;
+ unsigned int i, reg_count;
+
+ regs = array_get(&cmd_reg->persistent_tags, &reg_count);
+ for (i = 0; i < reg_count; i++) {
+ const struct sieve_argument_def *tag_def =
+ regs[i]->tag_def;
+
+ if (tag_def != NULL &&
+ tag_def->validate_persistent != NULL) {
+ /* To be sure */
+ if (!tag_def->validate_persistent(
+ valdtr, cmd, regs[i]->ext))
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static bool
+sieve_validate_arguments_context(struct sieve_validator *valdtr,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg =
+ sieve_command_first_argument(cmd);
+
+ while (arg != NULL) {
+ const struct sieve_argument *argument = arg->argument;
+
+ if (argument != NULL && argument->def != NULL &&
+ argument->def->validate_context != NULL) {
+
+ if (!argument->def->validate_context(valdtr, arg, cmd))
+ return FALSE;
+ }
+
+ arg = sieve_ast_argument_next(arg);
+ }
+
+ return TRUE;
+}
+
+/*
+ * Command Validation API
+ */
+
+static bool
+sieve_validate_command_subtests(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ const unsigned int count)
+{
+ switch (count) {
+ case 0:
+ if (sieve_ast_test_count(cmd->ast_node) > 0) {
+ /* Unexpected command specified */
+ enum sieve_command_type ctype = SCT_NONE;
+ struct sieve_command_registration *cmd_reg;
+ struct sieve_ast_node *test =
+ sieve_ast_test_first(cmd->ast_node);
+
+ cmd_reg = sieve_validator_find_command_registration(
+ valdtr, test->identifier);
+
+ /* First check what we are dealing with */
+ if (cmd_reg != NULL && cmd_reg->cmd_def != NULL)
+ ctype = cmd_reg->cmd_def->type;
+
+ switch (ctype) {
+ case SCT_TEST: /* Spurious test */
+ case SCT_HYBRID:
+ sieve_command_validate_error(
+ valdtr, cmd,
+ "the %s %s accepts no sub-tests, "
+ "but tests are specified",
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd));
+ break;
+ case SCT_NONE: /* Unknown command */
+ /* Is it perhaps a tag for which the ':' was
+ omitted ? */
+ if (sieve_validator_command_tag_exists(
+ valdtr, cmd, test->identifier)) {
+ sieve_command_validate_error(
+ valdtr, cmd,
+ "missing colon ':' before ':%s' tag in %s %s",
+ test->identifier,
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd));
+ break;
+ }
+ /* Fall through */
+ case SCT_COMMAND:
+ sieve_command_validate_error(
+ valdtr, cmd,
+ "missing semicolon ';' after %s %s",
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd));
+ break;
+ }
+ return FALSE;
+ }
+ break;
+ case 1:
+ if (sieve_ast_test_count(cmd->ast_node) == 0) {
+ sieve_command_validate_error(
+ valdtr, cmd,
+ "the %s %s requires one sub-test, "
+ "but none is specified",
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd));
+ return FALSE;
+
+ } else if (sieve_ast_test_count(cmd->ast_node) > 1 ||
+ cmd->ast_node->test_list) {
+ sieve_command_validate_error(
+ valdtr, cmd,
+ "the %s %s requires one sub-test, "
+ "but a list of tests is specified",
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd));
+ return FALSE;
+ }
+ break;
+ default:
+ if (sieve_ast_test_count(cmd->ast_node) == 0) {
+ sieve_command_validate_error(
+ valdtr, cmd,
+ "the %s %s requires a list of sub-tests, "
+ "but none is specified",
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd));
+ return FALSE;
+ } else if (sieve_ast_test_count(cmd->ast_node) == 1 &&
+ !cmd->ast_node->test_list) {
+ sieve_command_validate_error(
+ valdtr, cmd,
+ "the %s %s requires a list of sub-tests, "
+ "but a single test is specified",
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd));
+ return FALSE;
+ }
+ break;
+ }
+
+ return TRUE;
+}
+
+static bool
+sieve_validate_command_block(struct sieve_validator *valdtr,
+ struct sieve_command *cmd, bool block_allowed,
+ bool block_required)
+{
+ i_assert(cmd->ast_node->type == SAT_COMMAND);
+
+ if (block_required) {
+ if (!cmd->ast_node->block) {
+ sieve_command_validate_error(
+ valdtr, cmd,
+ "the %s command requires a command block, "
+ "but it is missing",
+ sieve_command_identifier(cmd));
+ return FALSE;
+ }
+ } else if (!block_allowed && cmd->ast_node->block) {
+ sieve_command_validate_error(
+ valdtr, cmd,
+ "the %s command does not accept a command block, "
+ "but one is specified anyway",
+ sieve_command_identifier(cmd));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * AST Validation
+ */
+
+static bool
+sieve_validate_test_list(struct sieve_validator *valdtr,
+ struct sieve_ast_node *test_list, int *const_r);
+static bool
+sieve_validate_block(struct sieve_validator *valdtr,
+ struct sieve_ast_node *block);
+static bool
+sieve_validate_command(struct sieve_validator *valdtr,
+ struct sieve_ast_node *cmd_node, int *const_r);
+
+static bool
+sieve_validate_command_context(struct sieve_validator *valdtr,
+ struct sieve_ast_node *cmd_node)
+{
+ enum sieve_ast_type ast_type = sieve_ast_node_type(cmd_node);
+ struct sieve_command_registration *cmd_reg;
+
+ i_assert(ast_type == SAT_TEST || ast_type == SAT_COMMAND);
+
+ /* Verify the command specified by this node */
+ cmd_reg = sieve_validator_find_command_registration(
+ valdtr, cmd_node->identifier);
+
+ if (cmd_reg != NULL && cmd_reg->cmd_def != NULL) {
+ const struct sieve_command_def *cmd_def = cmd_reg->cmd_def;
+
+ /* Identifier = "" when the command was previously marked as
+ unknown */
+ if (*(cmd_def->identifier) != '\0') {
+ if ((cmd_def->type == SCT_COMMAND && ast_type == SAT_TEST) ||
+ (cmd_def->type == SCT_TEST && ast_type == SAT_COMMAND)) {
+ sieve_validator_error(
+ valdtr, cmd_node->source_line,
+ "attempted to use %s '%s' as %s",
+ sieve_command_def_type_name(cmd_def),
+ cmd_node->identifier,
+ sieve_ast_type_name(ast_type));
+ return FALSE;
+ }
+
+ cmd_node->command = sieve_command_create(
+ cmd_node, cmd_reg->ext, cmd_def, cmd_reg);
+ } else {
+ return FALSE;
+ }
+ } else {
+ sieve_validator_error(
+ valdtr, cmd_node->source_line,
+ "unknown %s '%s' (only reported once at first occurrence)",
+ sieve_ast_type_name(ast_type), cmd_node->identifier);
+
+ sieve_validator_register_unknown_command(
+ valdtr, cmd_node->identifier);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool
+sieve_validate_command(struct sieve_validator *valdtr,
+ struct sieve_ast_node *cmd_node, int *const_r)
+{
+ enum sieve_ast_type ast_type = sieve_ast_node_type(cmd_node);
+ struct sieve_command *cmd =
+ (cmd_node == NULL ? NULL : cmd_node->command);
+ const struct sieve_command_def *cmd_def =
+ (cmd != NULL ? cmd->def : NULL);
+ bool result = TRUE;
+
+ i_assert(ast_type == SAT_TEST || ast_type == SAT_COMMAND);
+
+ if (cmd_def != NULL && *(cmd_def->identifier) != '\0') {
+ if (cmd_def->pre_validate == NULL ||
+ cmd_def->pre_validate(valdtr, cmd)) {
+ /* Check argument syntax */
+ if (!sieve_validate_command_arguments(valdtr, cmd)) {
+ result = FALSE;
+
+ /* A missing ':' causes a tag to become a test.
+ This can be the cause of the arguments
+ validation failing. Therefore we must produce
+ an error for the sub-tests as well if
+ appropriate. */
+ (void)sieve_validate_command_subtests(
+ valdtr, cmd, cmd_def->subtests);
+ } else if (!sieve_validate_command_subtests(
+ valdtr, cmd, cmd_def->subtests) ||
+ (ast_type == SAT_COMMAND &&
+ !sieve_validate_command_block(
+ valdtr, cmd, cmd_def->block_allowed,
+ cmd_def->block_required))) {
+ result = FALSE;
+ } else {
+ /* Call command validation function if specified
+ */
+ if (cmd_def->validate != NULL) {
+ result = cmd_def->validate(valdtr, cmd) &&
+ result;
+ }
+ }
+ } else {
+ /* If pre-validation fails, don't bother to validate
+ further as context might be missing and doing so is
+ not very useful for further error reporting anyway */
+ return FALSE;
+ }
+
+ result = result && sieve_validate_arguments_context(valdtr, cmd);
+ }
+
+ /*
+ * Descend further into the AST
+ */
+
+ if (cmd_def != NULL) {
+ /* Tests */
+ if (cmd_def->subtests > 0) {
+ if (result ||
+ sieve_errors_more_allowed(valdtr->ehandler)) {
+ result = sieve_validate_test_list(
+ valdtr, cmd_node, const_r) && result;
+ }
+ } else if (result) {
+ if (cmd_def->validate_const != NULL) {
+ (void)cmd_def->validate_const(
+ valdtr, cmd, const_r, -1);
+ } else {
+ *const_r = -1;
+ }
+ }
+
+ /* Skip block if result of test is const FALSE */
+ if (result && *const_r == 0)
+ return TRUE;
+
+ /* Command block */
+ if (cmd_def->block_allowed && ast_type == SAT_COMMAND &&
+ (result || sieve_errors_more_allowed(valdtr->ehandler))) {
+ result = sieve_validate_block(valdtr, cmd_node) &&
+ result;
+ }
+ }
+
+ return result;
+}
+
+static bool
+sieve_validate_test_list(struct sieve_validator *valdtr,
+ struct sieve_ast_node *test_node, int *const_r)
+{
+ struct sieve_command *tst = test_node->command;
+ const struct sieve_command_def *tst_def =
+ (tst != NULL ? tst->def : NULL);
+ struct sieve_ast_node *test;
+ bool result = TRUE;
+
+ if (tst_def != NULL && tst_def->validate_const != NULL) {
+ if (!tst_def->validate_const(valdtr, tst, const_r, -2))
+ return TRUE;
+ }
+
+ test = sieve_ast_test_first(test_node);
+ while (test != NULL &&
+ (result || sieve_errors_more_allowed(valdtr->ehandler))) {
+ int const_value = -2;
+
+ result = sieve_validate_command_context(valdtr, test) &&
+ sieve_validate_command(valdtr, test, &const_value) &&
+ result;
+
+ if (result) {
+ if (tst_def != NULL &&
+ tst_def->validate_const != NULL) {
+ if (!tst_def->validate_const(
+ valdtr, tst, const_r, const_value))
+ return TRUE;
+ } else {
+ *const_r = -1;
+ }
+ }
+
+ if (result && const_value >= 0)
+ test = sieve_ast_node_detach(test);
+ else
+ test = sieve_ast_test_next(test);
+ }
+
+ return result;
+}
+
+static bool
+sieve_validate_block(struct sieve_validator *valdtr,
+ struct sieve_ast_node *block)
+{
+ bool result = TRUE, fatal = FALSE;
+ struct sieve_ast_node *cmd_node, *next;
+
+ T_BEGIN {
+ cmd_node = sieve_ast_command_first(block);
+ while (!fatal && cmd_node != NULL &&
+ (result ||
+ sieve_errors_more_allowed(valdtr->ehandler))) {
+ bool command_success;
+ int const_value = -2;
+
+ next = sieve_ast_command_next(cmd_node);
+
+ /* Check if this is the first non-require command */
+ if (sieve_ast_node_type(block) == SAT_ROOT &&
+ !valdtr->finished_require &&
+ strcasecmp(cmd_node->identifier,
+ cmd_require.identifier) != 0) {
+ const struct sieve_validator_extension_reg *extrs;
+ const struct sieve_extension *const *exts;
+ unsigned int ext_count, i;
+
+ valdtr->finished_require = TRUE;
+
+ /* Load implicit extensions */
+ exts = sieve_extensions_get_all(valdtr->svinst, &ext_count);
+ for (i = 0; i < ext_count; i++) {
+ if (exts[i]->implicit) {
+ (void)sieve_validator_extension_load(
+ valdtr, NULL, NULL, exts[i], TRUE);
+ }
+ }
+
+ /* Validate all 'require'd extensions */
+ extrs = array_get(&valdtr->extensions, &ext_count);
+ for (i = 0; i < ext_count; i++) {
+ if (extrs[i].loaded && extrs[i].valext != NULL &&
+ extrs[i].valext->validate != NULL) {
+ if (!extrs[i].valext->validate(
+ extrs[i].ext, valdtr,
+ extrs[i].context, extrs[i].arg,
+ extrs[i].required)) {
+ fatal = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ command_success =
+ sieve_validate_command_context(valdtr, cmd_node);
+ result = command_success && result;
+
+ result = !fatal &&
+ sieve_validate_command(valdtr, cmd_node,
+ &const_value) && result;
+
+ cmd_node = next;
+ }
+ } T_END;
+
+ return result && !fatal;
+}
+
+bool sieve_validator_run(struct sieve_validator *valdtr)
+{
+ return sieve_validate_block(valdtr, sieve_ast_root(valdtr->ast));
+}
+
+/*
+ * Validator object registry
+ */
+
+struct sieve_validator_object_reg {
+ const struct sieve_object_def *obj_def;
+ const struct sieve_extension *ext;
+};
+
+struct sieve_validator_object_registry {
+ struct sieve_validator *valdtr;
+ ARRAY(struct sieve_validator_object_reg) registrations;
+};
+
+struct sieve_validator_object_registry *
+sieve_validator_object_registry_get(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext)
+{
+ return (struct sieve_validator_object_registry *)
+ sieve_validator_extension_get_context(valdtr, ext);
+}
+
+void sieve_validator_object_registry_add(
+ struct sieve_validator_object_registry *regs,
+ const struct sieve_extension *ext,
+ const struct sieve_object_def *obj_def)
+{
+ struct sieve_validator_object_reg *reg;
+
+ reg = array_append_space(&regs->registrations);
+ reg->ext = ext;
+ reg->obj_def = obj_def;
+}
+
+bool sieve_validator_object_registry_find(
+ struct sieve_validator_object_registry *regs, const char *identifier,
+ struct sieve_object *obj)
+{
+ unsigned int i;
+
+ for (i = 0; i < array_count(&regs->registrations); i++) {
+ const struct sieve_validator_object_reg *reg =
+ array_idx(&regs->registrations, i);
+
+ if (strcasecmp(reg->obj_def->identifier, identifier) == 0) {
+ if (obj != NULL) {
+ obj->def = reg->obj_def;
+ obj->ext = reg->ext;
+ }
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+struct sieve_validator_object_registry *
+sieve_validator_object_registry_create(struct sieve_validator *valdtr)
+{
+ pool_t pool = valdtr->pool;
+ struct sieve_validator_object_registry *regs =
+ p_new(pool, struct sieve_validator_object_registry, 1);
+
+ /* Setup registry */
+ p_array_init(&regs->registrations, valdtr->pool, 4);
+
+ regs->valdtr = valdtr;
+
+ return regs;
+}
+
+struct sieve_validator_object_registry *
+sieve_validator_object_registry_init(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext)
+{
+ struct sieve_validator_object_registry *regs =
+ sieve_validator_object_registry_create(valdtr);
+
+ sieve_validator_extension_set_context(valdtr, ext, regs);
+ return regs;
+}
+
+/*
+ * Error handling
+ */
+
+#undef sieve_validator_error
+void sieve_validator_error(struct sieve_validator *valdtr,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ unsigned int source_line, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_ERROR,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ params.location =
+ sieve_error_script_location(valdtr->script, source_line);
+
+ va_start(args, fmt);
+ sieve_logv(valdtr->ehandler, &params, fmt, args);
+ va_end(args);
+}
+
+#undef sieve_validator_warning
+void sieve_validator_warning(struct sieve_validator *valdtr,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ unsigned int source_line, const char *fmt, ...)
+{
+ struct sieve_error_params params = {
+ .log_type = LOG_TYPE_WARNING,
+ .csrc = {
+ .filename = csrc_filename,
+ .linenum = csrc_linenum,
+ },
+ };
+ va_list args;
+
+ params.location =
+ sieve_error_script_location(valdtr->script, source_line);
+
+ va_start(args, fmt);
+ sieve_logv(valdtr->ehandler, &params, fmt, args);
+ va_end(args);
+
+}
diff --git a/pigeonhole/src/lib-sieve/sieve-validator.h b/pigeonhole/src/lib-sieve/sieve-validator.h
new file mode 100644
index 0000000..21b41cc
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-validator.h
@@ -0,0 +1,197 @@
+#ifndef SIEVE_VALIDATOR_H
+#define SIEVE_VALIDATOR_H
+
+#include "lib.h"
+
+#include "sieve-common.h"
+
+/*
+ * Types
+ */
+
+enum sieve_argument_type {
+ SAT_NUMBER,
+ SAT_CONST_STRING,
+ SAT_VAR_STRING,
+ SAT_STRING_LIST,
+
+ SAT_COUNT
+};
+
+struct sieve_command_registration;
+
+/*
+ * Validator
+ */
+
+struct sieve_validator;
+
+struct sieve_validator *
+sieve_validator_create(struct sieve_ast *ast,
+ struct sieve_error_handler *ehandler,
+ enum sieve_compile_flags flags);
+void sieve_validator_free(struct sieve_validator **valdtr);
+pool_t sieve_validator_pool(struct sieve_validator *valdtr);
+
+bool sieve_validator_run(struct sieve_validator *valdtr);
+
+/*
+ * Accessors
+ */
+
+struct sieve_error_handler *
+sieve_validator_error_handler(struct sieve_validator *valdtr);
+struct sieve_ast *sieve_validator_ast(struct sieve_validator *valdtr);
+struct sieve_script *sieve_validator_script(struct sieve_validator *valdtr);
+struct sieve_instance *sieve_validator_svinst(struct sieve_validator *valdtr);
+enum sieve_compile_flags
+sieve_validator_compile_flags(struct sieve_validator *valdtr);
+
+/*
+ * Command/Test registry
+ */
+
+void sieve_validator_register_command(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ const struct sieve_command_def *command);
+
+/*
+ * Per-command tagged argument registry
+ */
+
+void sieve_validator_register_tag(struct sieve_validator *valdtr,
+ struct sieve_command_registration *cmd_reg,
+ const struct sieve_extension *ext,
+ const struct sieve_argument_def *tag_def,
+ int id_code);
+void sieve_validator_register_external_tag(
+ struct sieve_validator *valdtr, const char *command,
+ const struct sieve_extension *ext,
+ const struct sieve_argument_def *tag_def, int id_code);
+void sieve_validator_register_persistent_tag(
+ struct sieve_validator *valdtr, const char *command,
+ const struct sieve_extension *ext,
+ const struct sieve_argument_def *tag_def);
+
+/*
+ * Overriding the default literal arguments
+ */
+
+void sieve_validator_argument_override(
+ struct sieve_validator *valdtr, enum sieve_argument_type type,
+ const struct sieve_extension *ext,
+ const struct sieve_argument_def *arg_def);
+bool sieve_validator_argument_activate_super(
+ struct sieve_validator *valdtr, struct sieve_command *cmd,
+ struct sieve_ast_argument *arg, bool constant);
+
+/*
+ * Argument validation API
+ */
+
+bool sieve_validate_positional_argument(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument *arg,
+ const char *arg_name,
+ unsigned int arg_pos,
+ enum sieve_ast_argument_type req_type);
+bool sieve_validator_argument_activate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument *arg,
+ bool constant);
+
+bool sieve_validate_tag_parameter(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument *tag,
+ struct sieve_ast_argument *param,
+ const char *arg_name, unsigned int arg_pos,
+ enum sieve_ast_argument_type req_type,
+ bool constant);
+
+/*
+ * Extension support
+ */
+
+struct sieve_validator_extension {
+ const struct sieve_extension_def *ext;
+
+ bool (*check_conflict)(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context,
+ struct sieve_ast_argument *require_arg,
+ const struct sieve_extension *ext_other,
+ bool required);
+ bool (*validate)(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context,
+ struct sieve_ast_argument *require_arg, bool required);
+
+ void (*free)(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context);
+};
+
+bool sieve_validator_extension_load(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument *ext_arg,
+ const struct sieve_extension *ext,
+ bool required) ATTR_NULL(2, 3);
+const struct sieve_extension *
+sieve_validator_extension_load_by_name(struct sieve_validator *valdtr,
+ struct sieve_command *cmd,
+ struct sieve_ast_argument *ext_arg,
+ const char *ext_name);
+const struct sieve_extension *
+sieve_validator_extension_load_implicit(struct sieve_validator *valdtr,
+ const char *ext_name);
+
+void sieve_validator_extension_register(
+ struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ const struct sieve_validator_extension *valext, void *context);
+bool sieve_validator_extension_loaded(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext);
+
+void sieve_validator_extension_set_context(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ void *context);
+void *sieve_validator_extension_get_context(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext);
+
+/*
+ * Validator object registry
+ */
+
+struct sieve_validator_object_registry;
+
+struct sieve_validator_object_registry *
+sieve_validator_object_registry_get(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext);
+void sieve_validator_object_registry_add(
+ struct sieve_validator_object_registry *regs,
+ const struct sieve_extension *ext,
+ const struct sieve_object_def *obj_def);
+bool sieve_validator_object_registry_find(
+ struct sieve_validator_object_registry *regs, const char *identifier,
+ struct sieve_object *obj);
+struct sieve_validator_object_registry *
+sieve_validator_object_registry_create(struct sieve_validator *valdtr);
+struct sieve_validator_object_registry *
+sieve_validator_object_registry_init(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext);
+
+/*
+ * Error handling
+ */
+
+void sieve_validator_error(struct sieve_validator *valdtr,
+ const char *csrc_filename, unsigned int csrc_linenum,
+ unsigned int source_line, const char *fmt, ...)
+ ATTR_FORMAT(5, 6);
+#define sieve_validator_error(valdtr, ...) \
+ sieve_validator_error(valdtr, __FILE__, __LINE__, __VA_ARGS__)
+void sieve_validator_warning(struct sieve_validator *valdtr,
+ const char *csrc_filename,
+ unsigned int csrc_linenum,
+ unsigned int source_line, const char *fmt, ...)
+ ATTR_FORMAT(5, 6);
+#define sieve_validator_warning(valdtr, ...) \
+ sieve_validator_warning(valdtr, __FILE__, __LINE__, __VA_ARGS__)
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/sieve.c b/pigeonhole/src/lib-sieve/sieve.c
new file mode 100644
index 0000000..69827a9
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve.c
@@ -0,0 +1,1303 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "istream.h"
+#include "ostream.h"
+#include "buffer.h"
+#include "time-util.h"
+#include "eacces-error.h"
+#include "home-expand.h"
+#include "hostpid.h"
+#include "message-address.h"
+#include "mail-user.h"
+
+#include "sieve-settings.h"
+#include "sieve-extensions.h"
+#include "sieve-plugins.h"
+
+#include "sieve-address.h"
+#include "sieve-script.h"
+#include "sieve-storage-private.h"
+#include "sieve-ast.h"
+#include "sieve-binary.h"
+#include "sieve-actions.h"
+#include "sieve-result.h"
+
+#include "sieve-parser.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-binary-dumper.h"
+
+#include "sieve.h"
+#include "sieve-common.h"
+#include "sieve-limits.h"
+#include "sieve-error-private.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <dirent.h>
+
+struct event_category event_category_sieve = {
+ .name = "sieve",
+};
+
+/*
+ * Main Sieve library interface
+ */
+
+struct sieve_instance *
+sieve_init(const struct sieve_environment *env,
+ const struct sieve_callbacks *callbacks, void *context, bool debug)
+{
+ struct sieve_instance *svinst;
+ const char *domain;
+ pool_t pool;
+
+ /* Create Sieve engine instance */
+ pool = pool_alloconly_create("sieve", 8192);
+ svinst = p_new(pool, struct sieve_instance, 1);
+ svinst->pool = pool;
+ svinst->callbacks = callbacks;
+ svinst->context = context;
+ svinst->debug = debug;
+ svinst->base_dir = p_strdup_empty(pool, env->base_dir);
+ svinst->username = p_strdup_empty(pool, env->username);
+ svinst->home_dir = p_strdup_empty(pool, env->home_dir);
+ svinst->temp_dir = p_strdup_empty(pool, env->temp_dir);
+ svinst->flags = env->flags;
+ svinst->env_location = env->location;
+ svinst->delivery_phase = env->delivery_phase;
+
+ svinst->event = event_create(env->event_parent);
+ event_add_category(svinst->event, &event_category_sieve);
+ event_set_forced_debug(svinst->event, debug);
+ event_set_append_log_prefix(svinst->event, "sieve: ");
+ event_add_str(svinst->event, "user", env->username);
+
+ /* Determine domain */
+ if (env->domainname != NULL && *(env->domainname) != '\0')
+ domain = env->domainname;
+ else {
+ /* Fall back to parsing username localpart@domain */
+ domain = svinst->username == NULL ? NULL :
+ strchr(svinst->username, '@');
+ if (domain == NULL || *(domain+1) == '\0') {
+ /* Fall back to parsing hostname host.domain */
+ domain = (env->hostname != NULL ?
+ strchr(env->hostname, '.') : NULL);
+ if (domain == NULL || *(domain+1) == '\0' ||
+ strchr(domain+1, '.') == NULL) {
+ /* Fall back to bare hostname */
+ domain = env->hostname;
+ } else {
+ domain++;
+ }
+ } else {
+ domain++;
+ }
+ }
+ svinst->hostname = p_strdup_empty(pool, env->hostname);
+ svinst->domainname = p_strdup(pool, domain);
+
+ sieve_errors_init(svinst);
+
+ e_debug(svinst->event, "%s version %s initializing",
+ PIGEONHOLE_NAME, PIGEONHOLE_VERSION_FULL);
+
+ /* Read configuration */
+
+ sieve_settings_load(svinst);
+
+ /* Initialize extensions */
+ if (!sieve_extensions_init(svinst)) {
+ sieve_deinit(&svinst);
+ return NULL;
+ }
+
+ /* Initialize storage classes */
+ sieve_storages_init(svinst);
+
+ /* Initialize plugins */
+ sieve_plugins_load(svinst, NULL, NULL);
+
+ /* Configure extensions */
+ sieve_extensions_configure(svinst);
+
+ return svinst;
+}
+
+void sieve_deinit(struct sieve_instance **_svinst)
+{
+ struct sieve_instance *svinst = *_svinst;
+
+ sieve_plugins_unload(svinst);
+ sieve_storages_deinit(svinst);
+ sieve_extensions_deinit(svinst);
+ sieve_errors_deinit(svinst);
+
+ event_unref(&svinst->event);
+
+ pool_unref(&(svinst)->pool);
+ *_svinst = NULL;
+}
+
+void sieve_set_extensions(struct sieve_instance *svinst, const char *extensions)
+{
+ sieve_extensions_set_string(svinst, extensions, FALSE, FALSE);
+}
+
+const char *
+sieve_get_capabilities(struct sieve_instance *svinst, const char *name)
+{
+ if (name == NULL || *name == '\0')
+ return sieve_extensions_get_string(svinst);
+
+ return sieve_extension_capabilities_get_string(svinst, name);
+}
+
+struct event *sieve_get_event(struct sieve_instance *svinst)
+{
+ return svinst->event;
+}
+
+/*
+ * Low-level compiler functions
+ */
+
+struct sieve_ast *
+sieve_parse(struct sieve_script *script, struct sieve_error_handler *ehandler,
+ enum sieve_error *error_r)
+{
+ struct sieve_parser *parser;
+ struct sieve_ast *ast = NULL;
+
+ /* Parse */
+ parser = sieve_parser_create(script, ehandler, error_r);
+ if (parser == NULL)
+ return NULL;
+
+ if (!sieve_parser_run(parser, &ast))
+ ast = NULL;
+ else
+ sieve_ast_ref(ast);
+
+ sieve_parser_free(&parser);
+
+ if (error_r != NULL) {
+ if (ast == NULL)
+ *error_r = SIEVE_ERROR_NOT_VALID;
+ else
+ *error_r = SIEVE_ERROR_NONE;
+ }
+ return ast;
+}
+
+bool sieve_validate(struct sieve_ast *ast, struct sieve_error_handler *ehandler,
+ enum sieve_compile_flags flags, enum sieve_error *error_r)
+{
+ bool result = TRUE;
+ struct sieve_validator *validator =
+ sieve_validator_create(ast, ehandler, flags);
+
+ if (!sieve_validator_run(validator))
+ result = FALSE;
+
+ sieve_validator_free(&validator);
+
+ if (error_r != NULL) {
+ if (!result)
+ *error_r = SIEVE_ERROR_NOT_VALID;
+ else
+ *error_r = SIEVE_ERROR_NONE;
+ }
+ return result;
+}
+
+static struct sieve_binary *
+sieve_generate(struct sieve_ast *ast, struct sieve_error_handler *ehandler,
+ enum sieve_compile_flags flags, enum sieve_error *error_r)
+{
+ struct sieve_generator *generator =
+ sieve_generator_create(ast, ehandler, flags);
+ struct sieve_binary *sbin = NULL;
+
+ sbin = sieve_generator_run(generator, NULL);
+
+ sieve_generator_free(&generator);
+
+ if (error_r != NULL) {
+ if (sbin == NULL)
+ *error_r = SIEVE_ERROR_NOT_VALID;
+ else
+ *error_r = SIEVE_ERROR_NONE;
+ }
+ return sbin;
+}
+
+/*
+ * Sieve compilation
+ */
+
+struct sieve_binary *
+sieve_compile_script(struct sieve_script *script,
+ struct sieve_error_handler *ehandler,
+ enum sieve_compile_flags flags,
+ enum sieve_error *error_r)
+{
+ struct sieve_ast *ast;
+ struct sieve_binary *sbin;
+ enum sieve_error error, *errorp;
+
+ if (error_r != NULL)
+ errorp = error_r;
+ else
+ errorp = &error;
+ *errorp = SIEVE_ERROR_NONE;
+
+ /* Parse */
+ ast = sieve_parse(script, ehandler, errorp);
+ if (ast == NULL) {
+ switch (*errorp) {
+ case SIEVE_ERROR_NOT_FOUND:
+ if (error_r == NULL) {
+ sieve_error(ehandler, sieve_script_name(script),
+ "script not found");
+ }
+ break;
+ default:
+ sieve_error(ehandler, sieve_script_name(script),
+ "parse failed");
+ }
+ return NULL;
+ }
+
+ /* Validate */
+ if (!sieve_validate(ast, ehandler, flags, errorp)) {
+ sieve_error(ehandler, sieve_script_name(script),
+ "validation failed");
+
+ sieve_ast_unref(&ast);
+ return NULL;
+ }
+
+ /* Generate */
+ sbin = sieve_generate(ast, ehandler, flags, errorp);
+ if (sbin == NULL) {
+ sieve_error(ehandler, sieve_script_name(script),
+ "code generation failed");
+ sieve_ast_unref(&ast);
+ return NULL;
+ }
+
+ /* Cleanup */
+ sieve_ast_unref(&ast);
+ return sbin;
+}
+
+struct sieve_binary *
+sieve_compile(struct sieve_instance *svinst, const char *script_location,
+ const char *script_name, struct sieve_error_handler *ehandler,
+ enum sieve_compile_flags flags, enum sieve_error *error_r)
+{
+ struct sieve_script *script;
+ struct sieve_binary *sbin;
+ enum sieve_error error;
+
+ script = sieve_script_create_open(svinst, script_location,
+ script_name, &error);
+ if (script == NULL) {
+ if (error_r != NULL)
+ *error_r = error;
+ switch (error) {
+ case SIEVE_ERROR_NOT_FOUND:
+ sieve_error(ehandler, script_name, "script not found");
+ break;
+ default:
+ sieve_internal_error(ehandler, script_name,
+ "failed to open script");
+ }
+ return NULL;
+ }
+
+ sbin = sieve_compile_script(script, ehandler, flags, error_r);
+ if (sbin != NULL) {
+ e_debug(svinst->event,
+ "Script `%s' from %s successfully compiled",
+ sieve_script_name(script),
+ sieve_script_location(script));
+ }
+
+ sieve_script_unref(&script);
+ return sbin;
+}
+
+/*
+ * Sieve runtime
+ */
+
+static int
+sieve_run(struct sieve_binary *sbin, struct sieve_result *result,
+ struct sieve_execute_env *eenv, struct sieve_error_handler *ehandler)
+{
+ struct sieve_interpreter *interp;
+ int ret = 0;
+
+ /* Create the interpreter */
+ interp = sieve_interpreter_create(sbin, NULL, eenv, ehandler);
+ if (interp == NULL)
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ /* Run the interpreter */
+ ret = sieve_interpreter_run(interp, result);
+
+ /* Free the interpreter */
+ sieve_interpreter_free(&interp);
+
+ return ret;
+}
+
+/*
+ * Reading/writing sieve binaries
+ */
+
+struct sieve_binary *
+sieve_load(struct sieve_instance *svinst, const char *bin_path,
+ enum sieve_error *error_r)
+{
+ return sieve_binary_open(svinst, bin_path, NULL, error_r);
+}
+
+static struct sieve_binary *
+sieve_open_script_real(struct sieve_script *script,
+ struct sieve_error_handler *ehandler,
+ enum sieve_compile_flags flags,
+ enum sieve_error *error_r)
+{
+ struct sieve_instance *svinst = sieve_script_svinst(script);
+ struct sieve_resource_usage rusage;
+ struct sieve_binary *sbin;
+ enum sieve_error error;
+ const char *errorstr = NULL;
+ int ret;
+
+ if (error_r == NULL)
+ error_r = &error;
+
+ sieve_resource_usage_init(&rusage);
+
+ /* Try to open the matching binary */
+ sbin = sieve_script_binary_load(script, error_r);
+ if (sbin != NULL) {
+ sieve_binary_get_resource_usage(sbin, &rusage);
+
+ /* Ok, it exists; now let's see if it is up to date */
+ if (!sieve_resource_usage_is_excessive(svinst, &rusage) &&
+ !sieve_binary_up_to_date(sbin, flags)) {
+ /* Not up to date */
+ e_debug(svinst->event,
+ "Script binary %s is not up-to-date",
+ sieve_binary_path(sbin));
+ sieve_binary_close(&sbin);
+ }
+ }
+
+ /* If the binary does not exist or is not up-to-date, we need
+ * to (re-)compile.
+ */
+ if (sbin != NULL) {
+ e_debug(svinst->event,
+ "Script binary %s successfully loaded",
+ sieve_binary_path(sbin));
+ } else {
+ sbin = sieve_compile_script(script, ehandler, flags, error_r);
+ if (sbin == NULL)
+ return NULL;
+
+ e_debug(svinst->event,
+ "Script `%s' from %s successfully compiled",
+ sieve_script_name(script),
+ sieve_script_location(script));
+
+ sieve_binary_set_resource_usage(sbin, &rusage);
+ }
+
+ /* Check whether binary can be executed. */
+ ret = sieve_binary_check_executable(sbin, error_r, &errorstr);
+ if (ret <= 0) {
+ const char *path = sieve_binary_path(sbin);
+
+ if (path != NULL) {
+ e_debug(svinst->event,
+ "Script binary %s cannot be executed",
+ path);
+ } else {
+ e_debug(svinst->event,
+ "Script binary from %s cannot be executed",
+ sieve_binary_source(sbin));
+ }
+ if (ret < 0) {
+ sieve_internal_error(ehandler,
+ sieve_script_name(script),
+ "failed to open script");
+ } else {
+ sieve_error(ehandler, sieve_script_name(script),
+ "%s", errorstr);
+ }
+ sieve_binary_close(&sbin);
+ }
+
+ return sbin;
+}
+
+struct sieve_binary *
+sieve_open_script(struct sieve_script *script,
+ struct sieve_error_handler *ehandler,
+ enum sieve_compile_flags flags, enum sieve_error *error_r)
+{
+ struct sieve_binary *sbin;
+
+ T_BEGIN {
+ sbin = sieve_open_script_real(script, ehandler, flags, error_r);
+ } T_END;
+
+ return sbin;
+}
+
+struct sieve_binary *
+sieve_open(struct sieve_instance *svinst, const char *script_location,
+ const char *script_name, struct sieve_error_handler *ehandler,
+ enum sieve_compile_flags flags, enum sieve_error *error_r)
+{
+ struct sieve_script *script;
+ struct sieve_binary *sbin;
+ enum sieve_error error;
+
+ /* First open the scriptfile itself */
+ script = sieve_script_create_open(svinst, script_location,
+ script_name, &error);
+ if (script == NULL) {
+ /* Failed */
+ if (error_r != NULL)
+ *error_r = error;
+ switch (error) {
+ case SIEVE_ERROR_NOT_FOUND:
+ sieve_error(ehandler, script_name, "script not found");
+ break;
+ default:
+ sieve_internal_error(ehandler, script_name,
+ "failed to open script");
+ }
+ return NULL;
+ }
+
+ sbin = sieve_open_script(script, ehandler, flags, error_r);
+
+ /* Drop script reference, if sbin != NULL it holds a reference of its own.
+ * Otherwise the script object is freed here.
+ */
+ sieve_script_unref(&script);
+
+ return sbin;
+}
+
+const char *sieve_get_source(struct sieve_binary *sbin)
+{
+ return sieve_binary_source(sbin);
+}
+
+bool sieve_is_loaded(struct sieve_binary *sbin)
+{
+ return sieve_binary_loaded(sbin);
+}
+
+int sieve_save_as(struct sieve_binary *sbin, const char *bin_path, bool update,
+ mode_t save_mode, enum sieve_error *error_r)
+{
+ if (bin_path == NULL)
+ return sieve_save(sbin, update, error_r);
+
+ return sieve_binary_save(sbin, bin_path, update, save_mode, error_r);
+}
+
+int sieve_save(struct sieve_binary *sbin, bool update,
+ enum sieve_error *error_r)
+{
+ struct sieve_script *script = sieve_binary_script(sbin);
+
+ if (script == NULL)
+ return sieve_binary_save(sbin, NULL, update, 0600, error_r);
+
+ return sieve_script_binary_save(script, sbin, update, error_r);
+}
+
+bool sieve_record_resource_usage(struct sieve_binary *sbin,
+ const struct sieve_resource_usage *rusage)
+{
+ return sieve_binary_record_resource_usage(sbin, rusage);
+}
+
+int sieve_check_executable(struct sieve_binary *sbin,
+ enum sieve_error *error_r,
+ const char **client_error_r)
+{
+ return sieve_binary_check_executable(sbin, error_r, client_error_r);
+}
+
+void sieve_close(struct sieve_binary **_sbin)
+{
+ sieve_binary_close(_sbin);
+}
+
+/*
+ * Debugging
+ */
+
+void sieve_dump(struct sieve_binary *sbin, struct ostream *stream, bool verbose)
+{
+ struct sieve_binary_dumper *dumpr = sieve_binary_dumper_create(sbin);
+
+ sieve_binary_dumper_run(dumpr, stream, verbose);
+
+ sieve_binary_dumper_free(&dumpr);
+}
+
+void sieve_hexdump(struct sieve_binary *sbin, struct ostream *stream)
+{
+ struct sieve_binary_dumper *dumpr = sieve_binary_dumper_create(sbin);
+
+ sieve_binary_dumper_hexdump(dumpr, stream);
+
+ sieve_binary_dumper_free(&dumpr);
+}
+
+int sieve_test(struct sieve_binary *sbin,
+ const struct sieve_message_data *msgdata,
+ const struct sieve_script_env *senv,
+ struct sieve_error_handler *ehandler, struct ostream *stream,
+ enum sieve_execute_flags flags)
+{
+ struct sieve_instance *svinst = sieve_binary_svinst(sbin);
+ struct sieve_result *result;
+ struct sieve_execute_env eenv;
+ pool_t pool;
+ int ret;
+
+ pool = pool_alloconly_create("sieve execution", 4096);
+ sieve_execute_init(&eenv, svinst, pool, msgdata, senv, flags);
+
+ /* Create result object */
+ result = sieve_result_create(svinst, pool, &eenv);
+
+ /* Run the script */
+ ret = sieve_run(sbin, result, &eenv, ehandler);
+
+ /* Print result if successful */
+ if (ret > 0) {
+ ret = (sieve_result_print(result, senv, stream, NULL) ?
+ SIEVE_EXEC_OK : SIEVE_EXEC_FAILURE);
+ }
+
+ /* Cleanup */
+ if (result != NULL)
+ sieve_result_unref(&result);
+ sieve_execute_deinit(&eenv);
+ pool_unref(&pool);
+
+ return ret;
+}
+
+/*
+ * Script execution
+ */
+
+int sieve_script_env_init(struct sieve_script_env *senv, struct mail_user *user,
+ const char **error_r)
+{
+ const struct message_address *postmaster;
+ const char *error;
+
+ if (!mail_user_get_postmaster_address(user, &postmaster, &error)) {
+ *error_r = t_strdup_printf(
+ "Invalid postmaster_address: %s", error);
+ return -1;
+ }
+
+ i_zero(senv);
+ senv->user = user;
+ senv->postmaster_address = postmaster;
+ return 0;
+}
+
+int sieve_execute(struct sieve_binary *sbin,
+ const struct sieve_message_data *msgdata,
+ const struct sieve_script_env *senv,
+ struct sieve_error_handler *exec_ehandler,
+ struct sieve_error_handler *action_ehandler,
+ enum sieve_execute_flags flags)
+{
+ struct sieve_instance *svinst = sieve_binary_svinst(sbin);
+ struct sieve_result *result = NULL;
+ struct sieve_result_execution *rexec;
+ struct sieve_execute_env eenv;
+ pool_t pool;
+ int ret;
+
+ pool = pool_alloconly_create("sieve execution", 4096);
+ sieve_execute_init(&eenv, svinst, pool, msgdata, senv, flags);
+
+ /* Create result object */
+ result = sieve_result_create(svinst, pool, &eenv);
+
+ /* Run the script */
+ ret = sieve_run(sbin, result, &eenv, exec_ehandler);
+
+ rexec = sieve_result_execution_create(result, pool);
+
+ /* Evaluate status and execute the result:
+ Strange situations, e.g. currupt binaries, must be handled by the
+ caller. In that case no implicit keep is attempted, because the
+ situation may be resolved.
+ */
+ ret = sieve_result_execute(rexec, ret, TRUE, action_ehandler, NULL);
+
+ sieve_result_execution_destroy(&rexec);
+
+ /* Cleanup */
+ if (result != NULL)
+ sieve_result_unref(&result);
+ sieve_execute_finish(&eenv, ret);
+ sieve_execute_deinit(&eenv);
+ pool_unref(&pool);
+
+ return ret;
+}
+
+/*
+ * Multiscript support
+ */
+
+struct sieve_multiscript {
+ pool_t pool;
+ struct sieve_execute_env exec_env;
+ struct sieve_result *result;
+ struct sieve_result_execution *rexec;
+ struct event *event;
+
+ int status;
+ bool keep;
+
+ struct ostream *teststream;
+
+ bool active:1;
+ bool discard_handled:1;
+};
+
+struct sieve_multiscript *
+sieve_multiscript_start_execute(struct sieve_instance *svinst,
+ const struct sieve_message_data *msgdata,
+ const struct sieve_script_env *senv)
+{
+ pool_t pool;
+ struct sieve_result *result;
+ struct sieve_multiscript *mscript;
+
+ pool = pool_alloconly_create("sieve execution", 4096);
+ mscript = p_new(pool, struct sieve_multiscript, 1);
+ mscript->pool = pool;
+ sieve_execute_init(&mscript->exec_env, svinst, pool, msgdata, senv, 0);
+
+ mscript->event = event_create(mscript->exec_env.event);
+ event_set_append_log_prefix(mscript->event, "multi-script: ");
+
+ result = sieve_result_create(svinst, pool, &mscript->exec_env);
+ sieve_result_set_keep_action(result, NULL, NULL);
+ mscript->result = result;
+
+ mscript->rexec = sieve_result_execution_create(result, pool);
+
+ mscript->status = SIEVE_EXEC_OK;
+ mscript->active = TRUE;
+ mscript->keep = TRUE;
+
+ e_debug(mscript->event, "Start execute sequence");
+
+ return mscript;
+}
+
+static void sieve_multiscript_destroy(struct sieve_multiscript **_mscript)
+{
+ struct sieve_multiscript *mscript = *_mscript;
+
+ if (mscript == NULL)
+ return;
+ *_mscript = NULL;
+
+ e_debug(mscript->event, "Destroy");
+
+ event_unref(&mscript->event);
+
+ sieve_result_execution_destroy(&mscript->rexec);
+ sieve_result_unref(&mscript->result);
+ sieve_execute_deinit(&mscript->exec_env);
+ pool_unref(&mscript->pool);
+}
+
+struct sieve_multiscript *
+sieve_multiscript_start_test(struct sieve_instance *svinst,
+ const struct sieve_message_data *msgdata,
+ const struct sieve_script_env *senv,
+ struct ostream *stream)
+{
+ struct sieve_multiscript *mscript =
+ sieve_multiscript_start_execute(svinst, msgdata, senv);
+
+ mscript->teststream = stream;
+
+ return mscript;
+}
+
+static void
+sieve_multiscript_test(struct sieve_multiscript *mscript)
+{
+ const struct sieve_script_env *senv = mscript->exec_env.scriptenv;
+
+ e_debug(mscript->event, "Test result");
+
+ if (mscript->status > 0) {
+ mscript->status =
+ (sieve_result_print(mscript->result, senv,
+ mscript->teststream,
+ &mscript->keep) ?
+ SIEVE_EXEC_OK : SIEVE_EXEC_FAILURE);
+ } else {
+ mscript->keep = TRUE;
+ }
+
+ sieve_result_mark_executed(mscript->result);
+}
+
+static void
+sieve_multiscript_execute(struct sieve_multiscript *mscript,
+ struct sieve_error_handler *ehandler,
+ enum sieve_execute_flags flags)
+{
+ e_debug(mscript->event, "Execute result");
+
+ mscript->exec_env.flags = flags;
+
+ if (mscript->status > 0) {
+ mscript->status = sieve_result_execute(mscript->rexec,
+ SIEVE_EXEC_OK, FALSE,
+ ehandler,
+ &mscript->keep);
+ }
+}
+
+bool sieve_multiscript_run(struct sieve_multiscript *mscript,
+ struct sieve_binary *sbin,
+ struct sieve_error_handler *exec_ehandler,
+ struct sieve_error_handler *action_ehandler,
+ enum sieve_execute_flags flags)
+{
+ if (!mscript->active) {
+ e_debug(mscript->event, "Sequence ended");
+ return FALSE;
+ }
+
+ e_debug(mscript->event, "Run script `%s'", sieve_binary_source(sbin));
+
+ /* Run the script */
+ mscript->exec_env.flags = flags;
+ mscript->status = sieve_run(sbin, mscript->result, &mscript->exec_env,
+ exec_ehandler);
+
+ if (mscript->status >= 0) {
+ mscript->keep = FALSE;
+
+ if (mscript->teststream != NULL)
+ sieve_multiscript_test(mscript);
+ else {
+ sieve_multiscript_execute(mscript, action_ehandler,
+ flags);
+ }
+ if (!mscript->keep)
+ mscript->active = FALSE;
+ }
+
+ if (!mscript->active || mscript->status <= 0) {
+ e_debug(mscript->event, "Sequence ended");
+ mscript->active = FALSE;
+ return FALSE;
+ }
+
+ e_debug(mscript->event, "Sequence active");
+ return TRUE;
+}
+
+bool sieve_multiscript_will_discard(struct sieve_multiscript *mscript)
+{
+ return (!mscript->active && mscript->status == SIEVE_EXEC_OK &&
+ !sieve_result_executed_delivery(mscript->rexec));
+}
+
+void sieve_multiscript_run_discard(struct sieve_multiscript *mscript,
+ struct sieve_binary *sbin,
+ struct sieve_error_handler *exec_ehandler,
+ struct sieve_error_handler *action_ehandler,
+ enum sieve_execute_flags flags)
+{
+ if (!sieve_multiscript_will_discard(mscript)) {
+ e_debug(mscript->event, "Not running discard script");
+ return;
+ }
+ i_assert(!mscript->discard_handled);
+
+ e_debug(mscript->event, "Run discard script `%s'",
+ sieve_binary_source(sbin));
+
+ sieve_result_set_keep_action(mscript->result, NULL, &act_store);
+
+ /* Run the discard script */
+ flags |= SIEVE_EXECUTE_FLAG_DEFER_KEEP;
+ mscript->exec_env.flags = flags;
+ mscript->status = sieve_run(sbin, mscript->result, &mscript->exec_env,
+ exec_ehandler);
+
+ if (mscript->status >= 0) {
+ mscript->keep = FALSE;
+
+ if (mscript->teststream != NULL)
+ sieve_multiscript_test(mscript);
+ else {
+ sieve_multiscript_execute(mscript, action_ehandler,
+ flags);
+ }
+ if (mscript->status == SIEVE_EXEC_FAILURE)
+ mscript->status = SIEVE_EXEC_KEEP_FAILED;
+ mscript->active = FALSE;
+ }
+
+ mscript->discard_handled = TRUE;
+}
+
+int sieve_multiscript_status(struct sieve_multiscript *mscript)
+{
+ return mscript->status;
+}
+
+int sieve_multiscript_finish(struct sieve_multiscript **_mscript,
+ struct sieve_error_handler *action_ehandler,
+ enum sieve_execute_flags flags, int status)
+{
+ struct sieve_multiscript *mscript = *_mscript;
+
+ if (mscript == NULL)
+ return SIEVE_EXEC_OK;
+ *_mscript = NULL;
+
+ switch (status) {
+ case SIEVE_EXEC_OK:
+ status = mscript->status;
+ break;
+ case SIEVE_EXEC_TEMP_FAILURE:
+ break;
+ case SIEVE_EXEC_BIN_CORRUPT:
+ case SIEVE_EXEC_FAILURE:
+ case SIEVE_EXEC_KEEP_FAILED:
+ case SIEVE_EXEC_RESOURCE_LIMIT:
+ if (mscript->status == SIEVE_EXEC_TEMP_FAILURE)
+ status = mscript->status;
+ break;
+ }
+
+ e_debug(mscript->event, "Finishing sequence (status=%s)",
+ sieve_execution_exitcode_to_str(status));
+
+ mscript->exec_env.flags = flags;
+ sieve_result_set_keep_action(mscript->result, NULL, &act_store);
+
+ mscript->keep = FALSE;
+ if (mscript->teststream != NULL)
+ mscript->keep = TRUE;
+ else {
+ status = sieve_result_execute(
+ mscript->rexec, status, TRUE, action_ehandler,
+ &mscript->keep);
+ }
+
+ e_debug(mscript->event, "Sequence finished (status=%s, keep=%s)",
+ sieve_execution_exitcode_to_str(status),
+ (mscript->keep ? "yes" : "no"));
+
+ sieve_execute_finish(&mscript->exec_env, status);
+
+ /* Cleanup */
+ sieve_multiscript_destroy(&mscript);
+
+ return status;
+}
+
+/*
+ * Configured Limits
+ */
+
+unsigned int sieve_max_redirects(struct sieve_instance *svinst)
+{
+ return svinst->max_redirects;
+}
+
+unsigned int sieve_max_actions(struct sieve_instance *svinst)
+{
+ return svinst->max_actions;
+}
+
+size_t sieve_max_script_size(struct sieve_instance *svinst)
+{
+ return svinst->max_script_size;
+}
+
+/*
+ * User log
+ */
+
+const char *
+sieve_user_get_log_path(struct sieve_instance *svinst,
+ struct sieve_script *user_script)
+{
+ const char *log_path = NULL;
+
+ /* Determine user log file path */
+ log_path = sieve_setting_get(svinst, "sieve_user_log");
+ if (log_path == NULL) {
+ const char *path;
+
+ if (user_script == NULL ||
+ (path = sieve_file_script_get_path(user_script)) == NULL) {
+ /* Default */
+ if (svinst->home_dir != NULL) {
+ log_path = t_strconcat(
+ svinst->home_dir, "/.dovecot.sieve.log",
+ NULL);
+ }
+ } else {
+ /* Use script file as a base (legacy behavior) */
+ log_path = t_strconcat(path, ".log", NULL);
+ }
+ } else if (svinst->home_dir != NULL) {
+ /* Expand home dir if necessary */
+ if (log_path[0] == '~') {
+ log_path = home_expand_tilde(log_path,
+ svinst->home_dir);
+ } else if (log_path[0] != '/') {
+ log_path = t_strconcat(svinst->home_dir, "/",
+ log_path, NULL);
+ }
+ }
+ return log_path;
+}
+
+/*
+ * Script trace log
+ */
+
+struct sieve_trace_log {
+ struct ostream *output;
+};
+
+int sieve_trace_log_create(struct sieve_instance *svinst, const char *path,
+ struct sieve_trace_log **trace_log_r)
+{
+ struct sieve_trace_log *trace_log;
+ struct ostream *output;
+ int fd;
+
+ *trace_log_r = NULL;
+
+ if (path == NULL)
+ output = o_stream_create_fd(1, 0);
+ else {
+ fd = open(path, O_CREAT | O_APPEND | O_WRONLY, 0600);
+ if (fd == -1) {
+ e_error(svinst->event, "trace: "
+ "creat(%s) failed: %m", path);
+ return -1;
+ }
+ output = o_stream_create_fd_autoclose(&fd, 0);
+ o_stream_set_name(output, path);
+ }
+
+ trace_log = i_new(struct sieve_trace_log, 1);
+ trace_log->output = output;
+
+ *trace_log_r = trace_log;
+ return 0;
+}
+
+int sieve_trace_log_create_dir(struct sieve_instance *svinst, const char *dir,
+ struct sieve_trace_log **trace_log_r)
+{
+ static unsigned int counter = 0;
+ const char *timestamp, *prefix;
+ struct stat st;
+
+ *trace_log_r = NULL;
+
+ if (stat(dir, &st) < 0) {
+ if (errno != ENOENT && errno != EACCES) {
+ e_error(svinst->event, "trace: "
+ "stat(%s) failed: %m", dir);
+ }
+ return -1;
+ }
+
+ timestamp = t_strflocaltime("%Y%m%d-%H%M%S", ioloop_time);
+
+ counter++;
+
+ prefix = t_strdup_printf("%s/%s.%s.%u.trace",
+ dir, timestamp, my_pid, counter);
+ return sieve_trace_log_create(svinst, prefix, trace_log_r);
+}
+
+int sieve_trace_log_open(struct sieve_instance *svinst,
+ struct sieve_trace_log **trace_log_r)
+{
+ const char *trace_dir =
+ sieve_setting_get(svinst, "sieve_trace_dir");
+
+ *trace_log_r = NULL;
+ if (trace_dir == NULL)
+ return -1;
+
+ if (svinst->home_dir != NULL) {
+ /* Expand home dir if necessary */
+ if (trace_dir[0] == '~') {
+ trace_dir = home_expand_tilde(trace_dir,
+ svinst->home_dir);
+ } else if (trace_dir[0] != '/') {
+ trace_dir = t_strconcat(svinst->home_dir, "/",
+ trace_dir, NULL);
+ }
+ }
+
+ return sieve_trace_log_create_dir(svinst, trace_dir, trace_log_r);
+}
+
+void sieve_trace_log_write_line(struct sieve_trace_log *trace_log,
+ const string_t *line)
+{
+ struct const_iovec iov[2];
+
+ if (line == NULL) {
+ o_stream_nsend_str(trace_log->output, "\n");
+ return;
+ }
+
+ memset(iov, 0, sizeof(iov));
+ iov[0].iov_base = str_data(line);
+ iov[0].iov_len = str_len(line);
+ iov[1].iov_base = "\n";
+ iov[1].iov_len = 1;
+ o_stream_nsendv(trace_log->output, iov, 2);
+}
+
+void sieve_trace_log_printf(struct sieve_trace_log *trace_log,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ T_BEGIN {
+ o_stream_nsend_str(trace_log->output,
+ t_strdup_vprintf(fmt, args));
+ } T_END;
+ va_end(args);
+}
+
+void sieve_trace_log_free(struct sieve_trace_log **_trace_log)
+{
+ struct sieve_trace_log *trace_log = *_trace_log;
+
+ *_trace_log = NULL;
+
+ if (o_stream_finish(trace_log->output) < 0) {
+ i_error("write(%s) failed: %s",
+ o_stream_get_name(trace_log->output),
+ o_stream_get_error(trace_log->output));
+ }
+ o_stream_destroy(&trace_log->output);
+ i_free(trace_log);
+}
+
+int sieve_trace_config_get(struct sieve_instance *svinst,
+ struct sieve_trace_config *tr_config)
+{
+ const char *tr_level =
+ sieve_setting_get(svinst, "sieve_trace_level");
+ bool tr_debug, tr_addresses;
+
+ i_zero(tr_config);
+
+ if (tr_level == NULL || *tr_level == '\0' ||
+ strcasecmp(tr_level, "none") == 0)
+ return -1;
+
+ if (strcasecmp(tr_level, "actions") == 0)
+ tr_config->level = SIEVE_TRLVL_ACTIONS;
+ else if (strcasecmp(tr_level, "commands") == 0)
+ tr_config->level = SIEVE_TRLVL_COMMANDS;
+ else if (strcasecmp(tr_level, "tests") == 0)
+ tr_config->level = SIEVE_TRLVL_TESTS;
+ else if (strcasecmp(tr_level, "matching") == 0)
+ tr_config->level = SIEVE_TRLVL_MATCHING;
+ else {
+ e_error(svinst->event, "Unknown trace level: %s", tr_level);
+ return -1;
+ }
+
+ tr_debug = FALSE;
+ (void)sieve_setting_get_bool_value(svinst, "sieve_trace_debug",
+ &tr_debug);
+ tr_addresses = FALSE;
+ (void)sieve_setting_get_bool_value(svinst, "sieve_trace_addresses",
+ &tr_addresses);
+
+ if (tr_debug)
+ tr_config->flags |= SIEVE_TRFLG_DEBUG;
+ if (tr_addresses)
+ tr_config->flags |= SIEVE_TRFLG_ADDRESSES;
+ return 0;
+}
+
+/*
+ * Execution exit codes
+ */
+
+const char *sieve_execution_exitcode_to_str(int code)
+{
+ switch (code) {
+ case SIEVE_EXEC_OK:
+ return "ok";
+ case SIEVE_EXEC_FAILURE:
+ return "failure";
+ case SIEVE_EXEC_TEMP_FAILURE:
+ return "temporary_failure";
+ case SIEVE_EXEC_BIN_CORRUPT:
+ return "binary_corrupt";
+ case SIEVE_EXEC_KEEP_FAILED:
+ return "keep_failed";
+ case SIEVE_EXEC_RESOURCE_LIMIT:
+ return "resource_limit";
+ }
+ i_unreached();
+}
+
+/*
+ * User e-mail address
+ */
+
+const struct smtp_address *sieve_get_user_email(struct sieve_instance *svinst)
+{
+ struct smtp_address *address;
+ const char *username = svinst->username;
+
+ if (svinst->user_email_implicit != NULL)
+ return svinst->user_email_implicit;
+ if (svinst->user_email != NULL)
+ return svinst->user_email;
+
+ if (smtp_address_parse_mailbox(svinst->pool, username, 0,
+ &address, NULL) >= 0) {
+ svinst->user_email_implicit = address;
+ return svinst->user_email_implicit;
+ }
+
+ if (svinst->domainname != NULL) {
+ svinst->user_email_implicit = smtp_address_create(
+ svinst->pool, username, svinst->domainname);
+ return svinst->user_email_implicit;
+ }
+ return NULL;
+}
+
+/*
+ * Postmaster address
+ */
+
+const struct message_address *
+sieve_get_postmaster(const struct sieve_script_env *senv)
+{
+ i_assert(senv->postmaster_address != NULL);
+ return senv->postmaster_address;
+}
+
+const struct smtp_address *
+sieve_get_postmaster_smtp(const struct sieve_script_env *senv)
+{
+ struct smtp_address *addr;
+ int ret;
+
+ ret = smtp_address_create_from_msg_temp(
+ sieve_get_postmaster(senv), &addr);
+ i_assert(ret >= 0);
+ return addr;
+}
+
+const char *sieve_get_postmaster_address(const struct sieve_script_env *senv)
+{
+ const struct message_address *postmaster =
+ sieve_get_postmaster(senv);
+ string_t *addr = t_str_new(256);
+
+ message_address_write(addr, postmaster);
+ return str_c(addr);
+}
+
+/*
+ * Resource usage
+ */
+
+void sieve_resource_usage_init(struct sieve_resource_usage *rusage_r)
+{
+ i_zero(rusage_r);
+}
+
+void sieve_resource_usage_add(struct sieve_resource_usage *dst,
+ const struct sieve_resource_usage *src)
+{
+ if ((UINT_MAX - dst->cpu_time_msecs) < src->cpu_time_msecs)
+ dst->cpu_time_msecs = UINT_MAX;
+ else
+ dst->cpu_time_msecs += src->cpu_time_msecs;
+}
+
+bool sieve_resource_usage_is_high(struct sieve_instance *svinst ATTR_UNUSED,
+ const struct sieve_resource_usage *rusage)
+{
+ return (rusage->cpu_time_msecs > SIEVE_HIGH_CPU_TIME_MSECS);
+}
+
+bool sieve_resource_usage_is_excessive(
+ struct sieve_instance *svinst,
+ const struct sieve_resource_usage *rusage)
+{
+ i_assert(svinst->max_cpu_time_secs <= (UINT_MAX / 1000));
+ if (svinst->max_cpu_time_secs == 0)
+ return FALSE;
+ return (rusage->cpu_time_msecs > (svinst->max_cpu_time_secs * 1000));
+}
+
+const char *
+sieve_resource_usage_get_summary(const struct sieve_resource_usage *rusage)
+{
+ if (rusage->cpu_time_msecs == 0)
+ return "no usage recorded";
+
+ return t_strdup_printf("cpu time = %u ms", rusage->cpu_time_msecs);
+}
diff --git a/pigeonhole/src/lib-sieve/sieve.h b/pigeonhole/src/lib-sieve/sieve.h
new file mode 100644
index 0000000..66a6d12
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve.h
@@ -0,0 +1,261 @@
+#ifndef SIEVE_H
+#define SIEVE_H
+
+struct sieve_script;
+struct sieve_binary;
+
+#include "sieve-config.h"
+#include "sieve-types.h"
+#include "sieve-error.h"
+
+/*
+ * Main Sieve library interface
+ */
+
+/* Initialize the sieve engine. Must be called before any sieve functionality is
+ used. */
+struct sieve_instance *
+sieve_init(const struct sieve_environment *env,
+ const struct sieve_callbacks *callbacks, void *context, bool debug);
+
+/* Free all memory allocated by the sieve engine. */
+void sieve_deinit(struct sieve_instance **_svinst);
+
+/* Get capability string for a particular extension. */
+const char *
+sieve_get_capabilities(struct sieve_instance *svinst, const char *name);
+
+/* Set the supported extensions. The provided string is parsed into a list
+ of extensions that are to be enabled/disabled. */
+void sieve_set_extensions(struct sieve_instance *svinst,
+ const char *extensions);
+
+
+/* Get top-level event for this Sieve instance. */
+struct event *sieve_get_event(struct sieve_instance *svinst) ATTR_PURE;
+
+/*
+ * Script compilation
+ */
+
+/* Compile a Sieve script from a Sieve script object. Returns Sieve binary upon
+ success and NULL upon failure. */
+struct sieve_binary *
+sieve_compile_script(struct sieve_script *script,
+ struct sieve_error_handler *ehandler,
+ enum sieve_compile_flags flags, enum sieve_error *error_r)
+ ATTR_NULL(2, 4);
+
+/* Compile a Sieve script from a Sieve script location string. Returns Sieve
+ binary upon success and NULL upon failure. The provided script_name is used
+ for the internally created Sieve script object. */
+struct sieve_binary *
+sieve_compile(struct sieve_instance *svinst, const char *script_location,
+ const char *script_name, struct sieve_error_handler *ehandler,
+ enum sieve_compile_flags flags, enum sieve_error *error_r)
+ ATTR_NULL(3, 4, 6);
+
+/*
+ * Reading/writing Sieve binaries
+ */
+
+/* Loads the sieve binary indicated by the provided path. */
+struct sieve_binary *
+sieve_load(struct sieve_instance *svinst, const char *bin_path,
+ enum sieve_error *error_r);
+/* First tries to open the binary version of the specified script and if it does
+ not exist or if it contains errors, the script is (re-)compiled. Note that
+ errors in the bytecode are caught only at runtime.
+ */
+struct sieve_binary *
+sieve_open_script(struct sieve_script *script,
+ struct sieve_error_handler *ehandler,
+ enum sieve_compile_flags flags, enum sieve_error *error_r);
+/* First tries to open the binary version of the specified script and if it does
+ not exist or if it contains errors, the script is (re-)compiled. Note that
+ errors in the bytecode are caught only at runtime.
+ */
+struct sieve_binary *
+sieve_open(struct sieve_instance *svinst, const char *script_location,
+ const char *script_name, struct sieve_error_handler *ehandler,
+ enum sieve_compile_flags flags, enum sieve_error *error_r);
+
+/* Record resource usage in the binary cumulatively. The binary is disabled when
+ resource limits are exceeded within a configured timeout. Returns FALSE when
+ resource limits are exceeded. */
+bool ATTR_NOWARN_UNUSED_RESULT
+sieve_record_resource_usage(struct sieve_binary *sbin,
+ const struct sieve_resource_usage *rusage)
+ ATTR_NULL(1);
+
+/* Check whether Sieve binary is (still) executable. Returns 1 if all is OK,
+ 0 when an error occurred, and -1 when the error is internal. Sets the Sieve
+ error code in error_r and a user error message in client_error_r when the
+ error is not internal. */
+int sieve_check_executable(struct sieve_binary *sbin,
+ enum sieve_error *error_r,
+ const char **client_error_r);
+
+/* Saves the binary as the file indicated by the path parameter. This function
+ will not write the binary to disk when the provided binary object was loaded
+ earlier from the indicated bin_path, unless update is TRUE.
+ */
+int sieve_save_as(struct sieve_binary *sbin, const char *bin_path, bool update,
+ mode_t save_mode, enum sieve_error *error_r);
+
+/* Saves the binary to the default location. This function will not overwrite
+ the binary on disk when the provided binary object was loaded earlier from
+ the default location, unless update is TRUE.
+ */
+int sieve_save(struct sieve_binary *sbin, bool update,
+ enum sieve_error *error_r);
+
+/* Closes a compiled/opened sieve binary. */
+void sieve_close(struct sieve_binary **_sbin);
+
+/* Obtains the path the binary was compiled or loaded from. */
+const char *sieve_get_source(struct sieve_binary *sbin);
+/* Indicates whether the binary was loaded from a pre-compiled file. */
+bool sieve_is_loaded(struct sieve_binary *sbin);
+
+/*
+ * Debugging
+ */
+
+/* Dumps the byte code in human-readable form to the specified ostream. */
+void sieve_dump(struct sieve_binary *sbin,
+ struct ostream *stream, bool verbose);
+/* Dumps the byte code in hexdump form to the specified ostream. */
+void sieve_hexdump(struct sieve_binary *sbin, struct ostream *stream);
+
+/* Executes the bytecode, but only prints the result to the given stream. */
+int sieve_test(struct sieve_binary *sbin,
+ const struct sieve_message_data *msgdata,
+ const struct sieve_script_env *senv,
+ struct sieve_error_handler *ehandler, struct ostream *stream,
+ enum sieve_execute_flags flags);
+
+/*
+ * Script execution
+ */
+
+/* Initializes the scirpt environment from the given mail_user. */
+int sieve_script_env_init(struct sieve_script_env *senv, struct mail_user *user,
+ const char **error_r);
+
+/* Executes the binary, including the result. */
+int sieve_execute(struct sieve_binary *sbin,
+ const struct sieve_message_data *msgdata,
+ const struct sieve_script_env *senv,
+ struct sieve_error_handler *exec_ehandler,
+ struct sieve_error_handler *action_ehandler,
+ enum sieve_execute_flags flags);
+
+/*
+ * Multiscript support
+ */
+
+struct sieve_multiscript;
+
+struct sieve_multiscript *
+sieve_multiscript_start_execute(struct sieve_instance *svinst,
+ const struct sieve_message_data *msgdata,
+ const struct sieve_script_env *senv);
+struct sieve_multiscript *
+sieve_multiscript_start_test(struct sieve_instance *svinst,
+ const struct sieve_message_data *msgdata,
+ const struct sieve_script_env *senv,
+ struct ostream *stream);
+
+bool sieve_multiscript_run(struct sieve_multiscript *mscript,
+ struct sieve_binary *sbin,
+ struct sieve_error_handler *exec_ehandler,
+ struct sieve_error_handler *action_ehandler,
+ enum sieve_execute_flags flags);
+
+bool sieve_multiscript_will_discard(struct sieve_multiscript *mscript);
+void sieve_multiscript_run_discard(struct sieve_multiscript *mscript,
+ struct sieve_binary *sbin,
+ struct sieve_error_handler *exec_ehandler,
+ struct sieve_error_handler *action_ehandler,
+ enum sieve_execute_flags flags);
+
+int sieve_multiscript_status(struct sieve_multiscript *mscript);
+
+int sieve_multiscript_finish(struct sieve_multiscript **_mscript,
+ struct sieve_error_handler *action_ehandler,
+ enum sieve_execute_flags flags, int status);
+
+/*
+ * Configured limits
+ */
+
+unsigned int sieve_max_redirects(struct sieve_instance *svinst);
+unsigned int sieve_max_actions(struct sieve_instance *svinst);
+size_t sieve_max_script_size(struct sieve_instance *svinst);
+
+/*
+ * User log
+ */
+
+const char *sieve_user_get_log_path(struct sieve_instance *svinst,
+ struct sieve_script *user_script)
+ ATTR_NULL(2);
+
+/*
+ * Script trace log
+ */
+
+struct sieve_trace_log;
+
+int sieve_trace_log_create(struct sieve_instance *svinst, const char *path,
+ struct sieve_trace_log **trace_log_r) ATTR_NULL(2);
+int sieve_trace_log_create_dir(struct sieve_instance *svinst, const char *dir,
+ struct sieve_trace_log **trace_log_r)
+ ATTR_NULL(3);
+
+int sieve_trace_log_open(struct sieve_instance *svinst,
+ struct sieve_trace_log **trace_log_r) ATTR_NULL(2);
+
+void sieve_trace_log_printf(struct sieve_trace_log *trace_log,
+ const char *fmt, ...) ATTR_FORMAT(2, 3);
+
+void sieve_trace_log_free(struct sieve_trace_log **_trace_log);
+
+int sieve_trace_config_get(struct sieve_instance *svinst,
+ struct sieve_trace_config *tr_config);
+
+/*
+ * Execution exit codes
+ */
+
+const char *sieve_execution_exitcode_to_str(int code);
+
+/*
+ * Resource usage
+ */
+
+/* Initialize the resource usage struct, clearing all usage statistics. */
+void sieve_resource_usage_init(struct sieve_resource_usage *rusage_r);
+
+/* Calculate the sum of the provided resource usage statistics, writing the
+ result to the first. */
+void sieve_resource_usage_add(struct sieve_resource_usage *dst,
+ const struct sieve_resource_usage *src);
+
+/* Returns TRUE if the resource usage is sufficiently high to warrant recording
+ for checking cumulative resource limits (across several different script
+ executions). */
+bool sieve_resource_usage_is_high(struct sieve_instance *svinst,
+ const struct sieve_resource_usage *rusage);
+/* Returns TRUE when the provided resource usage statistics exceed a configured
+ policy limit. */
+bool sieve_resource_usage_is_excessive(
+ struct sieve_instance *svinst,
+ const struct sieve_resource_usage *rusage);
+/* Returns a string containing a description of the resource usage (to be used
+ log messages). */
+const char *
+sieve_resource_usage_get_summary(const struct sieve_resource_usage *rusage);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/storage/Makefile.am b/pigeonhole/src/lib-sieve/storage/Makefile.am
new file mode 100644
index 0000000..ba39e4a
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/Makefile.am
@@ -0,0 +1,5 @@
+SUBDIRS = \
+ data \
+ file \
+ dict \
+ ldap
diff --git a/pigeonhole/src/lib-sieve/storage/Makefile.in b/pigeonhole/src/lib-sieve/storage/Makefile.in
new file mode 100644
index 0000000..d81c0c5
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/Makefile.in
@@ -0,0 +1,697 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/storage
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = \
+ data \
+ file \
+ dict \
+ ldap
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/storage/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/storage/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/storage/data/Makefile.am b/pigeonhole/src/lib-sieve/storage/data/Makefile.am
new file mode 100644
index 0000000..c17741d
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/data/Makefile.am
@@ -0,0 +1,13 @@
+noinst_LTLIBRARIES = libsieve_storage_data.la
+
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src/lib-sieve
+
+libsieve_storage_data_la_SOURCES = \
+ sieve-data-script.c \
+ sieve-data-storage.c
+
+noinst_HEADERS = \
+ sieve-data-storage.h
diff --git a/pigeonhole/src/lib-sieve/storage/data/Makefile.in b/pigeonhole/src/lib-sieve/storage/data/Makefile.in
new file mode 100644
index 0000000..199f2db
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/data/Makefile.in
@@ -0,0 +1,686 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/storage/data
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_storage_data_la_LIBADD =
+am_libsieve_storage_data_la_OBJECTS = sieve-data-script.lo \
+ sieve-data-storage.lo
+libsieve_storage_data_la_OBJECTS = \
+ $(am_libsieve_storage_data_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/sieve-data-script.Plo \
+ ./$(DEPDIR)/sieve-data-storage.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_storage_data_la_SOURCES)
+DIST_SOURCES = $(libsieve_storage_data_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_storage_data.la
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src/lib-sieve
+
+libsieve_storage_data_la_SOURCES = \
+ sieve-data-script.c \
+ sieve-data-storage.c
+
+noinst_HEADERS = \
+ sieve-data-storage.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/storage/data/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/storage/data/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_storage_data.la: $(libsieve_storage_data_la_OBJECTS) $(libsieve_storage_data_la_DEPENDENCIES) $(EXTRA_libsieve_storage_data_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_storage_data_la_OBJECTS) $(libsieve_storage_data_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-data-script.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-data-storage.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/sieve-data-script.Plo
+ -rm -f ./$(DEPDIR)/sieve-data-storage.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/sieve-data-script.Plo
+ -rm -f ./$(DEPDIR)/sieve-data-storage.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/storage/data/sieve-data-script.c b/pigeonhole/src/lib-sieve/storage/data/sieve-data-script.c
new file mode 100644
index 0000000..2241bc5
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/data/sieve-data-script.c
@@ -0,0 +1,95 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "strfuncs.h"
+#include "istream.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-dump.h"
+#include "sieve-binary.h"
+
+#include "sieve-data-storage.h"
+
+/*
+ * Script data implementation
+ */
+
+static struct sieve_data_script *sieve_data_script_alloc(void)
+{
+ struct sieve_data_script *dscript;
+ pool_t pool;
+
+ pool = pool_alloconly_create("sieve_data_script", 1024);
+ dscript = p_new(pool, struct sieve_data_script, 1);
+ dscript->script = sieve_data_script;
+ dscript->script.pool = pool;
+
+ return dscript;
+}
+
+struct sieve_script *sieve_data_script_create_from_input
+(struct sieve_instance *svinst, const char *name, struct istream *input)
+{
+ struct sieve_storage *storage;
+ struct sieve_data_script *dscript = NULL;
+
+ storage = sieve_storage_alloc(svinst, NULL, &sieve_data_storage,
+ "", 0, FALSE);
+
+ dscript = sieve_data_script_alloc();
+ sieve_script_init(&dscript->script,
+ storage, &sieve_data_script, "data:", name);
+
+ dscript->data = input;
+ i_stream_ref(dscript->data);
+
+ sieve_storage_unref(&storage);
+
+ dscript->script.open = TRUE;
+
+ return &dscript->script;
+}
+
+static void sieve_data_script_destroy(struct sieve_script *script)
+{
+ struct sieve_data_script *dscript =
+ (struct sieve_data_script *)script;
+
+ i_stream_unref(&dscript->data);
+}
+
+static int sieve_data_script_get_stream
+(struct sieve_script *script, struct istream **stream_r,
+ enum sieve_error *error_r)
+{
+ struct sieve_data_script *dscript =
+ (struct sieve_data_script *)script;
+
+ i_stream_ref(dscript->data);
+ i_stream_seek(dscript->data, 0);
+
+ *stream_r = dscript->data;
+ *error_r = SIEVE_ERROR_NONE;
+ return 0;
+}
+
+static bool sieve_data_script_equals
+(const struct sieve_script *script ATTR_UNUSED,
+ const struct sieve_script *other ATTR_UNUSED)
+{
+ return ( script == other );
+}
+
+const struct sieve_script sieve_data_script = {
+ .driver_name = SIEVE_DATA_STORAGE_DRIVER_NAME,
+ .v = {
+ .destroy = sieve_data_script_destroy,
+
+ .get_stream = sieve_data_script_get_stream,
+
+ .equals = sieve_data_script_equals
+ }
+};
diff --git a/pigeonhole/src/lib-sieve/storage/data/sieve-data-storage.c b/pigeonhole/src/lib-sieve/storage/data/sieve-data-storage.c
new file mode 100644
index 0000000..21b4f35
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/data/sieve-data-storage.c
@@ -0,0 +1,47 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+
+#include "sieve-data-storage.h"
+
+/*
+ * Storage class
+ */
+
+static struct sieve_storage *sieve_data_storage_alloc(void)
+{
+ struct sieve_data_storage *dstorage;
+ pool_t pool;
+
+ pool = pool_alloconly_create("sieve_data_storage", 1024);
+ dstorage = p_new(pool, struct sieve_data_storage, 1);
+ dstorage->storage = sieve_data_storage;
+ dstorage->storage.pool = pool;
+
+ return &dstorage->storage;
+}
+
+static int sieve_data_storage_init
+(struct sieve_storage *storage ATTR_UNUSED,
+ const char *const *options ATTR_UNUSED,
+ enum sieve_error *error_r ATTR_UNUSED)
+{
+ return 0;
+}
+
+/*
+ * Driver definition
+ */
+
+const struct sieve_storage sieve_data_storage = {
+ .driver_name = SIEVE_DATA_STORAGE_DRIVER_NAME,
+ .version = 0,
+ .v = {
+ .alloc = sieve_data_storage_alloc,
+ .init = sieve_data_storage_init,
+ }
+};
diff --git a/pigeonhole/src/lib-sieve/storage/data/sieve-data-storage.h b/pigeonhole/src/lib-sieve/storage/data/sieve-data-storage.h
new file mode 100644
index 0000000..a200e25
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/data/sieve-data-storage.h
@@ -0,0 +1,30 @@
+#ifndef SIEVE_DATA_STORAGE_H
+#define SIEVE_DATA_STORAGE_H
+
+#include "sieve.h"
+#include "sieve-script-private.h"
+#include "sieve-storage-private.h"
+
+/*
+ * Storage class
+ */
+
+struct sieve_data_storage {
+ struct sieve_storage storage;
+};
+
+/*
+ * Script class
+ */
+
+struct sieve_data_script {
+ struct sieve_script script;
+
+ struct istream *data;
+};
+
+struct sieve_script *sieve_data_script_create_from_input
+ (struct sieve_instance *svinst, const char *name,
+ struct istream *input);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/storage/dict/Makefile.am b/pigeonhole/src/lib-sieve/storage/dict/Makefile.am
new file mode 100644
index 0000000..2a73f43
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/dict/Makefile.am
@@ -0,0 +1,13 @@
+noinst_LTLIBRARIES = libsieve_storage_dict.la
+
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src/lib-sieve
+
+libsieve_storage_dict_la_SOURCES = \
+ sieve-dict-script.c \
+ sieve-dict-storage.c
+
+noinst_HEADERS = \
+ sieve-dict-storage.h
diff --git a/pigeonhole/src/lib-sieve/storage/dict/Makefile.in b/pigeonhole/src/lib-sieve/storage/dict/Makefile.in
new file mode 100644
index 0000000..58fd0c5
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/dict/Makefile.in
@@ -0,0 +1,686 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/storage/dict
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_storage_dict_la_LIBADD =
+am_libsieve_storage_dict_la_OBJECTS = sieve-dict-script.lo \
+ sieve-dict-storage.lo
+libsieve_storage_dict_la_OBJECTS = \
+ $(am_libsieve_storage_dict_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/sieve-dict-script.Plo \
+ ./$(DEPDIR)/sieve-dict-storage.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_storage_dict_la_SOURCES)
+DIST_SOURCES = $(libsieve_storage_dict_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_storage_dict.la
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src/lib-sieve
+
+libsieve_storage_dict_la_SOURCES = \
+ sieve-dict-script.c \
+ sieve-dict-storage.c
+
+noinst_HEADERS = \
+ sieve-dict-storage.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/storage/dict/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/storage/dict/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_storage_dict.la: $(libsieve_storage_dict_la_OBJECTS) $(libsieve_storage_dict_la_DEPENDENCIES) $(EXTRA_libsieve_storage_dict_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_storage_dict_la_OBJECTS) $(libsieve_storage_dict_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-dict-script.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-dict-storage.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/sieve-dict-script.Plo
+ -rm -f ./$(DEPDIR)/sieve-dict-storage.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/sieve-dict-script.Plo
+ -rm -f ./$(DEPDIR)/sieve-dict-storage.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/storage/dict/sieve-dict-script.c b/pigeonhole/src/lib-sieve/storage/dict/sieve-dict-script.c
new file mode 100644
index 0000000..eb28f7d
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/dict/sieve-dict-script.c
@@ -0,0 +1,343 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "strfuncs.h"
+#include "istream.h"
+#include "dict.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-dump.h"
+#include "sieve-binary.h"
+
+#include "sieve-dict-storage.h"
+
+/*
+ * Script dict implementation
+ */
+
+static struct sieve_dict_script *sieve_dict_script_alloc(void)
+{
+ struct sieve_dict_script *dscript;
+ pool_t pool;
+
+ pool = pool_alloconly_create("sieve_dict_script", 1024);
+ dscript = p_new(pool, struct sieve_dict_script, 1);
+ dscript->script = sieve_dict_script;
+ dscript->script.pool = pool;
+
+ return dscript;
+}
+
+struct sieve_dict_script *sieve_dict_script_init
+(struct sieve_dict_storage *dstorage, const char *name)
+{
+ struct sieve_storage *storage = &dstorage->storage;
+ struct sieve_dict_script *dscript = NULL;
+ const char *location;
+
+ if ( name == NULL ) {
+ name = SIEVE_DICT_SCRIPT_DEFAULT;
+ location = storage->location;
+ } else {
+ location = t_strconcat
+ (storage->location, ";name=", name, NULL);
+ }
+
+ dscript = sieve_dict_script_alloc();
+ sieve_script_init(&dscript->script,
+ storage, &sieve_dict_script, location, name);
+
+ return dscript;
+}
+
+static void sieve_dict_script_destroy(struct sieve_script *script)
+{
+ struct sieve_dict_script *dscript =
+ (struct sieve_dict_script *)script;
+
+ if ( dscript->data_pool != NULL )
+ pool_unref(&dscript->data_pool);
+}
+
+static int sieve_dict_script_open
+(struct sieve_script *script, enum sieve_error *error_r)
+{
+ struct sieve_dict_script *dscript =
+ (struct sieve_dict_script *)script;
+ struct sieve_storage *storage = script->storage;
+ struct sieve_dict_storage *dstorage =
+ (struct sieve_dict_storage *)storage;
+ const char *name = script->name;
+ const char *path, *data_id, *error;
+ int ret;
+
+ if ( sieve_dict_storage_get_dict
+ (dstorage, &dscript->dict, error_r) < 0 )
+ return -1;
+
+ path = t_strconcat
+ (DICT_SIEVE_NAME_PATH, dict_escape_string(name), NULL);
+
+ struct dict_op_settings set = {
+ .username = dstorage->username,
+ };
+ ret = dict_lookup
+ (dscript->dict, &set, script->pool, path, &data_id, &error);
+ if ( ret <= 0 ) {
+ if ( ret < 0 ) {
+ sieve_script_set_critical(script,
+ "Failed to lookup script id from path %s: %s", path, error);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ } else {
+ e_debug(script->event,
+ "Script `%s' not found at path %s", name, path);
+ sieve_script_set_error(script,
+ SIEVE_ERROR_NOT_FOUND,
+ "Sieve script `%s' not found", name);
+ *error_r = SIEVE_ERROR_NOT_FOUND;
+ }
+ return -1;
+ }
+
+ dscript->data_id = p_strdup(script->pool, data_id);
+ return 0;
+}
+
+static int sieve_dict_script_get_stream
+(struct sieve_script *script, struct istream **stream_r,
+ enum sieve_error *error_r)
+{
+ struct sieve_dict_script *dscript =
+ (struct sieve_dict_script *)script;
+ struct sieve_dict_storage *dstorage =
+ (struct sieve_dict_storage *)script->storage;
+ const char *path, *name = script->name, *data, *error;
+ int ret;
+
+ dscript->data_pool =
+ pool_alloconly_create("sieve_dict_script data pool", 1024);
+
+ path = t_strconcat
+ (DICT_SIEVE_DATA_PATH, dict_escape_string(dscript->data_id), NULL);
+
+ struct dict_op_settings set = {
+ .username = dstorage->username,
+ };
+ ret = dict_lookup
+ (dscript->dict, &set, dscript->data_pool, path, &data, &error);
+ if ( ret <= 0 ) {
+ if ( ret < 0 ) {
+ sieve_script_set_critical(script,
+ "Failed to lookup data with id `%s' "
+ "for script `%s' from path %s: %s",
+ dscript->data_id, name, path, error);
+ } else {
+ sieve_script_set_critical(script,
+ "Data with id `%s' for script `%s' "
+ "not found at path %s",
+ dscript->data_id, name, path);
+ }
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+
+ dscript->data = p_strdup(script->pool, data);
+ *stream_r = i_stream_create_from_data(dscript->data, strlen(dscript->data));
+ return 0;
+}
+
+static int sieve_dict_script_binary_read_metadata
+(struct sieve_script *script, struct sieve_binary_block *sblock,
+ sieve_size_t *offset)
+{
+ struct sieve_dict_script *dscript =
+ (struct sieve_dict_script *)script;
+ struct sieve_binary *sbin =
+ sieve_binary_block_get_binary(sblock);
+ string_t *data_id;
+
+ if ( dscript->data_id == NULL &&
+ sieve_script_open(script, NULL) < 0 )
+ return 0;
+
+ if ( !sieve_binary_read_string(sblock, offset, &data_id) ) {
+ e_error(script->event,
+ "Binary `%s' has invalid metadata for script `%s'",
+ sieve_binary_path(sbin), sieve_script_location(script));
+ return -1;
+ }
+ i_assert( dscript->data_id != NULL );
+ if ( strcmp(str_c(data_id), dscript->data_id) != 0 ) {
+ e_debug(script->event,
+ "Binary `%s' reports different data ID for script `%s' "
+ "(`%s' rather than `%s')",
+ sieve_binary_path(sbin), sieve_script_location(script),
+ str_c(data_id), dscript->data_id);
+ return 0;
+ }
+ return 1;
+}
+
+static void sieve_dict_script_binary_write_metadata
+(struct sieve_script *script, struct sieve_binary_block *sblock)
+{
+ struct sieve_dict_script *dscript =
+ (struct sieve_dict_script *)script;
+
+ sieve_binary_emit_cstring(sblock, dscript->data_id);
+}
+
+static bool sieve_dict_script_binary_dump_metadata
+(struct sieve_script *script ATTR_UNUSED, struct sieve_dumptime_env *denv,
+ struct sieve_binary_block *sblock, sieve_size_t *offset)
+{
+ string_t *data_id;
+
+ if ( !sieve_binary_read_string(sblock, offset, &data_id) )
+ return FALSE;
+ sieve_binary_dumpf(denv, "dict.data_id = %s\n", str_c(data_id));
+
+ return TRUE;
+}
+
+static const char * sieve_dict_script_get_binpath
+(struct sieve_dict_script *dscript)
+{
+ struct sieve_script *script = &dscript->script;
+ struct sieve_storage *storage = script->storage;
+
+ if ( dscript->binpath == NULL ) {
+ if ( storage->bin_dir == NULL )
+ return NULL;
+ dscript->binpath = p_strconcat(script->pool,
+ storage->bin_dir, "/",
+ sieve_binfile_from_name(script->name), NULL);
+ }
+
+ return dscript->binpath;
+}
+
+static struct sieve_binary *sieve_dict_script_binary_load
+(struct sieve_script *script, enum sieve_error *error_r)
+{
+ struct sieve_dict_script *dscript =
+ (struct sieve_dict_script *)script;
+
+ if ( sieve_dict_script_get_binpath(dscript) == NULL )
+ return NULL;
+
+ return sieve_binary_open(script->storage->svinst,
+ dscript->binpath, script, error_r);
+}
+
+static int sieve_dict_script_binary_save
+(struct sieve_script *script, struct sieve_binary *sbin, bool update,
+ enum sieve_error *error_r)
+{
+ struct sieve_dict_script *dscript =
+ (struct sieve_dict_script *)script;
+
+ if ( sieve_dict_script_get_binpath(dscript) == NULL )
+ return 0;
+ if ( sieve_storage_setup_bindir(script->storage, 0700) < 0 )
+ return -1;
+
+ return sieve_binary_save(sbin,
+ dscript->binpath, update, 0600, error_r);
+}
+
+static bool sieve_dict_script_equals
+(const struct sieve_script *script, const struct sieve_script *other)
+{
+ struct sieve_storage *storage = script->storage;
+ struct sieve_storage *sother = other->storage;
+
+ if ( strcmp(storage->location, sother->location) != 0 )
+ return FALSE;
+
+ i_assert( script->name != NULL && other->name != NULL );
+
+ return ( strcmp(script->name, other->name) == 0 );
+}
+
+const struct sieve_script sieve_dict_script = {
+ .driver_name = SIEVE_DICT_STORAGE_DRIVER_NAME,
+ .v = {
+ .destroy = sieve_dict_script_destroy,
+
+ .open = sieve_dict_script_open,
+
+ .get_stream = sieve_dict_script_get_stream,
+
+ .binary_read_metadata =sieve_dict_script_binary_read_metadata,
+ .binary_write_metadata = sieve_dict_script_binary_write_metadata,
+ .binary_dump_metadata = sieve_dict_script_binary_dump_metadata,
+ .binary_load = sieve_dict_script_binary_load,
+ .binary_save = sieve_dict_script_binary_save,
+
+ .equals = sieve_dict_script_equals
+ }
+};
+
+/*
+ * Script sequence
+ */
+
+struct sieve_dict_script_sequence {
+ struct sieve_script_sequence seq;
+
+ bool done:1;
+};
+
+struct sieve_script_sequence *sieve_dict_storage_get_script_sequence
+(struct sieve_storage *storage, enum sieve_error *error_r)
+{
+ struct sieve_dict_script_sequence *dseq = NULL;
+
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_NONE;
+
+ /* Create sequence object */
+ dseq = i_new(struct sieve_dict_script_sequence, 1);
+ sieve_script_sequence_init(&dseq->seq, storage);
+
+ return &dseq->seq;
+}
+
+struct sieve_script *sieve_dict_script_sequence_next
+(struct sieve_script_sequence *seq, enum sieve_error *error_r)
+{
+ struct sieve_dict_script_sequence *dseq =
+ (struct sieve_dict_script_sequence *)seq;
+ struct sieve_dict_storage *dstorage =
+ (struct sieve_dict_storage *)seq->storage;
+ struct sieve_dict_script *dscript;
+
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_NONE;
+
+ if ( dseq->done )
+ return NULL;
+ dseq->done = TRUE;
+
+ dscript = sieve_dict_script_init
+ (dstorage, seq->storage->script_name);
+ if ( sieve_script_open(&dscript->script, error_r) < 0 ) {
+ struct sieve_script *script = &dscript->script;
+ sieve_script_unref(&script);
+ return NULL;
+ }
+
+ return &dscript->script;
+}
+
+void sieve_dict_script_sequence_destroy(struct sieve_script_sequence *seq)
+{
+ struct sieve_dict_script_sequence *dseq =
+ (struct sieve_dict_script_sequence *)seq;
+ i_free(dseq);
+}
+
diff --git a/pigeonhole/src/lib-sieve/storage/dict/sieve-dict-storage.c b/pigeonhole/src/lib-sieve/storage/dict/sieve-dict-storage.c
new file mode 100644
index 0000000..7f50816
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/dict/sieve-dict-storage.c
@@ -0,0 +1,193 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "dict.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+
+#include "sieve-dict-storage.h"
+
+/*
+ * Storage class
+ */
+
+static struct sieve_storage *sieve_dict_storage_alloc(void)
+{
+ struct sieve_dict_storage *dstorage;
+ pool_t pool;
+
+ pool = pool_alloconly_create("sieve_dict_storage", 1024);
+ dstorage = p_new(pool, struct sieve_dict_storage, 1);
+ dstorage->storage = sieve_dict_storage;
+ dstorage->storage.pool = pool;
+
+ return &dstorage->storage;
+}
+
+static int sieve_dict_storage_init
+(struct sieve_storage *storage, const char *const *options,
+ enum sieve_error *error_r)
+{
+ struct sieve_dict_storage *dstorage =
+ (struct sieve_dict_storage *)storage;
+ struct sieve_instance *svinst = storage->svinst;
+ const char *uri = storage->location, *username = NULL;
+
+ if ( options != NULL ) {
+ while ( *options != NULL ) {
+ const char *option = *options;
+
+ if ( strncasecmp(option, "user=", 5) == 0 && option[5] != '\0' ) {
+ username = option+5;
+ } else {
+ sieve_storage_set_critical(storage,
+ "Invalid option `%s'", option);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+
+ options++;
+ }
+ }
+
+ if ( username == NULL ) {
+ if ( svinst->username == NULL ) {
+ sieve_storage_set_critical(storage,
+ "No username specified");
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+ username = svinst->username;
+ }
+
+ if ( svinst->base_dir == NULL ) {
+ sieve_storage_set_critical(storage,
+ "BUG: Sieve interpreter is initialized without a base_dir");
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+
+ e_debug(storage->event, "user=%s, uri=%s", username, uri);
+
+ dstorage->uri = p_strdup(storage->pool, uri);
+ dstorage->username = p_strdup(storage->pool, username);
+
+ storage->location = p_strconcat(storage->pool,
+ SIEVE_DICT_STORAGE_DRIVER_NAME, ":", storage->location,
+ ";user=", username, NULL);
+
+ return 0;
+}
+
+int sieve_dict_storage_get_dict
+(struct sieve_dict_storage *dstorage, struct dict **dict_r,
+ enum sieve_error *error_r)
+{
+ struct sieve_storage *storage = &dstorage->storage;
+ struct sieve_instance *svinst = storage->svinst;
+ struct dict_settings dict_set;
+ const char *error;
+ int ret;
+
+ if ( dstorage->dict == NULL ) {
+ i_zero(&dict_set);
+ dict_set.base_dir = svinst->base_dir;
+ ret = dict_init(dstorage->uri, &dict_set, &dstorage->dict, &error);
+ if ( ret < 0 ) {
+ sieve_storage_set_critical(storage,
+ "Failed to initialize dict with data `%s' for user `%s': %s",
+ dstorage->uri, dstorage->username, error);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+ }
+
+ *dict_r = dstorage->dict;
+ return 0;
+}
+
+static void sieve_dict_storage_destroy(struct sieve_storage *storage)
+{
+ struct sieve_dict_storage *dstorage =
+ (struct sieve_dict_storage *)storage;
+
+ if ( dstorage->dict != NULL )
+ dict_deinit(&dstorage->dict);
+}
+
+/*
+ * Script access
+ */
+
+static struct sieve_script *sieve_dict_storage_get_script
+(struct sieve_storage *storage, const char *name)
+{
+ struct sieve_dict_storage *dstorage =
+ (struct sieve_dict_storage *)storage;
+ struct sieve_dict_script *dscript;
+
+ T_BEGIN {
+ dscript = sieve_dict_script_init(dstorage, name);
+ } T_END;
+
+ return &dscript->script;
+}
+
+/*
+ * Active script
+ */
+
+struct sieve_script *sieve_dict_storage_active_script_open
+(struct sieve_storage *storage)
+{
+ struct sieve_dict_storage *dstorage =
+ (struct sieve_dict_storage *)storage;
+ struct sieve_dict_script *dscript;
+
+ dscript = sieve_dict_script_init
+ (dstorage, storage->script_name);
+ if ( sieve_script_open(&dscript->script, NULL) < 0 ) {
+ struct sieve_script *script = &dscript->script;
+ sieve_script_unref(&script);
+ return NULL;
+ }
+
+ return &dscript->script;
+}
+
+int sieve_dict_storage_active_script_get_name
+(struct sieve_storage *storage, const char **name_r)
+{
+ if ( storage->script_name != NULL )
+ *name_r = storage->script_name;
+ else
+ *name_r = SIEVE_DICT_SCRIPT_DEFAULT;
+ return 0;
+}
+
+/*
+ * Driver definition
+ */
+
+const struct sieve_storage sieve_dict_storage = {
+ .driver_name = SIEVE_DICT_STORAGE_DRIVER_NAME,
+ .version = 0,
+ .v = {
+ .alloc = sieve_dict_storage_alloc,
+ .destroy = sieve_dict_storage_destroy,
+ .init = sieve_dict_storage_init,
+
+ .get_script = sieve_dict_storage_get_script,
+
+ .get_script_sequence = sieve_dict_storage_get_script_sequence,
+ .script_sequence_next = sieve_dict_script_sequence_next,
+ .script_sequence_destroy = sieve_dict_script_sequence_destroy,
+
+ .active_script_get_name = sieve_dict_storage_active_script_get_name,
+ .active_script_open = sieve_dict_storage_active_script_open,
+
+ // FIXME: impement management interface
+ }
+};
diff --git a/pigeonhole/src/lib-sieve/storage/dict/sieve-dict-storage.h b/pigeonhole/src/lib-sieve/storage/dict/sieve-dict-storage.h
new file mode 100644
index 0000000..1f92221
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/dict/sieve-dict-storage.h
@@ -0,0 +1,66 @@
+#ifndef SIEVE_DICT_STORAGE_H
+#define SIEVE_DICT_STORAGE_H
+
+#include "sieve.h"
+#include "sieve-script-private.h"
+#include "sieve-storage-private.h"
+
+#define DICT_SIEVE_PATH DICT_PATH_PRIVATE"sieve/"
+#define DICT_SIEVE_NAME_PATH DICT_SIEVE_PATH"name/"
+#define DICT_SIEVE_DATA_PATH DICT_SIEVE_PATH"data/"
+
+#define SIEVE_DICT_SCRIPT_DEFAULT "default"
+
+/*
+ * Storage class
+ */
+
+struct sieve_dict_storage {
+ struct sieve_storage storage;
+
+ const char *username;
+ const char *uri;
+
+ struct dict *dict;
+};
+
+int sieve_dict_storage_get_dict
+ (struct sieve_dict_storage *dstorage, struct dict **dict_r,
+ enum sieve_error *error_r);
+
+struct sieve_script *sieve_dict_storage_active_script_open
+ (struct sieve_storage *storage);
+int sieve_dict_storage_active_script_get_name
+ (struct sieve_storage *storage, const char **name_r);
+
+/*
+ * Script class
+ */
+
+struct sieve_dict_script {
+ struct sieve_script script;
+
+ struct dict *dict;
+
+ pool_t data_pool;
+ const char *data_id;
+ const char *data;
+
+ const char *binpath;
+};
+
+struct sieve_dict_script *sieve_dict_script_init
+ (struct sieve_dict_storage *dstorage, const char *name);
+
+/*
+ * Script sequence
+ */
+
+struct sieve_script_sequence *sieve_dict_storage_get_script_sequence
+ (struct sieve_storage *storage, enum sieve_error *error_r);
+
+struct sieve_script *sieve_dict_script_sequence_next
+ (struct sieve_script_sequence *seq, enum sieve_error *error_r);
+void sieve_dict_script_sequence_destroy(struct sieve_script_sequence *seq);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/storage/file/Makefile.am b/pigeonhole/src/lib-sieve/storage/file/Makefile.am
new file mode 100644
index 0000000..b401fa8
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/file/Makefile.am
@@ -0,0 +1,19 @@
+noinst_LTLIBRARIES = libsieve_storage_file.la
+
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src/lib-sieve \
+ -I$(top_srcdir)/src/lib-sieve/util
+
+libsieve_storage_file_la_SOURCES = \
+ sieve-file-script.c \
+ sieve-file-script-sequence.c \
+ sieve-file-storage-active.c \
+ sieve-file-storage-save.c \
+ sieve-file-storage-list.c \
+ sieve-file-storage-quota.c \
+ sieve-file-storage.c
+
+noinst_HEADERS = \
+ sieve-file-storage.h
diff --git a/pigeonhole/src/lib-sieve/storage/file/Makefile.in b/pigeonhole/src/lib-sieve/storage/file/Makefile.in
new file mode 100644
index 0000000..8432831
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/file/Makefile.in
@@ -0,0 +1,714 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib-sieve/storage/file
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_storage_file_la_LIBADD =
+am_libsieve_storage_file_la_OBJECTS = sieve-file-script.lo \
+ sieve-file-script-sequence.lo sieve-file-storage-active.lo \
+ sieve-file-storage-save.lo sieve-file-storage-list.lo \
+ sieve-file-storage-quota.lo sieve-file-storage.lo
+libsieve_storage_file_la_OBJECTS = \
+ $(am_libsieve_storage_file_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/sieve-file-script-sequence.Plo \
+ ./$(DEPDIR)/sieve-file-script.Plo \
+ ./$(DEPDIR)/sieve-file-storage-active.Plo \
+ ./$(DEPDIR)/sieve-file-storage-list.Plo \
+ ./$(DEPDIR)/sieve-file-storage-quota.Plo \
+ ./$(DEPDIR)/sieve-file-storage-save.Plo \
+ ./$(DEPDIR)/sieve-file-storage.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_storage_file_la_SOURCES)
+DIST_SOURCES = $(libsieve_storage_file_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_storage_file.la
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src/lib-sieve \
+ -I$(top_srcdir)/src/lib-sieve/util
+
+libsieve_storage_file_la_SOURCES = \
+ sieve-file-script.c \
+ sieve-file-script-sequence.c \
+ sieve-file-storage-active.c \
+ sieve-file-storage-save.c \
+ sieve-file-storage-list.c \
+ sieve-file-storage-quota.c \
+ sieve-file-storage.c
+
+noinst_HEADERS = \
+ sieve-file-storage.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/storage/file/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/storage/file/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_storage_file.la: $(libsieve_storage_file_la_OBJECTS) $(libsieve_storage_file_la_DEPENDENCIES) $(EXTRA_libsieve_storage_file_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_storage_file_la_OBJECTS) $(libsieve_storage_file_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-file-script-sequence.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-file-script.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-file-storage-active.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-file-storage-list.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-file-storage-quota.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-file-storage-save.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-file-storage.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/sieve-file-script-sequence.Plo
+ -rm -f ./$(DEPDIR)/sieve-file-script.Plo
+ -rm -f ./$(DEPDIR)/sieve-file-storage-active.Plo
+ -rm -f ./$(DEPDIR)/sieve-file-storage-list.Plo
+ -rm -f ./$(DEPDIR)/sieve-file-storage-quota.Plo
+ -rm -f ./$(DEPDIR)/sieve-file-storage-save.Plo
+ -rm -f ./$(DEPDIR)/sieve-file-storage.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/sieve-file-script-sequence.Plo
+ -rm -f ./$(DEPDIR)/sieve-file-script.Plo
+ -rm -f ./$(DEPDIR)/sieve-file-storage-active.Plo
+ -rm -f ./$(DEPDIR)/sieve-file-storage-list.Plo
+ -rm -f ./$(DEPDIR)/sieve-file-storage-quota.Plo
+ -rm -f ./$(DEPDIR)/sieve-file-storage-save.Plo
+ -rm -f ./$(DEPDIR)/sieve-file-storage.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/storage/file/sieve-file-script-sequence.c b/pigeonhole/src/lib-sieve/storage/file/sieve-file-script-sequence.c
new file mode 100644
index 0000000..a1ae75d
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/file/sieve-file-script-sequence.c
@@ -0,0 +1,244 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "array.h"
+#include "eacces-error.h"
+
+#include "sieve-common.h"
+#include "sieve-script-private.h"
+
+#include "sieve-file-storage.h"
+
+#include <stdio.h>
+#include <dirent.h>
+
+/*
+ * Script sequence
+ */
+
+struct sieve_file_script_sequence {
+ struct sieve_script_sequence seq;
+ pool_t pool;
+
+ ARRAY_TYPE(const_string) script_files;
+ unsigned int index;
+
+ bool storage_is_file:1;
+};
+
+static int sieve_file_script_sequence_read_dir
+(struct sieve_file_script_sequence *fseq, const char *path)
+{
+ struct sieve_storage *storage = fseq->seq.storage;
+ DIR *dirp;
+ int ret = 0;
+
+ /* Open the directory */
+ if ( (dirp = opendir(path)) == NULL ) {
+ switch ( errno ) {
+ case ENOENT:
+ sieve_storage_set_error(storage,
+ SIEVE_ERROR_NOT_FOUND,
+ "Script sequence location not found");
+ break;
+ case EACCES:
+ sieve_storage_set_error(storage,
+ SIEVE_ERROR_NO_PERMISSION,
+ "Script sequence location not accessible");
+ e_error(storage->event,
+ "Failed to open sieve sequence: %s",
+ eacces_error_get("stat", path));
+ break;
+ default:
+ sieve_storage_set_critical(storage,
+ "Failed to open sieve sequence: "
+ "opendir(%s) failed: %m", path);
+ break;
+ }
+ return -1;
+ }
+
+ /* Read and sort script files */
+ for (;;) {
+ const char *const *files;
+ unsigned int count, i;
+ const char *file;
+ struct dirent *dp;
+ struct stat st;
+
+ errno = 0;
+ if ( (dp=readdir(dirp)) == NULL )
+ break;
+
+ if ( !sieve_script_file_has_extension(dp->d_name) )
+ continue;
+
+ file = NULL;
+ T_BEGIN {
+ if ( path[strlen(path)-1] == '/' )
+ file = t_strconcat(path, dp->d_name, NULL);
+ else
+ file = t_strconcat(path, "/", dp->d_name, NULL);
+
+ if ( stat(file, &st) == 0 && S_ISREG(st.st_mode) )
+ file = p_strdup(fseq->pool, dp->d_name);
+ else
+ file = NULL;
+ } T_END;
+
+ if (file == NULL)
+ continue;
+
+ /* Insert into sorted array */
+ files = array_get(&fseq->script_files, &count);
+ for ( i = 0; i < count; i++ ) {
+ if ( strcmp(file, files[i]) < 0 )
+ break;
+ }
+
+ if ( i == count )
+ array_append(&fseq->script_files, &file, 1);
+ else
+ array_insert(&fseq->script_files, i, &file, 1);
+ }
+
+ if ( errno != 0 ) {
+ sieve_storage_set_critical(storage,
+ "Failed to read sequence directory: "
+ "readdir(%s) failed: %m", path);
+ ret = -1;
+ }
+
+ /* Close the directory */
+ if ( dirp != NULL && closedir(dirp) < 0 ) {
+ e_error(storage->event,
+ "Failed to close sequence directory: "
+ "closedir(%s) failed: %m", path);
+ }
+ return ret;
+}
+
+struct sieve_script_sequence *sieve_file_storage_get_script_sequence
+(struct sieve_storage *storage, enum sieve_error *error_r)
+{
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ struct sieve_file_script_sequence *fseq = NULL;
+ const char *name = storage->script_name;
+ const char *file;
+ pool_t pool;
+ struct stat st;
+
+ /* Specified path can either be a regular file or a directory */
+ if ( stat(fstorage->path, &st) != 0 ) {
+ switch ( errno ) {
+ case ENOENT:
+ sieve_storage_set_error(storage,
+ SIEVE_ERROR_NOT_FOUND,
+ "Script sequence location not found");
+ break;
+ case EACCES:
+ sieve_storage_set_error(storage,
+ SIEVE_ERROR_NO_PERMISSION,
+ "Script sequence location not accessible");
+ e_error(storage->event,
+ "Failed to open sieve sequence: %s",
+ eacces_error_get("stat", fstorage->path));
+ break;
+ default:
+ sieve_storage_set_critical(storage,
+ "Failed to open sieve sequence: "
+ "stat(%s) failed: %m", fstorage->path);
+ break;
+ }
+ *error_r = storage->error_code;
+ return NULL;
+ }
+
+ /* Create sequence object */
+ pool = pool_alloconly_create("sieve_file_script_sequence", 1024);
+ fseq = p_new(pool, struct sieve_file_script_sequence, 1);
+ fseq->pool = pool;
+ sieve_script_sequence_init(&fseq->seq, storage);
+
+ if ( S_ISDIR(st.st_mode) ) {
+ i_array_init(&fseq->script_files, 16);
+
+ /* Path is directory */
+ if (name == 0 || *name == '\0') {
+ /* Read all '.sieve' files in directory */
+ if (sieve_file_script_sequence_read_dir
+ (fseq, fstorage->path) < 0) {
+ *error_r = storage->error_code;
+ sieve_file_script_sequence_destroy(&fseq->seq);
+ return NULL;
+ }
+
+ } else {
+ /* Read specific script file */
+ file = sieve_script_file_from_name(name);
+ file = p_strdup(pool, file);
+ array_append(&fseq->script_files, &file, 1);
+ }
+
+ } else {
+ /* Path is a file
+ (apparently; we'll see about that once it is opened) */
+ fseq->storage_is_file = TRUE;
+ }
+
+ return &fseq->seq;
+}
+
+struct sieve_script *sieve_file_script_sequence_next
+(struct sieve_script_sequence *seq, enum sieve_error *error_r)
+{
+ struct sieve_file_script_sequence *fseq =
+ (struct sieve_file_script_sequence *)seq;
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)seq->storage;
+ struct sieve_file_script *fscript;
+ const char *const *files;
+ unsigned int count;
+
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_NONE;
+
+ fscript = NULL;
+ if ( fseq->storage_is_file ) {
+ if ( fseq->index++ < 1 )
+ fscript = sieve_file_script_open_from_name(fstorage, NULL);
+
+ } else {
+ files = array_get(&fseq->script_files, &count);
+
+ while ( fseq->index < count ) {
+ fscript = sieve_file_script_open_from_filename
+ (fstorage, files[fseq->index++], NULL);
+ if (fscript != NULL)
+ break;
+ if (seq->storage->error_code != SIEVE_ERROR_NOT_FOUND)
+ break;
+ sieve_storage_clear_error(seq->storage);
+ }
+ }
+
+ if (fscript == NULL ) {
+ if ( error_r != NULL )
+ *error_r = seq->storage->error_code;
+ return NULL;
+ }
+ return &fscript->script;
+}
+
+void sieve_file_script_sequence_destroy(struct sieve_script_sequence *seq)
+{
+ struct sieve_file_script_sequence *fseq =
+ (struct sieve_file_script_sequence *)seq;
+
+ if ( array_is_created(&fseq->script_files) )
+ array_free(&fseq->script_files);
+ pool_unref(&fseq->pool);
+}
diff --git a/pigeonhole/src/lib-sieve/storage/file/sieve-file-script.c b/pigeonhole/src/lib-sieve/storage/file/sieve-file-script.c
new file mode 100644
index 0000000..3c4ec60
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/file/sieve-file-script.c
@@ -0,0 +1,832 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "mempool.h"
+#include "path-util.h"
+#include "istream.h"
+#include "time-util.h"
+#include "eacces-error.h"
+
+#include "sieve-binary.h"
+#include "sieve-script-private.h"
+
+#include "sieve-file-storage.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+#include <fcntl.h>
+
+/*
+ * Filename to name/name to filename
+ */
+
+const char *sieve_script_file_get_scriptname(const char *filename)
+{
+ const char *ext;
+
+ /* Extract the script name */
+ ext = strrchr(filename, '.');
+ if ( ext == NULL || ext == filename ||
+ strcmp(ext, "."SIEVE_SCRIPT_FILEEXT) != 0 )
+ return NULL;
+
+ return t_strdup_until(filename, ext);
+}
+
+bool sieve_script_file_has_extension(const char *filename)
+{
+ return ( sieve_script_file_get_scriptname(filename) != NULL );
+}
+
+const char *sieve_script_file_from_name(const char *name)
+{
+ return t_strconcat(name, "."SIEVE_SCRIPT_FILEEXT, NULL);
+}
+
+/*
+ * Common error handling
+ */
+
+static void sieve_file_script_handle_error
+(struct sieve_file_script *fscript, const char *op, const char *path,
+ const char *name, enum sieve_error *error_r)
+{
+ struct sieve_script *script = &fscript->script;
+ const char *abspath, *error;
+
+ switch ( errno ) {
+ case ENOENT:
+ if (t_abspath(path, &abspath, &error) < 0) {
+ sieve_script_set_error(script,
+ SIEVE_ERROR_TEMP_FAILURE,
+ "t_abspath(%s) failed: %s",
+ path, error);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ break;
+ }
+ e_debug(script->event, "File `%s' not found", abspath);
+ sieve_script_set_error(script,
+ SIEVE_ERROR_NOT_FOUND,
+ "Sieve script `%s' not found", name);
+ *error_r = SIEVE_ERROR_NOT_FOUND;
+ break;
+ case EACCES:
+ sieve_script_set_critical(script,
+ "Failed to %s sieve script: %s",
+ op, eacces_error_get(op, path));
+ *error_r = SIEVE_ERROR_NO_PERMISSION;
+ break;
+ default:
+ sieve_script_set_critical(script,
+ "Failed to %s sieve script: %s(%s) failed: %m",
+ op, op, path);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ break;
+ }
+}
+
+/*
+ *
+ */
+
+static struct sieve_file_script *sieve_file_script_alloc(void)
+{
+ struct sieve_file_script *fscript;
+ pool_t pool;
+
+ pool = pool_alloconly_create("sieve_file_script", 2048);
+ fscript = p_new(pool, struct sieve_file_script, 1);
+ fscript->script = sieve_file_script;
+ fscript->script.pool = pool;
+
+ return fscript;
+}
+
+struct sieve_file_script *sieve_file_script_init_from_filename
+(struct sieve_file_storage *fstorage, const char *filename,
+ const char *scriptname)
+{
+ struct sieve_storage *storage = &fstorage->storage;
+ struct sieve_file_script *fscript = NULL;
+
+ /* Prevent initializing the active script link as a script when it
+ * resides in the sieve storage directory.
+ */
+ if ( scriptname != NULL && fstorage->link_path != NULL &&
+ *(fstorage->link_path) == '\0' ) {
+ if ( strcmp(filename, fstorage->active_fname) == 0 ) {
+ sieve_storage_set_error(storage,
+ SIEVE_ERROR_NOT_FOUND,
+ "Script `%s' does not exist.", scriptname);
+ return NULL;
+ }
+ }
+
+ fscript = sieve_file_script_alloc();
+ sieve_script_init
+ (&fscript->script, storage, &sieve_file_script,
+ sieve_file_storage_path_extend(fstorage, filename), scriptname);
+ fscript->filename = p_strdup(fscript->script.pool, filename);
+ return fscript;
+}
+
+struct sieve_file_script *sieve_file_script_open_from_filename
+(struct sieve_file_storage *fstorage, const char *filename,
+ const char *scriptname)
+{
+ struct sieve_file_script *fscript;
+ enum sieve_error error;
+
+ fscript = sieve_file_script_init_from_filename
+ (fstorage, filename, scriptname);
+ if ( fscript == NULL )
+ return NULL;
+
+ if ( sieve_script_open(&fscript->script, &error) < 0 ) {
+ struct sieve_script *script = &fscript->script;
+ sieve_script_unref(&script);
+ return NULL;
+ }
+
+ return fscript;
+}
+
+struct sieve_file_script *sieve_file_script_init_from_name
+(struct sieve_file_storage *fstorage, const char *name)
+{
+ struct sieve_storage *storage = &fstorage->storage;
+ struct sieve_file_script *fscript;
+
+ if (name != NULL && S_ISDIR(fstorage->st.st_mode)) {
+ return sieve_file_script_init_from_filename
+ (fstorage, sieve_script_file_from_name(name), name);
+ }
+
+ fscript = sieve_file_script_alloc();
+ sieve_script_init
+ (&fscript->script, storage, &sieve_file_script,
+ fstorage->active_path, name);
+ return fscript;
+}
+
+struct sieve_file_script *sieve_file_script_open_from_name
+(struct sieve_file_storage *fstorage, const char *name)
+{
+ struct sieve_file_script *fscript;
+ enum sieve_error error;
+
+ fscript = sieve_file_script_init_from_name(fstorage, name);
+ if ( fscript == NULL )
+ return NULL;
+
+ if ( sieve_script_open(&fscript->script, &error) < 0 ) {
+ struct sieve_script *script = &fscript->script;
+ sieve_script_unref(&script);
+ return NULL;
+ }
+
+ return fscript;
+}
+
+struct sieve_file_script *sieve_file_script_init_from_path
+(struct sieve_file_storage *fstorage, const char *path,
+ const char *scriptname, enum sieve_error *error_r)
+{
+ struct sieve_instance *svinst = fstorage->storage.svinst;
+ struct sieve_file_storage *fsubstorage;
+ struct sieve_file_script *fscript;
+ struct sieve_storage *substorage;
+ enum sieve_error error;
+
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_NONE;
+ else
+ error_r = &error;
+
+ fsubstorage = sieve_file_storage_init_from_path
+ (svinst, path, 0, error_r);
+ if (fsubstorage == NULL)
+ return NULL;
+ substorage = &fsubstorage->storage;
+
+ fscript = sieve_file_script_alloc();
+ sieve_script_init(&fscript->script,
+ substorage, &sieve_file_script, path, scriptname);
+ sieve_storage_unref(&substorage);
+
+ return fscript;
+}
+
+struct sieve_file_script *sieve_file_script_open_from_path
+(struct sieve_file_storage *fstorage, const char *path,
+ const char *scriptname, enum sieve_error *error_r)
+{
+ struct sieve_storage *storage = &fstorage->storage;
+ struct sieve_file_script *fscript;
+ enum sieve_error error;
+
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_NONE;
+ else
+ error_r = &error;
+
+ fscript = sieve_file_script_init_from_path
+ (fstorage, path, scriptname, error_r);
+ if (fscript == NULL) {
+ sieve_storage_set_error(storage,
+ *error_r, "Failed to open script");
+ return NULL;
+ }
+
+ if ( sieve_script_open(&fscript->script, error_r) < 0 ) {
+ struct sieve_script *script = &fscript->script;
+ const char *errormsg;
+
+ errormsg = sieve_script_get_last_error(&fscript->script, error_r);
+ sieve_storage_set_error(storage,
+ *error_r, "%s", errormsg);
+ sieve_script_unref(&script);
+ return NULL;
+ }
+
+ return fscript;
+}
+
+/*
+ * Open
+ */
+
+static int sieve_file_script_stat
+(const char *path, struct stat *st, struct stat *lnk_st)
+{
+ if ( lstat(path, st) < 0 )
+ return -1;
+
+ *lnk_st = *st;
+
+ if ( S_ISLNK(st->st_mode) && stat(path, st) < 0 )
+ return -1;
+
+ return 0;
+}
+
+static const char *
+path_split_filename(const char *path, const char **dirpath_r)
+{
+ const char *filename;
+
+ filename = strrchr(path, '/');
+ if ( filename == NULL ) {
+ *dirpath_r = "";
+ filename = path;
+ } else {
+ *dirpath_r = t_strdup_until(path, filename);
+ filename++;
+ }
+ return filename;
+}
+
+static int sieve_file_script_open
+(struct sieve_script *script, enum sieve_error *error_r)
+{
+ struct sieve_file_script *fscript =
+ (struct sieve_file_script *)script;
+ struct sieve_storage *storage = script->storage;
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ pool_t pool = script->pool;
+ const char *filename, *name, *path;
+ const char *dirpath, *basename, *binpath, *binprefix;
+ struct stat st, lnk_st;
+ bool success = TRUE;
+ int ret = 0;
+
+ filename = fscript->filename;
+ basename = NULL;
+ name = script->name;
+ st = fstorage->st;
+ lnk_st = fstorage->lnk_st;
+
+ if (name == NULL)
+ name = storage->script_name;
+
+ T_BEGIN {
+ if ( S_ISDIR(st.st_mode) ) {
+ /* Storage is a directory */
+ path = fstorage->path;
+
+ if ( (filename == NULL || *filename == '\0') &&
+ name != NULL && *name != '\0' ) {
+ /* Name is used to find actual filename */
+ filename = sieve_script_file_from_name(name);
+ basename = name;
+ }
+ if ( filename == NULL || *filename == '\0' ) {
+ sieve_script_set_critical(script,
+ "Sieve script file path '%s' is a directory.", path);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ success = FALSE;
+ } else {
+ /* Extend storage path with filename */
+ if (name == NULL) {
+ if ( basename == NULL &&
+ (basename=sieve_script_file_get_scriptname(filename)) == NULL )
+ basename = filename;
+ name = basename;
+ } else if (basename == NULL) {
+ basename = name;
+ }
+ dirpath = path;
+
+ path = sieve_file_storage_path_extend(fstorage, filename);
+ ret = sieve_file_script_stat(path, &st, &lnk_st);
+ }
+
+ } else {
+ /* Storage is a single file */
+ path = fstorage->active_path;
+
+ /* Extract filename from path */
+ filename = path_split_filename(path, &dirpath);
+
+ if ( (basename=sieve_script_file_get_scriptname(filename)) == NULL )
+ basename = filename;
+
+ if ( name == NULL )
+ name = basename;
+ }
+
+ if ( success ) {
+ if ( ret < 0 ) {
+ /* Make sure we have a script name for the error */
+ if ( name == NULL ) {
+ i_assert( basename != NULL );
+ name = basename;
+ }
+ sieve_file_script_handle_error
+ (fscript, "stat", path, name, error_r);
+ success = FALSE;
+
+ } else if ( !S_ISREG(st.st_mode) ) {
+ sieve_script_set_critical(script,
+ "Sieve script file '%s' is not a regular file.", path);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ success = FALSE;
+ }
+ }
+
+ if ( success ) {
+ const char *bpath, *bfile, *bprefix;
+
+ if ( storage->bin_dir != NULL ) {
+ bpath = storage->bin_dir;
+ bfile = sieve_binfile_from_name(name);
+ bprefix = name;
+
+ } else {
+ bpath = dirpath;
+ bfile = sieve_binfile_from_name(basename);
+ bprefix = basename;
+ }
+
+ if ( *bpath == '\0' ) {
+ binpath = bfile;
+ binprefix = bprefix;
+ } else if ( bpath[strlen(bpath)-1] == '/' ) {
+ binpath = t_strconcat(bpath, bfile, NULL);
+ binprefix = t_strconcat(bpath, bprefix, NULL);
+ } else {
+ binpath = t_strconcat(bpath, "/", bfile, NULL);
+ binprefix = t_strconcat(bpath, "/", bprefix, NULL);
+ }
+
+ fscript->st = st;
+ fscript->lnk_st = lnk_st;
+ fscript->path = p_strdup(pool, path);
+ fscript->filename = p_strdup(pool, filename);
+ fscript->dirpath = p_strdup(pool, dirpath);
+ fscript->binpath = p_strdup(pool, binpath);
+ fscript->binprefix = p_strdup(pool, binprefix);
+
+ fscript->script.location = fscript->path;
+
+ if ( fscript->script.name == NULL )
+ fscript->script.name = p_strdup(pool, basename);
+ }
+ } T_END;
+
+ return ( success ? 0 : -1 );
+}
+
+static int sieve_file_script_get_stream
+(struct sieve_script *script, struct istream **stream_r,
+ enum sieve_error *error_r)
+{
+ struct sieve_file_script *fscript = (struct sieve_file_script *)script;
+ struct stat st;
+ struct istream *result;
+ int fd;
+
+ if ( (fd=open(fscript->path, O_RDONLY)) < 0 ) {
+ sieve_file_script_handle_error
+ (fscript, "open", fscript->path, fscript->script.name, error_r);
+ return -1;
+ }
+
+ if ( fstat(fd, &st) != 0 ) {
+ sieve_script_set_critical(script,
+ "Failed to open sieve script: fstat(fd=%s) failed: %m",
+ fscript->path);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ result = NULL;
+ } else {
+ /* Re-check the file type just to be sure */
+ if ( !S_ISREG(st.st_mode) ) {
+ sieve_script_set_critical(script,
+ "Sieve script file `%s' is not a regular file", fscript->path);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ result = NULL;
+ } else {
+ result = i_stream_create_fd_autoclose(&fd, SIEVE_FILE_READ_BLOCK_SIZE);
+ fscript->st = fscript->lnk_st = st;
+ }
+ }
+
+ if ( result == NULL ) {
+ /* Something went wrong, close the fd */
+ if ( fd >= 0 && close(fd) != 0 ) {
+ e_error(script->event,
+ "Failed to close sieve script: "
+ "close(fd=%s) failed: %m", fscript->path);
+ }
+ return -1;
+ }
+
+ *stream_r = result;
+ return 0;
+}
+
+/*
+ * Binary
+ */
+
+static int sieve_file_script_binary_read_metadata
+(struct sieve_script *script, struct sieve_binary_block *sblock,
+ sieve_size_t *offset ATTR_UNUSED)
+{
+ struct sieve_file_script *fscript = (struct sieve_file_script *)script;
+ struct sieve_instance *svinst = script->storage->svinst;
+ struct sieve_binary *sbin = sieve_binary_block_get_binary(sblock);
+ const struct stat *sstat, *bstat;
+
+ bstat = sieve_binary_stat(sbin);
+ if ( fscript->st.st_mtime > fscript->lnk_st.st_mtime ||
+ (fscript->st.st_mtime == fscript->lnk_st.st_mtime &&
+ ST_MTIME_NSEC(fscript->st) >= ST_MTIME_NSEC(fscript->lnk_st)) ) {
+ sstat = &fscript->st;
+ } else {
+ sstat = &fscript->lnk_st;
+ }
+
+ if ( bstat->st_mtime < sstat->st_mtime ||
+ (bstat->st_mtime == sstat->st_mtime &&
+ ST_MTIME_NSEC(*bstat) <= ST_MTIME_NSEC(*sstat)) ) {
+ if ( svinst->debug ) {
+ e_debug(script->event,
+ "Sieve binary `%s' is not newer "
+ "than the Sieve script `%s' (%s.%lu <= %s.%lu)",
+ sieve_binary_path(sbin), sieve_script_location(script),
+ t_strflocaltime("%Y-%m-%d %H:%M:%S", bstat->st_mtime),
+ ST_MTIME_NSEC(*bstat),
+ t_strflocaltime("%Y-%m-%d %H:%M:%S", sstat->st_mtime),
+ ST_MTIME_NSEC(*sstat));
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct sieve_binary *sieve_file_script_binary_load
+(struct sieve_script *script, enum sieve_error *error_r)
+{
+ struct sieve_file_script *fscript = (struct sieve_file_script *)script;
+ struct sieve_instance *svinst = script->storage->svinst;
+
+ return sieve_binary_open(svinst, fscript->binpath, script, error_r);
+}
+
+static int sieve_file_script_binary_save
+(struct sieve_script *script, struct sieve_binary *sbin, bool update,
+ enum sieve_error *error_r)
+{
+ struct sieve_storage *storage = script->storage;
+ struct sieve_file_script *fscript = (struct sieve_file_script *)script;
+
+ if ( storage->bin_dir != NULL &&
+ sieve_storage_setup_bindir(storage, 0700) < 0 )
+ return -1;
+
+ return sieve_binary_save(sbin, fscript->binpath, update,
+ fscript->st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO), error_r);
+}
+
+static const char *sieve_file_script_binary_get_prefix
+(struct sieve_script *script)
+{
+ struct sieve_file_script *fscript = (struct sieve_file_script *)script;
+
+ return fscript->binprefix;
+}
+
+/*
+ * Management
+ */
+
+static int sieve_file_storage_script_is_active(struct sieve_script *script)
+{
+ struct sieve_file_script *fscript =
+ (struct sieve_file_script *) script;
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)script->storage;
+ const char *afile;
+ int ret = 0;
+
+ T_BEGIN {
+ ret = sieve_file_storage_active_script_get_file(fstorage, &afile);
+
+ if ( ret > 0 ) {
+ /* Is the requested script active? */
+ ret = ( strcmp(fscript->filename, afile) == 0 ? 1 : 0 );
+ }
+ } T_END;
+
+ return ret;
+}
+
+static int sieve_file_storage_script_delete(struct sieve_script *script)
+{
+ struct sieve_file_script *fscript =
+ (struct sieve_file_script *)script;
+ int ret = 0;
+
+ if ( sieve_file_storage_pre_modify(script->storage) < 0 )
+ return -1;
+
+ ret = unlink(fscript->path);
+ if ( ret < 0 ) {
+ if ( errno == ENOENT ) {
+ sieve_script_set_error(script,
+ SIEVE_ERROR_NOT_FOUND,
+ "Sieve script does not exist.");
+ } else {
+ sieve_script_set_critical(script,
+ "Performing unlink() failed on sieve file `%s': %m",
+ fscript->path);
+ }
+ }
+ return ret;
+}
+
+static int _sieve_file_storage_script_activate
+(struct sieve_file_script *fscript)
+{
+ struct sieve_script *script = &fscript->script;
+ struct sieve_storage *storage = script->storage;
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ struct stat st;
+ const char *link_path, *afile;
+ int activated = 0;
+ int ret;
+
+ /* Find out whether there is an active script, but recreate
+ * the symlink either way. This way, any possible error in the symlink
+ * resolves automatically. This step is only necessary to provide a
+ * proper return value indicating whether the script was already active.
+ */
+ ret = sieve_file_storage_active_script_get_file(fstorage, &afile);
+
+ /* Is the requested script already active? */
+ if ( ret <= 0 || strcmp(fscript->filename, afile) != 0 )
+ activated = 1;
+
+ i_assert( fstorage->link_path != NULL );
+
+ /* Check the scriptfile we are trying to activate */
+ if ( lstat(fscript->path, &st) != 0 ) {
+ sieve_script_set_critical(script,
+ "Failed to activate Sieve script: lstat(%s) failed: %m.",
+ fscript->path);
+ return -1;
+ }
+
+ /* Rescue a possible .dovecot.sieve regular file remaining from old
+ * installations.
+ */
+ if ( !sieve_file_storage_active_rescue_regular(fstorage) ) {
+ /* Rescue failed, manual intervention is necessary */
+ return -1;
+ }
+
+ /* Just try to create the symlink first */
+ link_path = t_strconcat
+ ( fstorage->link_path, fscript->filename, NULL );
+
+ ret = symlink(link_path, fstorage->active_path);
+ if ( ret < 0 ) {
+ if ( errno == EEXIST ) {
+ ret = sieve_file_storage_active_replace_link(fstorage, link_path);
+ if ( ret < 0 ) {
+ return ret;
+ }
+ } else {
+ /* Other error, critical */
+ sieve_script_set_critical(script,
+ "Failed to activate Sieve script: "
+ "symlink(%s, %s) failed: %m",
+ link_path, fstorage->active_path);
+ return -1;
+ }
+ }
+ return activated;
+}
+
+static int sieve_file_storage_script_activate
+(struct sieve_script *script)
+{
+ struct sieve_file_script *fscript =
+ (struct sieve_file_script *)script;
+ int ret;
+
+ if ( sieve_file_storage_pre_modify(script->storage) < 0 )
+ return -1;
+
+ T_BEGIN {
+ ret = _sieve_file_storage_script_activate(fscript);
+ } T_END;
+
+ return ret;
+}
+
+static int sieve_file_storage_script_rename
+(struct sieve_script *script, const char *newname)
+{
+ struct sieve_file_script *fscript =
+ (struct sieve_file_script *)script;
+ struct sieve_storage *storage = script->storage;
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ const char *newpath, *newfile, *link_path;
+ int ret = 0;
+
+ if ( sieve_file_storage_pre_modify(storage) < 0 )
+ return -1;
+
+ T_BEGIN {
+ newfile = sieve_script_file_from_name(newname);
+ newpath = t_strconcat( fstorage->path, "/", newfile, NULL );
+
+ /* The normal rename() system call overwrites the existing file without
+ * notice. Also, active scripts must not be disrupted by renaming a script.
+ * That is why we use a link(newpath) [activate newpath] unlink(oldpath)
+ */
+
+ /* Link to the new path */
+ ret = link(fscript->path, newpath);
+ if ( ret >= 0 ) {
+ /* Is the requested script active? */
+ if ( sieve_script_is_active(script) > 0 ) {
+ /* Active; make active link point to the new copy */
+ i_assert( fstorage->link_path != NULL );
+ link_path = t_strconcat
+ ( fstorage->link_path, newfile, NULL );
+
+ ret = sieve_file_storage_active_replace_link(fstorage, link_path);
+ }
+
+ if ( ret >= 0 ) {
+ /* If all is good, remove the old link */
+ if ( unlink(fscript->path) < 0 ) {
+ e_error(script->event,
+ "Failed to clean up after rename: "
+ "unlink(%s) failed: %m", fscript->path);
+ }
+
+ if ( script->name != NULL && *script->name != '\0' )
+ script->name = p_strdup(script->pool, newname);
+ fscript->path = p_strdup(script->pool, newpath);
+ fscript->filename = p_strdup(script->pool, newfile);
+ } else {
+ /* If something went wrong, remove the new link to restore previous
+ * state
+ */
+ if ( unlink(newpath) < 0 ) {
+ e_error(script->event,
+ "Failed to clean up after failed rename: "
+ "unlink(%s) failed: %m", newpath);
+ }
+ }
+ } else {
+ /* Our efforts failed right away */
+ switch ( errno ) {
+ case ENOENT:
+ sieve_script_set_error(script, SIEVE_ERROR_NOT_FOUND,
+ "Sieve script does not exist.");
+ break;
+ case EEXIST:
+ sieve_script_set_error(script, SIEVE_ERROR_EXISTS,
+ "A sieve script with that name already exists.");
+ break;
+ default:
+ sieve_script_set_critical(script,
+ "Failed to rename Sieve script: "
+ "link(%s, %s) failed: %m", fscript->path, newpath);
+ }
+ }
+ } T_END;
+
+ return ret;
+}
+
+/*
+ * Properties
+ */
+
+static int sieve_file_script_get_size
+(const struct sieve_script *script, uoff_t *size_r)
+{
+ struct sieve_file_script *fscript = (struct sieve_file_script *)script;
+
+ *size_r = fscript->st.st_size;
+ return 1;
+}
+
+const char *sieve_file_script_get_dirpath
+(const struct sieve_script *script)
+{
+ struct sieve_file_script *fscript = (struct sieve_file_script *)script;
+
+ if ( script->driver_name != sieve_file_script.driver_name )
+ return NULL;
+
+ return fscript->dirpath;
+}
+
+const char *sieve_file_script_get_path
+(const struct sieve_script *script)
+{
+ struct sieve_file_script *fscript = (struct sieve_file_script *)script;
+
+ if ( script->driver_name != sieve_file_script.driver_name )
+ return NULL;
+
+ return fscript->path;
+}
+
+/*
+ * Matching
+ */
+
+static bool sieve_file_script_equals
+(const struct sieve_script *script, const struct sieve_script *other)
+{
+ struct sieve_file_script *fscript =
+ (struct sieve_file_script *)script;
+ struct sieve_file_script *fother =
+ (struct sieve_file_script *)other;
+
+ return ( CMP_DEV_T(fscript->st.st_dev, fother->st.st_dev) &&
+ fscript->st.st_ino == fother->st.st_ino );
+}
+
+/*
+ * Driver definition
+ */
+
+const struct sieve_script sieve_file_script = {
+ .driver_name = SIEVE_FILE_STORAGE_DRIVER_NAME,
+ .v = {
+ .open = sieve_file_script_open,
+
+ .get_stream = sieve_file_script_get_stream,
+
+ .binary_read_metadata = sieve_file_script_binary_read_metadata,
+ .binary_load = sieve_file_script_binary_load,
+ .binary_save = sieve_file_script_binary_save,
+ .binary_get_prefix = sieve_file_script_binary_get_prefix,
+
+ .rename = sieve_file_storage_script_rename,
+ .delete = sieve_file_storage_script_delete,
+ .is_active = sieve_file_storage_script_is_active,
+ .activate = sieve_file_storage_script_activate,
+
+ .get_size = sieve_file_script_get_size,
+
+ .equals = sieve_file_script_equals
+ }
+};
+
diff --git a/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage-active.c b/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage-active.c
new file mode 100644
index 0000000..28bc9eb
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage-active.c
@@ -0,0 +1,403 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "path-util.h"
+#include "ioloop.h"
+#include "hostpid.h"
+#include "file-copy.h"
+#include "time-util.h"
+
+#include "sieve-file-storage.h"
+
+#include <unistd.h>
+
+/*
+ * Symlink manipulation
+ */
+
+static int sieve_file_storage_active_read_link
+(struct sieve_file_storage *fstorage, const char **link_r)
+{
+ struct sieve_storage *storage = &fstorage->storage;
+ const char *error = NULL;
+ int ret;
+
+ ret = t_readlink(fstorage->active_path, link_r, &error);
+
+ if ( ret < 0 ) {
+ *link_r = NULL;
+
+ if ( errno == EINVAL ) {
+ /* Our symlink is no symlink. Report 'no active script'.
+ * Activating a script will automatically resolve this, so
+ * there is no need to panic on this one.
+ */
+ if ( (storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0 &&
+ (storage->flags & SIEVE_STORAGE_FLAG_SYNCHRONIZING) == 0 ) {
+ e_warning(storage->event,
+ "Active sieve script symlink %s is no symlink.",
+ fstorage->active_path);
+ }
+ return 0;
+ }
+
+ if ( errno == ENOENT ) {
+ /* Symlink not found */
+ return 0;
+ }
+
+ /* We do need to panic otherwise */
+ sieve_storage_set_critical(storage,
+ "Performing t_readlink() on active sieve symlink '%s' failed: %s",
+ fstorage->active_path, error);
+ return -1;
+ }
+
+ /* ret is now assured to be valid, i.e. > 0 */
+ return 1;
+}
+
+static const char *sieve_file_storage_active_parse_link
+(struct sieve_file_storage *fstorage, const char *link,
+ const char **scriptname_r)
+{
+ struct sieve_storage *storage = &fstorage->storage;
+ const char *fname, *scriptname, *scriptpath, *link_dir;
+
+ /* Split off directory from link path */
+ fname = strrchr(fstorage->active_path, '/');
+ if (fname == NULL)
+ link_dir = "";
+ else
+ link_dir = t_strdup_until(fstorage->active_path, fname+1);
+
+ /* Split link into path and filename */
+ fname = strrchr(link, '/');
+ if ( fname != NULL ) {
+ scriptpath = t_strdup_until(link, fname+1);
+ fname++;
+ } else {
+ scriptpath = "";
+ fname = link;
+ }
+
+ /* Check the script name */
+ scriptname = sieve_script_file_get_scriptname(fname);
+
+ /* Warn if link is deemed to be invalid */
+ if ( scriptname == NULL ) {
+ e_warning(storage->event,
+ "Active Sieve script symlink %s is broken: "
+ "Invalid scriptname (points to %s).",
+ fstorage->active_path, link);
+ return NULL;
+ }
+
+ /* Check whether the path is any good */
+ const char *error = NULL;
+ if ( t_normpath_to(scriptpath, link_dir, &scriptpath, &error) < 0 ) {
+ e_warning(storage->event,
+ "Failed to check active Sieve script symlink %s: "
+ "Failed to normalize path (points to %s): %s",
+ fstorage->active_path, scriptpath, error);
+ return NULL;
+ }
+ if ( strcmp(scriptpath, fstorage->path) != 0 ) {
+ e_warning(storage->event,
+ "Active sieve script symlink %s is broken: "
+ "Invalid/unknown path to storage (points to %s).",
+ fstorage->active_path, scriptpath);
+ return NULL;
+ }
+
+ if ( scriptname_r != NULL )
+ *scriptname_r = scriptname;
+
+ return fname;
+}
+
+int sieve_file_storage_active_replace_link
+(struct sieve_file_storage *fstorage, const char *link_path)
+{
+ struct sieve_storage *storage = &fstorage->storage;
+ const char *active_path_new;
+ struct timeval *tv, tv_now;
+ int ret = 0;
+
+ tv = &ioloop_timeval;
+
+ for (;;) {
+ /* First the new symlink is created with a different filename */
+ active_path_new = t_strdup_printf
+ ("%s-new.%s.P%sM%s.%s",
+ fstorage->active_path,
+ dec2str(tv->tv_sec), my_pid,
+ dec2str(tv->tv_usec), my_hostname);
+
+ ret = symlink(link_path, active_path_new);
+
+ if ( ret < 0 ) {
+ /* If link exists we try again later */
+ if ( errno == EEXIST ) {
+ /* Wait and try again - very unlikely */
+ sleep(2);
+ tv = &tv_now;
+ i_gettimeofday(&tv_now);
+ continue;
+ }
+
+ /* Other error, critical */
+ sieve_storage_set_critical(storage,
+ "Creating symlink() %s to %s failed: %m",
+ active_path_new, link_path);
+ return -1;
+ }
+
+ /* Link created */
+ break;
+ }
+
+ /* Replace the existing link. This activates the new script */
+ ret = rename(active_path_new, fstorage->active_path);
+
+ if ( ret < 0 ) {
+ /* Failed; created symlink must be deleted */
+ i_unlink(active_path_new);
+ sieve_storage_set_critical(storage,
+ "Performing rename() %s to %s failed: %m",
+ active_path_new, fstorage->active_path);
+ return -1;
+ }
+
+ return 1;
+}
+
+/*
+ * Active script properties
+ */
+
+int sieve_file_storage_active_script_get_file
+(struct sieve_file_storage *fstorage, const char **file_r)
+{
+ const char *link, *scriptfile;
+ int ret;
+
+ *file_r = NULL;
+
+ /* Read the active link */
+ if ( (ret=sieve_file_storage_active_read_link(fstorage, &link)) <= 0 )
+ return ret;
+
+ /* Parse the link */
+ scriptfile = sieve_file_storage_active_parse_link(fstorage, link, NULL);
+
+ if (scriptfile == NULL) {
+ /* Obviously, someone has been playing with our symlink:
+ * ignore this situation and report 'no active script'.
+ * Activation should fix this situation.
+ */
+ return 0;
+ }
+
+ *file_r = scriptfile;
+ return 1;
+}
+
+int sieve_file_storage_active_script_get_name
+(struct sieve_storage *storage, const char **name_r)
+{
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ const char *link;
+ int ret;
+
+ *name_r = NULL;
+
+ /* Read the active link */
+ if ( (ret=sieve_file_storage_active_read_link
+ (fstorage, &link)) <= 0 )
+ return ret;
+
+ if ( sieve_file_storage_active_parse_link
+ (fstorage, link, name_r) == NULL ) {
+ /* Obviously, someone has been playing with our symlink:
+ * ignore this situation and report 'no active script'.
+ * Activation should fix this situation.
+ */
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Active script
+ */
+
+struct sieve_script *sieve_file_storage_active_script_open
+(struct sieve_storage *storage)
+{
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ struct sieve_file_script *fscript;
+ const char *scriptfile, *link;
+ int ret;
+
+ sieve_storage_clear_error(storage);
+
+ /* Read the active link */
+ if ( (ret=sieve_file_storage_active_read_link(fstorage, &link)) <= 0 ) {
+ if ( ret < 0 )
+ return NULL;
+
+ /* Try to open the active_path as a regular file */
+ if ( S_ISDIR(fstorage->st.st_mode) ) {
+ fscript = sieve_file_script_open_from_path(fstorage,
+ fstorage->active_path, NULL, NULL);
+ } else {
+ fscript = sieve_file_script_open_from_name(fstorage, NULL);
+ }
+ if ( fscript == NULL ) {
+ if ( storage->error_code != SIEVE_ERROR_NOT_FOUND ) {
+ sieve_storage_set_critical(storage,
+ "Failed to open active path `%s' as regular file: %s",
+ fstorage->active_path, storage->error);
+ }
+ return NULL;
+ }
+
+ return &fscript->script;
+ }
+
+ /* Parse the link */
+ scriptfile = sieve_file_storage_active_parse_link(fstorage, link, NULL);
+ if (scriptfile == NULL) {
+ /* Obviously someone has been playing with our symlink,
+ * ignore this situation and report 'no active script'.
+ * Activation should fix this situation.
+ */
+ sieve_storage_set_error(storage, SIEVE_ERROR_NOT_FOUND,
+ "Active script is invalid");
+ return NULL;
+ }
+
+ fscript = sieve_file_script_open_from_path(fstorage,
+ fstorage->active_path,
+ sieve_script_file_get_scriptname(scriptfile),
+ NULL);
+ if ( fscript == NULL && storage->error_code == SIEVE_ERROR_NOT_FOUND ) {
+ e_warning(storage->event,
+ "Active sieve script symlink %s points to non-existent script "
+ "(points to %s).", fstorage->active_path, link);
+ }
+ return (fscript != NULL ? &fscript->script : NULL);
+}
+
+int sieve_file_storage_active_script_get_last_change
+(struct sieve_storage *storage, time_t *last_change_r)
+{
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ struct stat st;
+
+ /* Try direct lstat first */
+ if ( lstat(fstorage->active_path, &st) == 0 ) {
+ if ( !S_ISLNK(st.st_mode) ) {
+ *last_change_r = st.st_mtime;
+ return 0;
+ }
+ }
+ /* Check error */
+ else if ( errno != ENOENT ) {
+ sieve_storage_set_critical(storage,
+ "lstat(%s) failed: %m", fstorage->active_path);
+ }
+
+ /* Fall back to statting storage directory */
+ return sieve_storage_get_last_change(storage, last_change_r);
+}
+
+bool sieve_file_storage_active_rescue_regular
+(struct sieve_file_storage *fstorage)
+{
+ struct sieve_storage *storage = &fstorage->storage;
+ struct stat st;
+
+ /* Stat the file */
+ if ( lstat(fstorage->active_path, &st) != 0 ) {
+ if ( errno != ENOENT ) {
+ sieve_storage_set_critical(storage,
+ "Failed to stat active sieve script symlink (%s): %m.",
+ fstorage->active_path);
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ if ( S_ISLNK( st.st_mode ) ) {
+ e_debug(storage->event,
+ "Nothing to rescue %s.", fstorage->active_path);
+ return TRUE; /* Nothing to rescue */
+ }
+
+ /* Only regular files can be rescued */
+ if ( S_ISREG( st.st_mode ) ) {
+ const char *dstpath;
+ bool result = TRUE;
+
+ T_BEGIN {
+
+ dstpath = t_strconcat( fstorage->path, "/",
+ sieve_script_file_from_name("dovecot.orig"), NULL );
+ if ( file_copy(fstorage->active_path, dstpath, TRUE) < 1 ) {
+ sieve_storage_set_critical(storage,
+ "Active sieve script file '%s' is a regular file "
+ "and copying it to the script storage as '%s' failed. "
+ "This needs to be fixed manually.",
+ fstorage->active_path, dstpath);
+ result = FALSE;
+ } else {
+ e_info(storage->event,
+ "Moved active sieve script file '%s' "
+ "to script storage as '%s'.",
+ fstorage->active_path, dstpath);
+ }
+ } T_END;
+
+ return result;
+ }
+
+ sieve_storage_set_critical(storage,
+ "Active sieve script file '%s' is no symlink nor a regular file. "
+ "This needs to be fixed manually.", fstorage->active_path);
+ return FALSE;
+}
+
+int sieve_file_storage_deactivate(struct sieve_storage *storage)
+{
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ int ret;
+
+ if ( sieve_file_storage_pre_modify(storage) < 0 )
+ return -1;
+
+ if ( !sieve_file_storage_active_rescue_regular(fstorage) )
+ return -1;
+
+ /* Delete the symlink, so no script is active */
+ ret = unlink(fstorage->active_path);
+
+ if ( ret < 0 ) {
+ if ( errno != ENOENT ) {
+ sieve_storage_set_critical(storage,
+ "Failed to deactivate Sieve: "
+ "unlink(%s) failed: %m", fstorage->active_path);
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+ return 1;
+}
diff --git a/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage-list.c b/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage-list.c
new file mode 100644
index 0000000..75a34c9
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage-list.c
@@ -0,0 +1,140 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "eacces-error.h"
+
+#include "sieve-common.h"
+#include "sieve-script-private.h"
+
+#include "sieve-file-storage.h"
+
+#include <stdio.h>
+#include <dirent.h>
+
+struct sieve_file_list_context {
+ struct sieve_storage_list_context context;
+ pool_t pool;
+
+ const char *active;
+ const char *dir;
+ DIR *dirp;
+};
+
+struct sieve_storage_list_context *sieve_file_storage_list_init
+(struct sieve_storage *storage)
+{
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ struct sieve_file_list_context *flctx;
+ const char *active = NULL;
+ pool_t pool;
+ DIR *dirp;
+
+ /* Open the directory */
+ if ( (dirp = opendir(fstorage->path)) == NULL ) {
+ switch ( errno ) {
+ case ENOENT:
+ sieve_storage_set_error(storage,
+ SIEVE_ERROR_NOT_FOUND,
+ "Script storage not found");
+ break;
+ case EACCES:
+ sieve_storage_set_error(storage,
+ SIEVE_ERROR_NO_PERMISSION,
+ "Script storage not accessible");
+ e_error(storage->event, "Failed to list scripts: %s",
+ eacces_error_get("opendir", fstorage->path));
+ break;
+ default:
+ sieve_storage_set_critical(storage,
+ "Failed to list scripts: "
+ "opendir(%s) failed: %m", fstorage->path);
+ break;
+ }
+ return NULL;
+ }
+
+ T_BEGIN {
+ /* Get the name of the active script */
+ if ( sieve_file_storage_active_script_get_file(fstorage, &active) < 0) {
+ flctx = NULL;
+ } else {
+ pool = pool_alloconly_create("sieve_file_list_context", 1024);
+ flctx = p_new(pool, struct sieve_file_list_context, 1);
+ flctx->pool = pool;
+ flctx->dirp = dirp;
+ flctx->active = ( active != NULL ? p_strdup(pool, active) : NULL );
+ }
+ } T_END;
+
+ if ( flctx == NULL ) {
+ if ( closedir(dirp) < 0) {
+ e_error(storage->event,
+ "closedir(%s) failed: %m", fstorage->path);
+ }
+ return NULL;
+ }
+ return &flctx->context;
+}
+
+const char *sieve_file_storage_list_next
+(struct sieve_storage_list_context *ctx, bool *active)
+{
+ struct sieve_file_list_context *flctx =
+ (struct sieve_file_list_context *)ctx;
+ const struct sieve_file_storage *fstorage =
+ (const struct sieve_file_storage *)ctx->storage;
+ struct dirent *dp;
+ const char *scriptname;
+
+ *active = FALSE;
+
+ for (;;) {
+ if ( (dp = readdir(flctx->dirp)) == NULL )
+ return NULL;
+
+ scriptname = sieve_script_file_get_scriptname(dp->d_name);
+ if (scriptname != NULL ) {
+ /* Don't list our active sieve script link if the link
+ * resides in the script dir (generally a bad idea).
+ */
+ i_assert( fstorage->link_path != NULL );
+ if ( *(fstorage->link_path) == '\0' &&
+ strcmp(fstorage->active_fname, dp->d_name) == 0 )
+ continue;
+
+ break;
+ }
+ }
+
+ if ( flctx->active != NULL && strcmp(dp->d_name, flctx->active) == 0 ) {
+ *active = TRUE;
+ flctx->active = NULL;
+ }
+
+ return scriptname;
+}
+
+int sieve_file_storage_list_deinit(struct sieve_storage_list_context *lctx)
+{
+ struct sieve_file_list_context *flctx =
+ (struct sieve_file_list_context *)lctx;
+ const struct sieve_file_storage *fstorage =
+ (const struct sieve_file_storage *)lctx->storage;
+
+ if (closedir(flctx->dirp) < 0) {
+ e_error(lctx->storage->event,
+ "closedir(%s) failed: %m", fstorage->path);
+ }
+
+ pool_unref(&flctx->pool);
+
+ // FIXME: return error here if something went wrong during listing
+ return 0;
+}
+
+
+
+
diff --git a/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage-quota.c b/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage-quota.c
new file mode 100644
index 0000000..65e075d
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage-quota.c
@@ -0,0 +1,120 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve.h"
+#include "sieve-script.h"
+
+#include "sieve-file-storage.h"
+
+#include <stdio.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int sieve_file_storage_quota_havespace
+(struct sieve_storage *storage, const char *scriptname, size_t size,
+ enum sieve_storage_quota *quota_r, uint64_t *limit_r)
+{
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ struct dirent *dp;
+ DIR *dirp;
+ uint64_t script_count = 1;
+ uint64_t script_storage = size;
+ int result = 1;
+
+ /* Open the directory */
+ if ( (dirp = opendir(fstorage->path)) == NULL ) {
+ sieve_storage_set_critical(storage,
+ "quota: opendir(%s) failed: %m", fstorage->path);
+ return -1;
+ }
+
+ /* Scan all files */
+ for (;;) {
+ const char *name;
+ bool replaced = FALSE;
+
+ /* Read next entry */
+ errno = 0;
+ if ( (dp = readdir(dirp)) == NULL ) {
+ if ( errno != 0 ) {
+ sieve_storage_set_critical(storage,
+ "quota: readdir(%s) failed: %m", fstorage->path);
+ result = -1;
+ }
+ break;
+ }
+
+ /* Parse filename */
+ name = sieve_script_file_get_scriptname(dp->d_name);
+
+ /* Ignore non-script files */
+ if ( name == NULL )
+ continue;
+
+ /* Don't list our active sieve script link if the link
+ * resides in the script dir (generally a bad idea).
+ */
+ i_assert( fstorage->link_path != NULL );
+ if ( *(fstorage->link_path) == '\0' &&
+ strcmp(fstorage->active_fname, dp->d_name) == 0 )
+ continue;
+
+ if ( strcmp(name, scriptname) == 0 )
+ replaced = TRUE;
+
+ /* Check count quota if necessary */
+ if ( storage->max_scripts > 0 ) {
+ if ( !replaced ) {
+ script_count++;
+
+ if ( script_count > storage->max_scripts ) {
+ *quota_r = SIEVE_STORAGE_QUOTA_MAXSCRIPTS;
+ *limit_r = storage->max_scripts;
+ result = 0;
+ break;
+ }
+ }
+ }
+
+ /* Check storage quota if necessary */
+ if ( storage->max_storage > 0 ) {
+ const char *path;
+ struct stat st;
+
+ path = t_strconcat(fstorage->path, "/", dp->d_name, NULL);
+
+ if ( stat(path, &st) < 0 ) {
+ e_warning(storage->event,
+ "quota: stat(%s) failed: %m", path);
+ continue;
+ }
+
+ if ( !replaced ) {
+ script_storage += st.st_size;
+
+ if ( script_storage > storage->max_storage ) {
+ *quota_r = SIEVE_STORAGE_QUOTA_MAXSTORAGE;
+ *limit_r = storage->max_storage;
+ result = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Close directory */
+ if ( closedir(dirp) < 0 ) {
+ sieve_storage_set_critical(storage,
+ "quota: closedir(%s) failed: %m", fstorage->path);
+ }
+ return result;
+}
+
+
+
+
diff --git a/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage-save.c b/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage-save.c
new file mode 100644
index 0000000..bfbe380
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage-save.c
@@ -0,0 +1,544 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "hostpid.h"
+#include "ioloop.h"
+#include "array.h"
+#include "buffer.h"
+#include "istream.h"
+#include "ostream.h"
+#include "str.h"
+#include "eacces-error.h"
+#include "safe-mkstemp.h"
+
+#include "sieve-file-storage.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utime.h>
+
+struct sieve_file_save_context {
+ struct sieve_storage_save_context context;
+
+ pool_t pool;
+
+ struct ostream *output;
+ int fd;
+ const char *tmp_path;
+
+ time_t mtime;
+
+ bool failed:1;
+ bool finished:1;
+};
+
+static const char *sieve_generate_tmp_filename(const char *scriptname)
+{
+ static struct timeval last_tv = { 0, 0 };
+ struct timeval tv;
+
+ /* use secs + usecs to guarantee uniqueness within this process. */
+ if (ioloop_timeval.tv_sec > last_tv.tv_sec ||
+ (ioloop_timeval.tv_sec == last_tv.tv_sec &&
+ ioloop_timeval.tv_usec > last_tv.tv_usec)) {
+ tv = ioloop_timeval;
+ } else {
+ tv = last_tv;
+ if (++tv.tv_usec == 1000000) {
+ tv.tv_sec++;
+ tv.tv_usec = 0;
+ }
+ }
+ last_tv = tv;
+
+ if ( scriptname == NULL ) {
+ return t_strdup_printf("%s.M%sP%s.%s.tmp",
+ dec2str(tv.tv_sec), dec2str(tv.tv_usec),
+ my_pid, my_hostname);
+ }
+
+ scriptname = t_strdup_printf("%s_%s.M%sP%s.%s",
+ scriptname, dec2str(tv.tv_sec), dec2str(tv.tv_usec),
+ my_pid, my_hostname);
+ return sieve_script_file_from_name(scriptname);
+}
+
+static int sieve_file_storage_create_tmp
+(struct sieve_file_storage *fstorage, const char *scriptname,
+ const char **fpath_r)
+{
+ struct sieve_storage *storage = &fstorage->storage;
+ struct stat st;
+ unsigned int prefix_len;
+ const char *tmp_fname = NULL;
+ string_t *path;
+ int fd;
+
+ path = t_str_new(256);
+ str_append(path, fstorage->path);
+ str_append(path, "/tmp/");
+ prefix_len = str_len(path);
+
+ for (;;) {
+ tmp_fname = sieve_generate_tmp_filename(scriptname);
+ str_truncate(path, prefix_len);
+ str_append(path, tmp_fname);
+
+ /* stat() first to see if it exists. pretty much the only
+ possibility of that happening is if time had moved
+ backwards, but even then it's highly unlikely. */
+ if (stat(str_c(path), &st) == 0) {
+ /* try another file name */
+ } else if (errno != ENOENT) {
+ switch ( errno ) {
+ case EACCES:
+ sieve_storage_set_critical(storage, "save: %s",
+ eacces_error_get("stat", fstorage->path));
+ break;
+ default:
+ sieve_storage_set_critical(storage, "save: "
+ "stat(%s) failed: %m", str_c(path));
+ break;
+ }
+ return -1;
+ } else {
+ /* doesn't exist */
+ mode_t old_mask = umask(0777 & ~(fstorage->file_create_mode));
+ fd = open(str_c(path),
+ O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0777);
+ umask(old_mask);
+
+ if (fd != -1 || errno != EEXIST)
+ break;
+ /* race condition between stat() and open().
+ highly unlikely. */
+ }
+ }
+
+ *fpath_r = str_c(path);
+ if (fd == -1) {
+ if (ENOQUOTA(errno)) {
+ sieve_storage_set_error(storage,
+ SIEVE_ERROR_NO_QUOTA,
+ "Not enough disk quota");
+ } else {
+ switch ( errno ) {
+ case EACCES:
+ sieve_storage_set_critical(storage, "save: %s",
+ eacces_error_get("open", fstorage->path));
+ break;
+ default:
+ sieve_storage_set_critical(storage, "save: "
+ "open(%s) failed: %m", str_c(path));
+ break;
+ }
+ }
+ }
+
+ return fd;
+}
+
+static int sieve_file_storage_script_move
+(struct sieve_file_save_context *fsctx, const char *dst)
+{
+ struct sieve_storage_save_context *sctx = &fsctx->context;
+ struct sieve_storage *storage = sctx->storage;
+ int result = 0;
+
+ T_BEGIN {
+
+ /* Using rename() to ensure existing files are replaced
+ * without conflicts with other processes using the same
+ * file. The kernel wont fully delete the original until
+ * all processes have closed the file.
+ */
+ if (rename(fsctx->tmp_path, dst) == 0)
+ result = 0;
+ else {
+ result = -1;
+ if ( ENOQUOTA(errno) ) {
+ sieve_storage_set_error(storage,
+ SIEVE_ERROR_NO_QUOTA,
+ "Not enough disk quota");
+ } else if ( errno == EACCES ) {
+ sieve_storage_set_critical(storage, "save: "
+ "Failed to save Sieve script: "
+ "%s", eacces_error_get("rename", dst));
+ } else {
+ sieve_storage_set_critical(storage, "save: "
+ "rename(%s, %s) failed: %m", fsctx->tmp_path, dst);
+ }
+ }
+
+ /* Always destroy temp file */
+ if (unlink(fsctx->tmp_path) < 0 && errno != ENOENT) {
+ e_warning(storage->event, "save: "
+ "unlink(%s) failed: %m", fsctx->tmp_path);
+ }
+ } T_END;
+
+ return result;
+}
+
+struct sieve_storage_save_context *
+sieve_file_storage_save_alloc(struct sieve_storage *storage)
+{
+ struct sieve_file_save_context *fsctx;
+ pool_t pool;
+
+ pool = pool_alloconly_create("sieve_file_save_context", 1024);
+ fsctx = p_new(pool, struct sieve_file_save_context, 1);
+ fsctx->context.pool = pool;
+ fsctx->context.storage = storage;
+
+ return &fsctx->context;
+}
+
+int sieve_file_storage_save_init(struct sieve_storage_save_context *sctx,
+ const char *scriptname, struct istream *input)
+{
+ struct sieve_storage *storage = sctx->storage;
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ struct sieve_file_save_context *fsctx =
+ (struct sieve_file_save_context *)sctx;
+ pool_t pool = sctx->pool;
+ const char *path;
+ int fd, ret = 0;
+
+ if ( sieve_file_storage_pre_modify(storage) < 0 )
+ return -1;
+
+ if ( scriptname != NULL ) {
+ /* Prevent overwriting the active script link when it resides in the
+ * sieve storage directory.
+ */
+ i_assert( fstorage->link_path != NULL );
+ if ( *(fstorage->link_path) == '\0' ) {
+ const char *svext;
+ size_t namelen;
+
+ svext = strrchr(fstorage->active_fname, '.');
+ namelen = svext - fstorage->active_fname;
+ if ( svext != NULL && str_begins(svext+1, "sieve") &&
+ strlen(scriptname) == namelen &&
+ str_begins(fstorage->active_fname, scriptname) )
+ {
+ sieve_storage_set_error(storage,
+ SIEVE_ERROR_BAD_PARAMS,
+ "Script name `%s' is reserved for internal use.",
+ scriptname);
+ return -1;
+ }
+ }
+ }
+
+ T_BEGIN {
+ fd = sieve_file_storage_create_tmp(fstorage, scriptname, &path);
+ if (fd == -1) {
+ ret = -1;
+ } else {
+ fsctx->context.scriptname = p_strdup(pool, scriptname);
+ fsctx->context.input = input;
+ fsctx->fd = fd;
+ fsctx->output = o_stream_create_fd(fsctx->fd, 0);
+ fsctx->tmp_path = p_strdup(pool, path);
+ }
+ } T_END;
+
+ return ret;
+}
+
+int sieve_file_storage_save_continue
+(struct sieve_storage_save_context *sctx)
+{
+ struct sieve_file_save_context *fsctx =
+ (struct sieve_file_save_context *)sctx;
+
+ switch (o_stream_send_istream(fsctx->output, sctx->input)) {
+ case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
+ case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
+ return 0;
+ case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
+ i_unreached();
+ case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
+ sieve_storage_set_critical(sctx->storage,
+ "save: read(%s) failed: %s",
+ i_stream_get_name(sctx->input),
+ i_stream_get_error(sctx->input));
+ return -1;
+ case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
+ sieve_storage_set_critical(sctx->storage,
+ "save: write(%s) failed: %s", fsctx->tmp_path,
+ o_stream_get_error(fsctx->output));
+ return -1;
+ }
+ return 0;
+}
+
+int sieve_file_storage_save_finish
+(struct sieve_storage_save_context *sctx)
+{
+ struct sieve_file_save_context *fsctx =
+ (struct sieve_file_save_context *)sctx;
+ struct sieve_storage *storage = sctx->storage;
+ int output_errno;
+
+ if ( sctx->failed && fsctx->fd == -1 ) {
+ /* tmp file creation failed */
+ return -1;
+ }
+
+ T_BEGIN {
+ output_errno = fsctx->output->stream_errno;
+ o_stream_destroy(&fsctx->output);
+
+ if ( fsync(fsctx->fd) < 0 ) {
+ sieve_storage_set_critical(storage, "save: "
+ "fsync(%s) failed: %m", fsctx->tmp_path);
+ sctx->failed = TRUE;
+ }
+ if ( close(fsctx->fd) < 0 ) {
+ sieve_storage_set_critical(storage, "save: "
+ "close(%s) failed: %m", fsctx->tmp_path);
+ sctx->failed = TRUE;
+ }
+ fsctx->fd = -1;
+
+ if ( sctx->failed ) {
+ /* delete the tmp file */
+ if (unlink(fsctx->tmp_path) < 0 && errno != ENOENT) {
+ e_warning(storage->event, "save: "
+ "unlink(%s) failed: %m",
+ fsctx->tmp_path);
+ }
+
+ errno = output_errno;
+ if ( ENOQUOTA(errno) ) {
+ sieve_storage_set_error(storage,
+ SIEVE_ERROR_NO_QUOTA,
+ "Not enough disk quota");
+ } else if ( errno != 0 ) {
+ sieve_storage_set_critical(storage, "save: "
+ "write(%s) failed: %m", fsctx->tmp_path);
+ }
+ fsctx->tmp_path = NULL;
+ }
+ } T_END;
+
+ return ( sctx->failed ? -1 : 0 );
+}
+
+struct sieve_script *sieve_file_storage_save_get_tempscript
+(struct sieve_storage_save_context *sctx)
+{
+ struct sieve_file_save_context *fsctx =
+ (struct sieve_file_save_context *)sctx;
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)sctx->storage;
+ struct sieve_file_script *tmpscript;
+ enum sieve_error error;
+ const char *scriptname;
+
+ if (sctx->failed)
+ return NULL;
+
+ if ( sctx->scriptobject != NULL )
+ return sctx->scriptobject;
+
+ scriptname =
+ ( sctx->scriptname == NULL ? "" : sctx->scriptname );
+ tmpscript = sieve_file_script_open_from_path
+ (fstorage, fsctx->tmp_path, scriptname, &error);
+
+ if ( tmpscript == NULL ) {
+ if ( error == SIEVE_ERROR_NOT_FOUND ) {
+ sieve_storage_set_critical(sctx->storage, "save: "
+ "Temporary script file `%s' got lost, "
+ "which should not happen (possibly deleted externally).",
+ fsctx->tmp_path);
+ } else {
+ sieve_storage_set_critical(sctx->storage, "save: "
+ "Failed to open temporary script file `%s'",
+ fsctx->tmp_path);
+ }
+ return NULL;
+ }
+
+ return &tmpscript->script;
+}
+
+static void sieve_file_storage_update_mtime
+(struct sieve_storage *storage, const char *path, time_t mtime)
+{
+ struct utimbuf times = { .actime = mtime, .modtime = mtime };
+
+ if ( utime(path, &times) < 0 ) {
+ switch ( errno ) {
+ case ENOENT:
+ break;
+ case EACCES:
+ e_error(storage->event, "save: %s",
+ eacces_error_get("utime", path));
+ break;
+ default:
+ e_error(storage->event,
+ "save: utime(%s) failed: %m", path);
+ }
+ }
+}
+
+int sieve_file_storage_save_commit
+(struct sieve_storage_save_context *sctx)
+{
+ struct sieve_file_save_context *fsctx =
+ (struct sieve_file_save_context *)sctx;
+ struct sieve_storage *storage = sctx->storage;
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)sctx->storage;
+ const char *dest_path;
+ bool failed = FALSE;
+
+ i_assert(fsctx->output == NULL);
+
+ T_BEGIN {
+ dest_path = t_strconcat(fstorage->path, "/",
+ sieve_script_file_from_name(sctx->scriptname), NULL);
+
+ failed = ( sieve_file_storage_script_move(fsctx, dest_path) < 0 );
+ if ( sctx->mtime != (time_t)-1 )
+ sieve_file_storage_update_mtime(storage, dest_path, sctx->mtime);
+ } T_END;
+
+ return ( failed ? -1 : 0 );
+}
+
+void sieve_file_storage_save_cancel(struct sieve_storage_save_context *sctx)
+{
+ struct sieve_file_save_context *fsctx =
+ (struct sieve_file_save_context *)sctx;
+ struct sieve_storage *storage = sctx->storage;
+
+ if (fsctx->tmp_path != NULL &&
+ unlink(fsctx->tmp_path) < 0 && errno != ENOENT) {
+ e_warning(storage->event, "save: unlink(%s) failed: %m",
+ fsctx->tmp_path);
+ }
+
+ i_assert(fsctx->output == NULL);
+}
+
+static int
+sieve_file_storage_save_to(struct sieve_file_storage *fstorage,
+ string_t *temp_path, struct istream *input,
+ const char *target)
+{
+ struct sieve_storage *storage = &fstorage->storage;
+ struct ostream *output;
+ int fd;
+
+ // FIXME: move this to base class
+ // FIXME: use io_stream_temp
+
+ fd = safe_mkstemp_hostpid
+ (temp_path, fstorage->file_create_mode, (uid_t)-1, (gid_t)-1);
+ if ( fd < 0 ) {
+ if ( errno == EACCES ) {
+ sieve_storage_set_critical(storage,
+ "Failed to create temporary file: %s",
+ eacces_error_get_creating("open", str_c(temp_path)));
+ } else {
+ sieve_storage_set_critical(storage,
+ "Failed to create temporary file: open(%s) failed: %m",
+ str_c(temp_path));
+ }
+ return -1;
+ }
+
+ output = o_stream_create_fd(fd, 0);
+ switch ( o_stream_send_istream(output, input) ) {
+ case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
+ break;
+ case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
+ case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
+ i_unreached();
+ case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
+ sieve_storage_set_critical(storage,
+ "read(%s) failed: %s", i_stream_get_name(input),
+ i_stream_get_error(input));
+ o_stream_destroy(&output);
+ i_unlink(str_c(temp_path));
+ return -1;
+ case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
+ sieve_storage_set_critical(storage,
+ "write(%s) failed: %s", str_c(temp_path),
+ o_stream_get_error(output));
+ o_stream_destroy(&output);
+ i_unlink(str_c(temp_path));
+ return -1;
+ }
+ o_stream_destroy(&output);
+
+ if ( rename(str_c(temp_path), target) < 0 ) {
+ if ( ENOQUOTA(errno) ) {
+ sieve_storage_set_error(storage,
+ SIEVE_ERROR_NO_QUOTA,
+ "Not enough disk quota");
+ } else if ( errno == EACCES ) {
+ sieve_storage_set_critical(storage,
+ "%s", eacces_error_get("rename", target));
+ } else {
+ sieve_storage_set_critical(storage,
+ "rename(%s, %s) failed: %m",
+ str_c(temp_path), target);
+ }
+ i_unlink(str_c(temp_path));
+ }
+ return 0;
+}
+
+int sieve_file_storage_save_as
+(struct sieve_storage *storage, struct istream *input,
+ const char *name)
+{
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ string_t *temp_path;
+ const char *dest_path;
+
+ temp_path = t_str_new(256);
+ str_append(temp_path, fstorage->path);
+ str_append(temp_path, "/tmp/");
+ str_append(temp_path, sieve_script_file_from_name(name));
+ str_append_c(temp_path, '.');
+
+ dest_path = t_strconcat(fstorage->path, "/",
+ sieve_script_file_from_name(name), NULL);
+
+ return sieve_file_storage_save_to
+ (fstorage, temp_path, input, dest_path);
+}
+
+int sieve_file_storage_save_as_active
+(struct sieve_storage *storage, struct istream *input,
+ time_t mtime)
+{
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ string_t *temp_path;
+
+ temp_path = t_str_new(256);
+ str_append(temp_path, fstorage->active_path);
+ str_append_c(temp_path, '.');
+
+ if ( sieve_file_storage_save_to
+ (fstorage, temp_path, input, fstorage->active_path) < 0 )
+ return -1;
+
+ sieve_file_storage_update_mtime
+ (storage, fstorage->active_path, mtime);
+ return 0;
+}
+
diff --git a/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage.c b/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage.c
new file mode 100644
index 0000000..76b3ebf
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage.c
@@ -0,0 +1,918 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "path-util.h"
+#include "home-expand.h"
+#include "ioloop.h"
+#include "mkdir-parents.h"
+#include "eacces-error.h"
+#include "unlink-old-files.h"
+#include "mail-storage-private.h"
+
+#include "sieve.h"
+#include "sieve-common.h"
+#include "sieve-settings.h"
+#include "sieve-error-private.h"
+#include "sieve-settings.h"
+
+#include "sieve-file-storage.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <utime.h>
+#include <sys/time.h>
+
+
+#define MAX_DIR_CREATE_MODE 0770
+
+/*
+ * Utility
+ */
+
+const char *sieve_file_storage_path_extend
+(struct sieve_file_storage *fstorage, const char *filename)
+{
+ const char *path = fstorage->path;
+
+ if ( path[strlen(path)-1] == '/' )
+ return t_strconcat(path, filename, NULL);
+
+ return t_strconcat(path, "/", filename , NULL);
+}
+
+/*
+ *
+ */
+
+static int sieve_file_storage_stat
+(struct sieve_file_storage *fstorage, const char *path,
+ enum sieve_error *error_r)
+{
+ struct sieve_storage *storage = &fstorage->storage;
+ struct stat st;
+ const char *abspath, *error;
+
+ if ( lstat(path, &st) == 0 ) {
+ fstorage->lnk_st = st;
+
+ if ( !S_ISLNK(st.st_mode) || stat(path, &st) == 0 ) {
+ fstorage->st = st;
+ return 0;
+ }
+ }
+
+ switch ( errno ) {
+ case ENOENT:
+ if (t_abspath(path, &abspath, &error) < 0) {
+ sieve_storage_set_critical(storage,
+ "t_abspath(%s) failed: %s", path, error);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ break;
+ }
+ e_debug(storage->event, "Storage path `%s' not found", abspath);
+ sieve_storage_set_internal_error(storage); // should be overriden
+ *error_r = SIEVE_ERROR_NOT_FOUND;
+ break;
+ case EACCES:
+ sieve_storage_set_critical(storage,
+ "Failed to stat sieve storage path: %s",
+ eacces_error_get("stat", path));
+ *error_r = SIEVE_ERROR_NO_PERMISSION;
+ break;
+ default:
+ sieve_storage_set_critical(storage,
+ "Failed to stat sieve storage path: "
+ "stat(%s) failed: %m", path);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ break;
+ }
+
+ return -1;
+}
+
+static const char *sieve_storage_get_relative_link_path
+ (const char *active_path, const char *storage_dir)
+{
+ const char *link_path, *p;
+ size_t pathlen;
+
+ /* Determine to what extent the sieve storage and active script
+ * paths match up. This enables the managed symlink to be short and the
+ * sieve storages can be moved around without trouble (if the active
+ * script path is common to the script storage).
+ */
+ p = strrchr(active_path, '/');
+ if ( p == NULL ) {
+ link_path = storage_dir;
+ } else {
+ pathlen = p - active_path;
+
+ if ( strncmp( storage_dir, active_path, pathlen ) == 0 &&
+ (storage_dir[pathlen] == '/' || storage_dir[pathlen] == '\0') )
+ {
+ if ( storage_dir[pathlen] == '\0' )
+ link_path = "";
+ else
+ link_path = storage_dir + pathlen + 1;
+ } else
+ link_path = storage_dir;
+ }
+
+ /* Add trailing '/' when link path is not empty
+ */
+ pathlen = strlen(link_path);
+ if ( pathlen != 0 && link_path[pathlen-1] != '/')
+ return t_strconcat(link_path, "/", NULL);
+
+ return t_strdup(link_path);
+}
+
+static mode_t get_dir_mode(mode_t mode)
+{
+ /* Add the execute bit if either read or write bit is set */
+
+ if ((mode & 0600) != 0) mode |= 0100;
+ if ((mode & 0060) != 0) mode |= 0010;
+ if ((mode & 0006) != 0) mode |= 0001;
+
+ return mode;
+}
+
+static int mkdir_verify
+(struct sieve_storage *storage, const char *dir,
+ mode_t mode, gid_t gid, const char *gid_origin)
+{
+ struct stat st;
+
+ if ( stat(dir, &st) == 0 )
+ return 0;
+
+ if ( errno == EACCES ) {
+ e_error(storage->event, "mkdir_verify: %s",
+ eacces_error_get("stat", dir));
+ return -1;
+ } else if ( errno != ENOENT ) {
+ e_error(storage->event, "mkdir_verify: "
+ "stat(%s) failed: %m", dir);
+ return -1;
+ }
+
+ if ( mkdir_parents_chgrp(dir, mode, gid, gid_origin) == 0 ) {
+ e_debug(storage->event, "Created storage directory %s", dir);
+ return 0;
+ }
+
+ switch ( errno ) {
+ case EEXIST:
+ return 0;
+ case ENOENT:
+ e_error(storage->event,
+ "Storage was deleted while it was being created");
+ break;
+ case EACCES:
+ e_error(storage->event, "%s",
+ eacces_error_get_creating("mkdir_parents_chgrp", dir));
+ break;
+ default:
+ e_error(storage->event,
+ "mkdir_parents_chgrp(%s) failed: %m", dir);
+ break;
+ }
+
+ return -1;
+}
+
+static int check_tmp(struct sieve_storage *storage, const char *path)
+{
+ struct stat st;
+
+ /* If tmp/ directory exists, we need to clean it up once in a while */
+ if ( stat(path, &st) < 0 ) {
+ if ( errno == ENOENT )
+ return 0;
+ if ( errno == EACCES ) {
+ e_error(storage->event, "check_tmp: %s",
+ eacces_error_get("stat", path));
+ return -1;
+ }
+ e_error(storage->event, "check_tmp: stat(%s) failed: %m", path);
+ return -1;
+ }
+
+ if ( st.st_atime > st.st_ctime + SIEVE_FILE_STORAGE_TMP_DELETE_SECS ) {
+ /* The directory should be empty. we won't do anything
+ until ctime changes. */
+ } else if ( st.st_atime < ioloop_time - SIEVE_FILE_STORAGE_TMP_SCAN_SECS ) {
+ /* Time to scan */
+ (void)unlink_old_files(path, "",
+ ioloop_time - SIEVE_FILE_STORAGE_TMP_DELETE_SECS);
+ }
+ return 1;
+}
+
+static struct sieve_storage *sieve_file_storage_alloc(void)
+{
+ struct sieve_file_storage *fstorage;
+ pool_t pool;
+
+ pool = pool_alloconly_create("sieve_file_storage", 2048);
+ fstorage = p_new(pool, struct sieve_file_storage, 1);
+ fstorage->storage = sieve_file_storage;
+ fstorage->storage.pool = pool;
+
+ return &fstorage->storage;
+}
+
+static int sieve_file_storage_get_full_path
+(struct sieve_file_storage *fstorage, const char **storage_path,
+ enum sieve_error *error_r)
+{
+ struct sieve_storage *storage = &fstorage->storage;
+ struct sieve_instance *svinst = storage->svinst;
+ const char *path = *storage_path;
+
+ /* Get full storage path */
+
+ if ( path != NULL &&
+ ((path[0] == '~' && (path[1] == '/' || path[1] == '\0')) ||
+ (((svinst->flags & SIEVE_FLAG_HOME_RELATIVE) != 0 ) && path[0] != '/')) ) {
+ /* home-relative path. change to absolute. */
+ const char *home = sieve_environment_get_homedir(svinst);
+
+ if ( home != NULL ) {
+ if ( path[0] == '~' && (path[1] == '/' || path[1] == '\0') )
+ path = home_expand_tilde(path, home);
+ else
+ path = t_strconcat(home, "/", path, NULL);
+ } else {
+ sieve_storage_set_critical(storage,
+ "Sieve storage path `%s' is relative to home directory, "
+ "but home directory is not available.", path);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+ }
+ *storage_path = path;
+ return 0;
+}
+
+static int sieve_file_storage_get_full_active_path
+(struct sieve_file_storage *fstorage, const char **active_path,
+ enum sieve_error *error_r)
+{
+ struct sieve_storage *storage = &fstorage->storage;
+ struct sieve_instance *svinst = storage->svinst;
+ const char *path = *active_path;
+
+ if ( path != NULL && *path != '\0' &&
+ ((path[0] == '~' && (path[1] == '/' || path[1] == '\0')) ||
+ (((svinst->flags & SIEVE_FLAG_HOME_RELATIVE) != 0 ) && path[0] != '/'))
+ ) {
+ /* home-relative path. change to absolute. */
+ const char *home = sieve_environment_get_homedir(svinst);
+
+ if ( home != NULL ) {
+ if ( path[0] == '~' && (path[1] == '/' || path[1] == '\0') )
+ path = home_expand_tilde(path, home);
+ else
+ path = t_strconcat(home, "/", path, NULL);
+ } else {
+ sieve_storage_set_critical(storage,
+ "Sieve storage active script path `%s' is relative to home directory, "
+ "but home directory is not available.", path);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+ }
+ *active_path = path;
+ return 0;
+}
+
+static int sieve_file_storage_init_common
+(struct sieve_file_storage *fstorage, const char *active_path,
+ const char *storage_path, bool exists, enum sieve_error *error_r)
+ ATTR_NULL(2, 3)
+{
+ struct sieve_storage *storage = &fstorage->storage;
+ const char *tmp_dir, *link_path, *active_fname, *storage_dir, *error;
+ bool have_link = FALSE;
+ int ret;
+
+ i_assert( storage_path != NULL || active_path != NULL );
+
+ fstorage->prev_mtime = (time_t)-1;
+
+ /* Get active script path */
+
+ if ( sieve_file_storage_get_full_active_path
+ (fstorage, &active_path, error_r) < 0 )
+ return -1;
+
+ /* Get the filename for the active script link */
+
+ active_fname = NULL;
+ if ( active_path != NULL && *active_path != '\0' ) {
+ const char *active_dir;
+
+ active_fname = strrchr(active_path, '/');
+ if ( active_fname == NULL ) {
+ active_fname = active_path;
+ active_dir = "";
+ } else {
+ active_dir = t_strdup_until(active_path, active_fname);
+ active_fname++;
+ }
+
+ if ( *active_fname == '\0' ) {
+ /* Link cannot be just a path ending in '/' */
+ sieve_storage_set_critical(storage,
+ "Path to %sscript must include the filename (path=%s)",
+ ( storage_path != NULL ? "active link/" : "" ),
+ active_path);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+
+ if (t_realpath(active_dir, &active_dir, &error) < 0) {
+ if (errno != ENOENT) {
+ e_error(storage->event,
+ "Failed to normalize active script directory "
+ "(path=%s): %s", active_dir, error);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+ e_debug(storage->event,
+ "Failed to normalize active script directory "
+ "(path=%s): "
+ "Part of the path does not exist (yet)",
+ active_dir);
+ } else {
+ active_path = t_abspath_to(active_fname, active_dir);
+ }
+
+ e_debug(storage->event, "Using %sSieve script path: %s",
+ (storage_path != NULL ? "active " : ""), active_path);
+
+ fstorage->active_path = p_strdup(storage->pool, active_path);
+ fstorage->active_fname = p_strdup(storage->pool, active_fname);
+ }
+
+ /* Determine storage path */
+
+ storage_dir = storage_path;
+ if ( storage_path != NULL && *storage_path != '\0' ) {
+ e_debug(storage->event, "Using script storage path: %s",
+ storage_path);
+ have_link = TRUE;
+
+ } else {
+ if ((storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0 ) {
+ sieve_storage_set_critical(storage,
+ "Storage path cannot be empty for write access");
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+
+ storage_path = active_path;
+ }
+
+ i_assert(storage_path != NULL);
+
+ /* Prepare for write access */
+
+ if ( (storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0 ) {
+ mode_t dir_create_mode, file_create_mode;
+ gid_t file_create_gid;
+ const char *file_create_gid_origin;
+
+ /* Use safe permission defaults */
+ file_create_mode = 0600;
+ dir_create_mode = 0700;
+ file_create_gid = (gid_t)-1;
+ file_create_gid_origin = "defaults";
+
+ /* Get actual permissions */
+ if ( exists ) {
+ file_create_mode = (fstorage->st.st_mode & 0666) | 0600;
+ dir_create_mode = (fstorage->st.st_mode & 0777) | 0700;
+ file_create_gid_origin = storage_dir;
+
+ if ( !S_ISDIR(fstorage->st.st_mode) ) {
+ /* We're getting permissions from a file.
+ Apply +x modes as necessary. */
+ dir_create_mode = get_dir_mode(dir_create_mode);
+ }
+
+ if (S_ISDIR(fstorage->st.st_mode) &&
+ (fstorage->st.st_mode & S_ISGID) != 0) {
+ /* Directory's GID is used automatically for new files */
+ file_create_gid = (gid_t)-1;
+ } else if ((fstorage->st.st_mode & 0070) >> 3 ==
+ (fstorage->st.st_mode & 0007)) {
+ /* Group has same permissions as world, so don't bother changing it */
+ file_create_gid = (gid_t)-1;
+ } else if (getegid() == fstorage->st.st_gid) {
+ /* Using our own gid, no need to change it */
+ file_create_gid = (gid_t)-1;
+ } else {
+ file_create_gid = fstorage->st.st_gid;
+ }
+ }
+
+ e_debug(storage->event,
+ "Using permissions from %s: mode=0%o gid=%ld",
+ file_create_gid_origin, (int)dir_create_mode,
+ file_create_gid == (gid_t)-1 ?
+ -1L : (long)file_create_gid);
+
+ /*
+ * Ensure sieve local directory structure exists (full autocreate):
+ * This currently only consists of a ./tmp direcory
+ */
+
+ tmp_dir = t_strconcat(storage_path, "/tmp", NULL);
+
+ /* Try to find and clean up tmp dir */
+ if ( (ret=check_tmp(storage, tmp_dir)) < 0 ) {
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+
+ /* Auto-create if necessary */
+ if ( ret == 0 && mkdir_verify(storage, tmp_dir,
+ dir_create_mode, file_create_gid, file_create_gid_origin) < 0 ) {
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+
+ fstorage->dir_create_mode = dir_create_mode;
+ fstorage->file_create_mode = file_create_mode;
+ fstorage->file_create_gid = file_create_gid;
+ }
+
+ if ( !exists && sieve_file_storage_stat
+ (fstorage, storage_path, error_r) < 0 )
+ return -1;
+
+ if ( have_link ) {
+ if ( t_realpath(storage_path, &storage_path, &error) < 0 ) {
+ e_error(storage->event,
+ "Failed to normalize storage path (path=%s): %s",
+ storage_path, error);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+ if ( active_path != NULL && *active_path != '\0' ) {
+ /* Get the path to be prefixed to the script name in the symlink
+ * pointing to the active script.
+ */
+ link_path = sieve_storage_get_relative_link_path
+ (fstorage->active_path, storage_path);
+
+ e_debug(storage->event,
+ "Relative path to sieve storage in active link: %s",
+ link_path);
+
+ fstorage->link_path = p_strdup(storage->pool, link_path);
+ }
+ }
+
+ fstorage->path = p_strdup(storage->pool, storage_path);
+ storage->location = fstorage->path;
+
+ return 0;
+}
+
+static int sieve_file_storage_init
+(struct sieve_storage *storage, const char *const *options,
+ enum sieve_error *error_r)
+{
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ const char *storage_path = storage->location;
+ const char *active_path = "";
+ bool exists = FALSE;
+
+ if ( options != NULL ) {
+ while ( *options != NULL ) {
+ const char *option = *options;
+
+ if ( strncasecmp(option, "active=", 7) == 0 && option[7] != '\0' ) {
+ active_path = option+7;
+ } else {
+ sieve_storage_set_critical(storage,
+ "Invalid option `%s'", option);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+
+ options++;
+ }
+ }
+
+ /* Get full storage path */
+
+ if ( sieve_file_storage_get_full_path
+ (fstorage, &storage_path, error_r) < 0 )
+ return -1;
+
+ /* Stat storage directory */
+
+ if ( storage_path != NULL && *storage_path != '\0' ) {
+ if ( sieve_file_storage_stat(fstorage, storage_path, error_r) < 0 ) {
+ if ( *error_r != SIEVE_ERROR_NOT_FOUND )
+ return -1;
+ if ( (storage->flags & SIEVE_STORAGE_FLAG_READWRITE) == 0 ) {
+ /* For backwards compatibility, recognize when storage directory
+ does not exist while active script exists and is a regular
+ file. */
+ if ( active_path == NULL || *active_path == '\0' )
+ return -1;
+ if ( sieve_file_storage_get_full_active_path
+ (fstorage, &active_path, error_r) < 0 )
+ return -1;
+ if ( sieve_file_storage_stat
+ (fstorage, active_path, error_r) < 0 )
+ return -1;
+ if ( !S_ISREG(fstorage->lnk_st.st_mode) )
+ return -1;
+ e_debug(storage->event,
+ "Sieve storage path `%s' not found, "
+ "but the active script `%s' is a regular file, "
+ "so this is used for backwards compatibility.",
+ storage_path, active_path);
+ storage_path = NULL;
+ }
+ } else {
+ exists = TRUE;
+
+ if ( !S_ISDIR(fstorage->st.st_mode) ) {
+ if ( (storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0 ) {
+ sieve_storage_set_critical(storage,
+ "Sieve storage path `%s' is not a directory, "
+ "but it is to be opened for write access", storage_path);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+ if ( active_path != NULL && *active_path != '\0' ) {
+ e_warning(storage->event,
+ "Explicitly specified active script path `%s' is ignored; "
+ "storage path `%s' is not a directory",
+ active_path, storage_path);
+ }
+ active_path = storage_path;
+ storage_path = NULL;
+ }
+ }
+ }
+
+ if ( active_path == NULL || *active_path == '\0' ) {
+ if ( storage->main_storage ||
+ (storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0) {
+ e_debug(storage->event,
+ "Active script path is unconfigured; "
+ "using default (path=%s)",
+ SIEVE_FILE_DEFAULT_PATH);
+ active_path = SIEVE_FILE_DEFAULT_PATH;
+ }
+ }
+
+ return sieve_file_storage_init_common
+ (fstorage, active_path, storage_path, exists, error_r);
+}
+
+static void sieve_file_storage_autodetect
+(struct sieve_file_storage *fstorage, const char **storage_path_r)
+{
+ struct sieve_storage *storage = &fstorage->storage;
+ struct sieve_instance *svinst = storage->svinst;
+ const char *home = sieve_environment_get_homedir(svinst);
+ int mode = ( (storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0 ?
+ R_OK|W_OK|X_OK : R_OK|X_OK );
+
+ e_debug(storage->event, "Performing auto-detection");
+
+ /* We'll need to figure out the storage location ourself.
+ *
+ * It's $HOME/sieve or /sieve when (presumed to be) chrooted.
+ */
+ if ( home != NULL && *home != '\0' ) {
+ /* Use default ~/sieve */
+ e_debug(storage->event, "Use home (%s)", home);
+ *storage_path_r = t_strconcat(home, "/sieve", NULL);
+ } else {
+ e_debug(storage->event, "HOME is not set");
+
+ if (access("/sieve", mode) == 0) {
+ *storage_path_r = "/sieve";
+ e_debug(storage->event,
+ "Directory `/sieve' exists, assuming chroot");
+ }
+ }
+}
+
+static int sieve_file_storage_do_init_legacy
+(struct sieve_file_storage *fstorage, const char *active_path,
+ const char *storage_path, enum sieve_error *error_r)
+{
+ struct sieve_storage *storage = &fstorage->storage;
+ bool explicit = FALSE, exists = FALSE;
+
+ if ( storage_path == NULL || *storage_path == '\0' ) {
+ /* Try autodectection */
+ sieve_file_storage_autodetect(fstorage, &storage_path);
+
+ if ( storage_path != NULL && *storage_path != '\0') {
+ /* Got something: stat it */
+ if (sieve_file_storage_stat
+ (fstorage, storage_path, error_r) < 0 ) {
+ if (*error_r != SIEVE_ERROR_NOT_FOUND) {
+ /* Error */
+ return -1;
+ }
+ } else if ( S_ISDIR(fstorage->st.st_mode) ) {
+ /* Success */
+ exists = TRUE;
+ }
+ }
+
+ if ( (storage_path == NULL || *storage_path == '\0') &&
+ (storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0 ) {
+ sieve_storage_set_critical(storage,
+ "Could not find storage root directory for write access; "
+ "path was left unconfigured and autodetection failed");
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+
+ } else {
+ /* Get full storage path */
+ if ( sieve_file_storage_get_full_path
+ (fstorage, &storage_path, error_r) < 0 )
+ return -1;
+
+ /* Stat storage directory */
+ if ( sieve_file_storage_stat(fstorage, storage_path, error_r) < 0 ) {
+ if ( (*error_r != SIEVE_ERROR_NOT_FOUND) )
+ return -1;
+ if ( (storage->flags & SIEVE_STORAGE_FLAG_READWRITE) == 0 )
+ storage_path = NULL;
+ } else {
+ exists = TRUE;
+ }
+
+ /* Storage path must be a directory */
+ if ( exists && !S_ISDIR(fstorage->st.st_mode) ) {
+ sieve_storage_set_critical(storage,
+ "Sieve storage path `%s' configured using sieve_dir "
+ "is not a directory", storage_path);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+
+ explicit = TRUE;
+ }
+
+ if ( (active_path == NULL || *active_path == '\0') ) {
+ if ( storage->main_storage ||
+ (storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0) {
+ e_debug(storage->event,
+ "Active script path is unconfigured; "
+ "using default (path=%s)",
+ SIEVE_FILE_DEFAULT_PATH);
+ active_path = SIEVE_FILE_DEFAULT_PATH;
+ } else {
+ return -1;
+ }
+ }
+
+ if ( !explicit && !exists &&
+ active_path != NULL && *active_path != '\0' &&
+ (storage->flags & SIEVE_STORAGE_FLAG_READWRITE) == 0 )
+ storage_path = NULL;
+
+ if ( sieve_file_storage_init_common
+ (fstorage, active_path, storage_path, exists, error_r) < 0 )
+ return -1;
+ return 0;
+}
+
+struct sieve_storage *sieve_file_storage_init_legacy
+(struct sieve_instance *svinst, const char *active_path,
+ const char *storage_path, enum sieve_storage_flags flags,
+ enum sieve_error *error_r)
+{
+ struct sieve_storage *storage;
+ struct sieve_file_storage *fstorage;
+
+ storage = sieve_storage_alloc(svinst, NULL, &sieve_file_storage,
+ "", flags, TRUE);
+ fstorage = (struct sieve_file_storage *)storage;
+
+ T_BEGIN {
+ if ( sieve_file_storage_do_init_legacy
+ (fstorage, active_path, storage_path, error_r) < 0 ) {
+ sieve_storage_unref(&storage);
+ storage = NULL;
+ }
+ } T_END;
+
+ return storage;
+}
+
+struct sieve_file_storage *sieve_file_storage_init_from_path
+(struct sieve_instance *svinst, const char *path,
+ enum sieve_storage_flags flags, enum sieve_error *error_r)
+{
+ struct sieve_storage *storage;
+ struct sieve_file_storage *fstorage;
+
+ i_assert( path != NULL );
+
+ storage = sieve_storage_alloc(svinst, NULL, &sieve_file_storage,
+ "", flags, FALSE);
+ fstorage = (struct sieve_file_storage *)storage;
+
+ T_BEGIN {
+ if ( sieve_file_storage_init_common
+ (fstorage, path, NULL, FALSE, error_r) < 0 ) {
+ sieve_storage_unref(&storage);
+ fstorage = NULL;
+ }
+ } T_END;
+
+ return fstorage;
+}
+
+static int sieve_file_storage_is_singular
+(struct sieve_storage *storage)
+{
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ struct stat st;
+
+ if ( fstorage->active_path == NULL )
+ return 1;
+
+ /* Stat the file */
+ if ( lstat(fstorage->active_path, &st) != 0 ) {
+ if ( errno != ENOENT ) {
+ sieve_storage_set_critical(storage,
+ "Failed to stat active sieve script symlink (%s): %m.",
+ fstorage->active_path);
+ return -1;
+ }
+ return 0;
+ }
+
+ if ( S_ISLNK( st.st_mode ) )
+ return 0;
+ if ( !S_ISREG( st.st_mode ) ) {
+ sieve_storage_set_critical(storage,
+ "Active sieve script file '%s' is no symlink nor a regular file.",
+ fstorage->active_path);
+ return -1;
+ }
+ return 1;
+}
+
+/*
+ *
+ */
+
+static int sieve_file_storage_get_last_change
+(struct sieve_storage *storage, time_t *last_change_r)
+{
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ struct stat st;
+
+ if ( fstorage->prev_mtime == (time_t)-1 ) {
+ /* Get the storage mtime before we modify it ourself */
+ if ( stat(fstorage->path, &st) < 0 ) {
+ if ( errno != ENOENT ) {
+ e_error(storage->event,
+ "stat(%s) failed: %m",
+ fstorage->path);
+ return -1;
+ }
+ st.st_mtime = 0;
+ }
+
+ fstorage->prev_mtime = st.st_mtime;
+ }
+
+ if ( last_change_r != NULL )
+ *last_change_r = fstorage->prev_mtime;
+ return 0;
+}
+
+int sieve_file_storage_pre_modify
+(struct sieve_storage *storage)
+{
+ i_assert( (storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0 );
+
+ return sieve_storage_get_last_change(storage, NULL);
+}
+
+static void sieve_file_storage_set_modified
+(struct sieve_storage *storage, time_t mtime)
+{
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ struct utimbuf times;
+ time_t cur_mtime;
+
+ if ( mtime != (time_t)-1 ) {
+ if ( sieve_storage_get_last_change(storage, &cur_mtime) >= 0 &&
+ cur_mtime > mtime )
+ return;
+ } else {
+ mtime = ioloop_time;
+ }
+
+ times.actime = mtime;
+ times.modtime = mtime;
+ if ( utime(fstorage->path, &times) < 0 ) {
+ switch ( errno ) {
+ case ENOENT:
+ break;
+ case EACCES:
+ e_error(storage->event, "%s",
+ eacces_error_get("utime", fstorage->path));
+ break;
+ default:
+ e_error(storage->event,
+ "utime(%s) failed: %m", fstorage->path);
+ }
+ } else {
+ fstorage->prev_mtime = mtime;
+ }
+}
+
+/*
+ * Script access
+ */
+
+static struct sieve_script *sieve_file_storage_get_script
+(struct sieve_storage *storage, const char *name)
+{
+ struct sieve_file_storage *fstorage =
+ (struct sieve_file_storage *)storage;
+ struct sieve_file_script *fscript;
+
+ T_BEGIN {
+ fscript = sieve_file_script_init_from_name(fstorage, name);
+ } T_END;
+
+ return &fscript->script;
+}
+
+/*
+ * Driver definition
+ */
+
+const struct sieve_storage sieve_file_storage = {
+ .driver_name = SIEVE_FILE_STORAGE_DRIVER_NAME,
+ .version = 0,
+ .allows_synchronization = TRUE,
+ .v = {
+ .alloc = sieve_file_storage_alloc,
+ .init = sieve_file_storage_init,
+
+ .get_last_change = sieve_file_storage_get_last_change,
+ .set_modified = sieve_file_storage_set_modified,
+
+ .is_singular = sieve_file_storage_is_singular,
+
+ .get_script = sieve_file_storage_get_script,
+
+ .get_script_sequence = sieve_file_storage_get_script_sequence,
+ .script_sequence_next = sieve_file_script_sequence_next,
+ .script_sequence_destroy = sieve_file_script_sequence_destroy,
+
+ .active_script_get_name = sieve_file_storage_active_script_get_name,
+ .active_script_open = sieve_file_storage_active_script_open,
+ .deactivate = sieve_file_storage_deactivate,
+ .active_script_get_last_change =
+ sieve_file_storage_active_script_get_last_change,
+
+ .list_init = sieve_file_storage_list_init,
+ .list_next = sieve_file_storage_list_next,
+ .list_deinit = sieve_file_storage_list_deinit,
+
+ .save_alloc = sieve_file_storage_save_alloc,
+ .save_init = sieve_file_storage_save_init,
+ .save_continue = sieve_file_storage_save_continue,
+ .save_finish = sieve_file_storage_save_finish,
+ .save_get_tempscript = sieve_file_storage_save_get_tempscript,
+ .save_cancel = sieve_file_storage_save_cancel,
+ .save_commit = sieve_file_storage_save_commit,
+ .save_as = sieve_file_storage_save_as,
+ .save_as_active = sieve_file_storage_save_as_active,
+
+ .quota_havespace = sieve_file_storage_quota_havespace
+ }
+};
diff --git a/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage.h b/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage.h
new file mode 100644
index 0000000..ea7b92f
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/file/sieve-file-storage.h
@@ -0,0 +1,186 @@
+#ifndef SIEVE_FILE_STORAGE_H
+#define SIEVE_FILE_STORAGE_H
+
+#include "lib.h"
+#include "mail-user.h"
+
+#include "sieve.h"
+#include "sieve-script-private.h"
+#include "sieve-storage-private.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define SIEVE_FILE_READ_BLOCK_SIZE (1024*8)
+
+#define SIEVE_FILE_DEFAULT_PATH "~/.dovecot."SIEVE_SCRIPT_FILEEXT
+
+/* How often to scan tmp/ directory for old files (based on dir's atime) */
+#define SIEVE_FILE_STORAGE_TMP_SCAN_SECS (8*60*60)
+/* Delete files having ctime older than this from tmp/. 36h is standard. */
+#define SIEVE_FILE_STORAGE_TMP_DELETE_SECS (36*60*60)
+
+/*
+ * Storage class
+ */
+
+struct sieve_file_storage {
+ struct sieve_storage storage;
+
+ const char *path;
+ const char *active_path;
+ const char *active_fname;
+ const char *link_path;
+
+ struct stat st;
+ struct stat lnk_st;
+
+ mode_t dir_create_mode;
+ mode_t file_create_mode;
+ gid_t file_create_gid;
+
+ time_t prev_mtime;
+};
+
+const char *sieve_file_storage_path_extend
+ (struct sieve_file_storage *fstorage, const char *filename);
+
+struct sieve_file_storage *sieve_file_storage_init_from_path
+(struct sieve_instance *svinst, const char *path,
+ enum sieve_storage_flags flags, enum sieve_error *error_r)
+ ATTR_NULL(4);
+
+int sieve_file_storage_pre_modify
+ (struct sieve_storage *storage);
+
+/* Active script */
+
+int sieve_file_storage_active_replace_link
+ (struct sieve_file_storage *fstorage, const char *link_path);
+bool sieve_file_storage_active_rescue_regular
+ (struct sieve_file_storage *fstorage);
+
+int sieve_file_storage_active_script_get_name
+ (struct sieve_storage *storage, const char **name_r);
+struct sieve_script *sieve_file_storage_active_script_open
+ (struct sieve_storage *storage);
+
+int sieve_file_storage_active_script_get_file
+ (struct sieve_file_storage *fstorage, const char **file_r);
+int sieve_file_storage_active_script_is_no_link
+ (struct sieve_file_storage *fstorage);
+
+int sieve_file_storage_deactivate
+ (struct sieve_storage *storage);
+
+int sieve_file_storage_active_script_get_last_change
+ (struct sieve_storage *storage, time_t *last_change_r);
+
+/* Listing */
+
+struct sieve_storage_list_context *sieve_file_storage_list_init
+ (struct sieve_storage *storage);
+const char *sieve_file_storage_list_next
+ (struct sieve_storage_list_context *ctx, bool *active);
+int sieve_file_storage_list_deinit
+ (struct sieve_storage_list_context *lctx);
+
+/* Saving */
+
+struct sieve_storage_save_context *
+sieve_file_storage_save_alloc(struct sieve_storage *storage);
+int sieve_file_storage_save_init(struct sieve_storage_save_context *sctx,
+ const char *scriptname, struct istream *input);
+int sieve_file_storage_save_continue
+ (struct sieve_storage_save_context *sctx);
+int sieve_file_storage_save_finish
+ (struct sieve_storage_save_context *sctx);
+struct sieve_script *sieve_file_storage_save_get_tempscript
+ (struct sieve_storage_save_context *sctx);
+int sieve_file_storage_save_commit
+ (struct sieve_storage_save_context *sctx);
+void sieve_file_storage_save_cancel
+ (struct sieve_storage_save_context *sctx);
+
+int sieve_file_storage_save_as
+ (struct sieve_storage *storage, struct istream *input,
+ const char *name);
+int sieve_file_storage_save_as_active
+ (struct sieve_storage *storage, struct istream *input,
+ time_t mtime);
+
+/* Quota */
+
+int sieve_file_storage_quota_havespace
+(struct sieve_storage *storage, const char *scriptname, size_t size,
+ enum sieve_storage_quota *quota_r, uint64_t *limit_r);
+
+/*
+ * Sieve script filenames
+ */
+
+const char *sieve_script_file_get_scriptname(const char *filename);
+const char *sieve_script_file_from_name(const char *name);
+
+/*
+ * Script class
+ */
+
+struct sieve_file_script {
+ struct sieve_script script;
+
+ struct stat st;
+ struct stat lnk_st;
+
+ const char *path;
+ const char *dirpath;
+ const char *filename;
+ const char *binpath;
+ const char *binprefix;
+
+ time_t prev_mtime;
+};
+
+struct sieve_file_script *sieve_file_script_init_from_filename
+ (struct sieve_file_storage *fstorage, const char *filename,
+ const char *scriptname);
+struct sieve_file_script *sieve_file_script_open_from_filename
+ (struct sieve_file_storage *fstorage, const char *filename,
+ const char *scriptname);
+struct sieve_file_script *sieve_file_script_init_from_name
+ (struct sieve_file_storage *fstorage, const char *name);
+struct sieve_file_script *sieve_file_script_open_from_name
+ (struct sieve_file_storage *fstorage, const char *name);
+
+struct sieve_file_script *sieve_file_script_init_from_path
+ (struct sieve_file_storage *fstorage, const char *path,
+ const char *scriptname, enum sieve_error *error_r)
+ ATTR_NULL(4);
+struct sieve_file_script *sieve_file_script_open_from_path
+ (struct sieve_file_storage *fstorage, const char *path,
+ const char *scriptname, enum sieve_error *error_r)
+ ATTR_NULL(4);
+
+/* Return directory where script resides in. Returns NULL if this is not a file
+ * script.
+ */
+const char *sieve_file_script_get_dirpath
+ (const struct sieve_script *script);
+
+/* Return full path to file script. Returns NULL if this is not a file script.
+ */
+const char *sieve_file_script_get_path
+ (const struct sieve_script *script);
+
+/*
+ * Script sequence
+ */
+
+struct sieve_script_sequence *sieve_file_storage_get_script_sequence
+ (struct sieve_storage *storage, enum sieve_error *error_r);
+
+struct sieve_script *sieve_file_script_sequence_next
+ (struct sieve_script_sequence *seq, enum sieve_error *error_r);
+void sieve_file_script_sequence_destroy(struct sieve_script_sequence *seq);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/storage/ldap/Makefile.am b/pigeonhole/src/lib-sieve/storage/ldap/Makefile.am
new file mode 100644
index 0000000..86df92c
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/ldap/Makefile.am
@@ -0,0 +1,32 @@
+noinst_LTLIBRARIES = libsieve_storage_ldap.la
+
+sieve_plugindir = $(dovecot_moduledir)/sieve
+sieve_plugin_LTLIBRARIES =
+
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src/lib-sieve
+
+ldap_sources = \
+ sieve-ldap-db.c \
+ sieve-ldap-script.c \
+ sieve-ldap-storage.c \
+ sieve-ldap-storage-settings.c
+
+libsieve_storage_ldap_la_SOURCES = $(ldap_sources)
+libsieve_storage_ldap_la_LIBADD = $(LDAP_LIBS)
+
+noinst_HEADERS = \
+ sieve-ldap-db.h \
+ sieve-ldap-storage.h
+
+if LDAP_PLUGIN
+sieve_plugin_LTLIBRARIES += lib10_sieve_storage_ldap_plugin.la
+
+lib10_sieve_storage_ldap_plugin_la_LDFLAGS = -module -avoid-version
+lib10_sieve_storage_ldap_plugin_la_LIBADD = $(LDAP_LIBS)
+lib10_sieve_storage_ldap_plugin_la_DEPENDENCIES = $(LDAP_LIBS)
+lib10_sieve_storage_ldap_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -DPLUGIN_BUILD
+lib10_sieve_storage_ldap_plugin_la_SOURCES = $(ldap_sources)
+endif
diff --git a/pigeonhole/src/lib-sieve/storage/ldap/Makefile.in b/pigeonhole/src/lib-sieve/storage/ldap/Makefile.in
new file mode 100644
index 0000000..232f781
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/ldap/Makefile.in
@@ -0,0 +1,843 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@LDAP_PLUGIN_TRUE@am__append_1 = lib10_sieve_storage_ldap_plugin.la
+subdir = src/lib-sieve/storage/ldap
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(sieve_plugindir)"
+LTLIBRARIES = $(noinst_LTLIBRARIES) $(sieve_plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+am__lib10_sieve_storage_ldap_plugin_la_SOURCES_DIST = sieve-ldap-db.c \
+ sieve-ldap-script.c sieve-ldap-storage.c \
+ sieve-ldap-storage-settings.c
+am__objects_1 = lib10_sieve_storage_ldap_plugin_la-sieve-ldap-db.lo \
+ lib10_sieve_storage_ldap_plugin_la-sieve-ldap-script.lo \
+ lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage.lo \
+ lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage-settings.lo
+@LDAP_PLUGIN_TRUE@am_lib10_sieve_storage_ldap_plugin_la_OBJECTS = \
+@LDAP_PLUGIN_TRUE@ $(am__objects_1)
+lib10_sieve_storage_ldap_plugin_la_OBJECTS = \
+ $(am_lib10_sieve_storage_ldap_plugin_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+lib10_sieve_storage_ldap_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(lib10_sieve_storage_ldap_plugin_la_LDFLAGS) $(LDFLAGS) -o $@
+@LDAP_PLUGIN_TRUE@am_lib10_sieve_storage_ldap_plugin_la_rpath = \
+@LDAP_PLUGIN_TRUE@ -rpath $(sieve_plugindir)
+libsieve_storage_ldap_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am__objects_2 = sieve-ldap-db.lo sieve-ldap-script.lo \
+ sieve-ldap-storage.lo sieve-ldap-storage-settings.lo
+am_libsieve_storage_ldap_la_OBJECTS = $(am__objects_2)
+libsieve_storage_ldap_la_OBJECTS = \
+ $(am_libsieve_storage_ldap_la_OBJECTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-db.Plo \
+ ./$(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-script.Plo \
+ ./$(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage-settings.Plo \
+ ./$(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage.Plo \
+ ./$(DEPDIR)/sieve-ldap-db.Plo \
+ ./$(DEPDIR)/sieve-ldap-script.Plo \
+ ./$(DEPDIR)/sieve-ldap-storage-settings.Plo \
+ ./$(DEPDIR)/sieve-ldap-storage.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(lib10_sieve_storage_ldap_plugin_la_SOURCES) \
+ $(libsieve_storage_ldap_la_SOURCES)
+DIST_SOURCES = $(am__lib10_sieve_storage_ldap_plugin_la_SOURCES_DIST) \
+ $(libsieve_storage_ldap_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_storage_ldap.la
+sieve_plugindir = $(dovecot_moduledir)/sieve
+sieve_plugin_LTLIBRARIES = $(am__append_1)
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src/lib-sieve
+
+ldap_sources = \
+ sieve-ldap-db.c \
+ sieve-ldap-script.c \
+ sieve-ldap-storage.c \
+ sieve-ldap-storage-settings.c
+
+libsieve_storage_ldap_la_SOURCES = $(ldap_sources)
+libsieve_storage_ldap_la_LIBADD = $(LDAP_LIBS)
+noinst_HEADERS = \
+ sieve-ldap-db.h \
+ sieve-ldap-storage.h
+
+@LDAP_PLUGIN_TRUE@lib10_sieve_storage_ldap_plugin_la_LDFLAGS = -module -avoid-version
+@LDAP_PLUGIN_TRUE@lib10_sieve_storage_ldap_plugin_la_LIBADD = $(LDAP_LIBS)
+@LDAP_PLUGIN_TRUE@lib10_sieve_storage_ldap_plugin_la_DEPENDENCIES = $(LDAP_LIBS)
+@LDAP_PLUGIN_TRUE@lib10_sieve_storage_ldap_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -DPLUGIN_BUILD
+@LDAP_PLUGIN_TRUE@lib10_sieve_storage_ldap_plugin_la_SOURCES = $(ldap_sources)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/storage/ldap/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/storage/ldap/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+install-sieve_pluginLTLIBRARIES: $(sieve_plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(sieve_plugin_LTLIBRARIES)'; test -n "$(sieve_plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sieve_plugindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sieve_plugindir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(sieve_plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(sieve_plugindir)"; \
+ }
+
+uninstall-sieve_pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sieve_plugin_LTLIBRARIES)'; test -n "$(sieve_plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(sieve_plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(sieve_plugindir)/$$f"; \
+ done
+
+clean-sieve_pluginLTLIBRARIES:
+ -test -z "$(sieve_plugin_LTLIBRARIES)" || rm -f $(sieve_plugin_LTLIBRARIES)
+ @list='$(sieve_plugin_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+lib10_sieve_storage_ldap_plugin.la: $(lib10_sieve_storage_ldap_plugin_la_OBJECTS) $(lib10_sieve_storage_ldap_plugin_la_DEPENDENCIES) $(EXTRA_lib10_sieve_storage_ldap_plugin_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(lib10_sieve_storage_ldap_plugin_la_LINK) $(am_lib10_sieve_storage_ldap_plugin_la_rpath) $(lib10_sieve_storage_ldap_plugin_la_OBJECTS) $(lib10_sieve_storage_ldap_plugin_la_LIBADD) $(LIBS)
+
+libsieve_storage_ldap.la: $(libsieve_storage_ldap_la_OBJECTS) $(libsieve_storage_ldap_la_DEPENDENCIES) $(EXTRA_libsieve_storage_ldap_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_storage_ldap_la_OBJECTS) $(libsieve_storage_ldap_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-db.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-script.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage-settings.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-ldap-db.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-ldap-script.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-ldap-storage-settings.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-ldap-storage.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+lib10_sieve_storage_ldap_plugin_la-sieve-ldap-db.lo: sieve-ldap-db.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib10_sieve_storage_ldap_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib10_sieve_storage_ldap_plugin_la-sieve-ldap-db.lo -MD -MP -MF $(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-db.Tpo -c -o lib10_sieve_storage_ldap_plugin_la-sieve-ldap-db.lo `test -f 'sieve-ldap-db.c' || echo '$(srcdir)/'`sieve-ldap-db.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-db.Tpo $(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-db.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sieve-ldap-db.c' object='lib10_sieve_storage_ldap_plugin_la-sieve-ldap-db.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib10_sieve_storage_ldap_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib10_sieve_storage_ldap_plugin_la-sieve-ldap-db.lo `test -f 'sieve-ldap-db.c' || echo '$(srcdir)/'`sieve-ldap-db.c
+
+lib10_sieve_storage_ldap_plugin_la-sieve-ldap-script.lo: sieve-ldap-script.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib10_sieve_storage_ldap_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib10_sieve_storage_ldap_plugin_la-sieve-ldap-script.lo -MD -MP -MF $(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-script.Tpo -c -o lib10_sieve_storage_ldap_plugin_la-sieve-ldap-script.lo `test -f 'sieve-ldap-script.c' || echo '$(srcdir)/'`sieve-ldap-script.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-script.Tpo $(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-script.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sieve-ldap-script.c' object='lib10_sieve_storage_ldap_plugin_la-sieve-ldap-script.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib10_sieve_storage_ldap_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib10_sieve_storage_ldap_plugin_la-sieve-ldap-script.lo `test -f 'sieve-ldap-script.c' || echo '$(srcdir)/'`sieve-ldap-script.c
+
+lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage.lo: sieve-ldap-storage.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib10_sieve_storage_ldap_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage.lo -MD -MP -MF $(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage.Tpo -c -o lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage.lo `test -f 'sieve-ldap-storage.c' || echo '$(srcdir)/'`sieve-ldap-storage.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage.Tpo $(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sieve-ldap-storage.c' object='lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib10_sieve_storage_ldap_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage.lo `test -f 'sieve-ldap-storage.c' || echo '$(srcdir)/'`sieve-ldap-storage.c
+
+lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage-settings.lo: sieve-ldap-storage-settings.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib10_sieve_storage_ldap_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage-settings.lo -MD -MP -MF $(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage-settings.Tpo -c -o lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage-settings.lo `test -f 'sieve-ldap-storage-settings.c' || echo '$(srcdir)/'`sieve-ldap-storage-settings.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage-settings.Tpo $(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage-settings.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sieve-ldap-storage-settings.c' object='lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage-settings.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib10_sieve_storage_ldap_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage-settings.lo `test -f 'sieve-ldap-storage-settings.c' || echo '$(srcdir)/'`sieve-ldap-storage-settings.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(sieve_plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ clean-sieve_pluginLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-db.Plo
+ -rm -f ./$(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-script.Plo
+ -rm -f ./$(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage-settings.Plo
+ -rm -f ./$(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage.Plo
+ -rm -f ./$(DEPDIR)/sieve-ldap-db.Plo
+ -rm -f ./$(DEPDIR)/sieve-ldap-script.Plo
+ -rm -f ./$(DEPDIR)/sieve-ldap-storage-settings.Plo
+ -rm -f ./$(DEPDIR)/sieve-ldap-storage.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-sieve_pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-db.Plo
+ -rm -f ./$(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-script.Plo
+ -rm -f ./$(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage-settings.Plo
+ -rm -f ./$(DEPDIR)/lib10_sieve_storage_ldap_plugin_la-sieve-ldap-storage.Plo
+ -rm -f ./$(DEPDIR)/sieve-ldap-db.Plo
+ -rm -f ./$(DEPDIR)/sieve-ldap-script.Plo
+ -rm -f ./$(DEPDIR)/sieve-ldap-storage-settings.Plo
+ -rm -f ./$(DEPDIR)/sieve-ldap-storage.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-sieve_pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ clean-sieve_pluginLTLIBRARIES cscopelist-am ctags ctags-am \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-sieve_pluginLTLIBRARIES \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-sieve_pluginLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-db.c b/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-db.c
new file mode 100644
index 0000000..0a7b440
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-db.c
@@ -0,0 +1,1378 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+
+#include "sieve-ldap-storage.h"
+
+/* FIXME: Imported this from Dovecot auth for now. We're working on a proper
+ lib-ldap, but, until then, some code is duplicated here. */
+
+#if defined(SIEVE_BUILTIN_LDAP) || defined(PLUGIN_BUILD)
+
+#include "net.h"
+#include "ioloop.h"
+#include "array.h"
+#include "hash.h"
+#include "aqueue.h"
+#include "str.h"
+#include "time-util.h"
+#include "env-util.h"
+#include "var-expand.h"
+#include "istream.h"
+
+#include <stddef.h>
+#include <unistd.h>
+
+struct db_ldap_result {
+ int refcount;
+ LDAPMessage *msg;
+};
+
+struct db_ldap_result_iterate_context {
+ pool_t pool;
+
+ struct auth_request *auth_request;
+ const ARRAY_TYPE(ldap_field) *attr_map;
+ unsigned int attr_idx;
+
+ /* attribute name => value */
+ HASH_TABLE(char *, struct db_ldap_value *) ldap_attrs;
+
+ const char *val_1_arr[2];
+ string_t *var, *debug;
+
+ bool skip_null_values;
+ bool iter_dn_values;
+};
+
+struct db_ldap_sasl_bind_context {
+ const char *authcid;
+ const char *passwd;
+ const char *realm;
+ const char *authzid;
+};
+
+static struct ldap_connection *ldap_connections = NULL;
+
+static int db_ldap_bind(struct ldap_connection *conn);
+static void db_ldap_conn_close(struct ldap_connection *conn);
+
+int ldap_deref_from_str(const char *str, int *deref_r)
+{
+ if (strcasecmp(str, "never") == 0)
+ *deref_r = LDAP_DEREF_NEVER;
+ else if (strcasecmp(str, "searching") == 0)
+ *deref_r = LDAP_DEREF_SEARCHING;
+ else if (strcasecmp(str, "finding") == 0)
+ *deref_r = LDAP_DEREF_FINDING;
+ else if (strcasecmp(str, "always") == 0)
+ *deref_r = LDAP_DEREF_ALWAYS;
+ else
+ return -1;
+ return 0;
+}
+
+int ldap_scope_from_str(const char *str, int *scope_r)
+{
+ if (strcasecmp(str, "base") == 0)
+ *scope_r = LDAP_SCOPE_BASE;
+ else if (strcasecmp(str, "onelevel") == 0)
+ *scope_r = LDAP_SCOPE_ONELEVEL;
+ else if (strcasecmp(str, "subtree") == 0)
+ *scope_r = LDAP_SCOPE_SUBTREE;
+ else
+ return -1;
+ return 0;
+}
+
+#ifdef OPENLDAP_TLS_OPTIONS
+int ldap_tls_require_cert_from_str(const char *str, int *opt_x_tls_r)
+{
+ if (strcasecmp(str, "never") == 0)
+ *opt_x_tls_r = LDAP_OPT_X_TLS_NEVER;
+ else if (strcasecmp(str, "hard") == 0)
+ *opt_x_tls_r = LDAP_OPT_X_TLS_HARD;
+ else if (strcasecmp(str, "demand") == 0)
+ *opt_x_tls_r = LDAP_OPT_X_TLS_DEMAND;
+ else if (strcasecmp(str, "allow") == 0)
+ *opt_x_tls_r = LDAP_OPT_X_TLS_ALLOW;
+ else if (strcasecmp(str, "try") == 0)
+ *opt_x_tls_r = LDAP_OPT_X_TLS_TRY;
+ else
+ return -1;
+ return 0;
+}
+#endif
+
+
+static int ldap_get_errno(struct ldap_connection *conn)
+{
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ int ret, err;
+
+ ret = ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, (void *) &err);
+ if (ret != LDAP_SUCCESS) {
+ e_error(storage->event, "db: "
+ "Can't get error number: %s",
+ ldap_err2string(ret));
+ return LDAP_UNAVAILABLE;
+ }
+
+ return err;
+}
+
+const char *ldap_get_error(struct ldap_connection *conn)
+{
+ const char *ret;
+ char *str = NULL;
+
+ ret = ldap_err2string(ldap_get_errno(conn));
+
+ ldap_get_option(conn->ld, LDAP_OPT_ERROR_STRING, (void *)&str);
+ if (str != NULL) {
+ ret = t_strconcat(ret, ", ", str, NULL);
+ ldap_memfree(str);
+ }
+ ldap_set_option(conn->ld, LDAP_OPT_ERROR_STRING, NULL);
+ return ret;
+}
+
+static void ldap_conn_reconnect(struct ldap_connection *conn)
+{
+ db_ldap_conn_close(conn);
+ if (sieve_ldap_db_connect(conn) < 0)
+ db_ldap_conn_close(conn);
+}
+
+static int ldap_handle_error(struct ldap_connection *conn)
+{
+ int err = ldap_get_errno(conn);
+
+ switch (err) {
+ case LDAP_SUCCESS:
+ i_unreached();
+ case LDAP_SIZELIMIT_EXCEEDED:
+ case LDAP_TIMELIMIT_EXCEEDED:
+ case LDAP_NO_SUCH_ATTRIBUTE:
+ case LDAP_UNDEFINED_TYPE:
+ case LDAP_INAPPROPRIATE_MATCHING:
+ case LDAP_CONSTRAINT_VIOLATION:
+ case LDAP_TYPE_OR_VALUE_EXISTS:
+ case LDAP_INVALID_SYNTAX:
+ case LDAP_NO_SUCH_OBJECT:
+ case LDAP_ALIAS_PROBLEM:
+ case LDAP_INVALID_DN_SYNTAX:
+ case LDAP_IS_LEAF:
+ case LDAP_ALIAS_DEREF_PROBLEM:
+ case LDAP_FILTER_ERROR:
+ /* invalid input */
+ return -1;
+ case LDAP_SERVER_DOWN:
+ case LDAP_TIMEOUT:
+ case LDAP_UNAVAILABLE:
+ case LDAP_BUSY:
+#ifdef LDAP_CONNECT_ERROR
+ case LDAP_CONNECT_ERROR:
+#endif
+ case LDAP_LOCAL_ERROR:
+ case LDAP_INVALID_CREDENTIALS:
+ case LDAP_OPERATIONS_ERROR:
+ default:
+ /* connection problems */
+ ldap_conn_reconnect(conn);
+ return 0;
+ }
+}
+
+static int db_ldap_request_search(struct ldap_connection *conn,
+ struct ldap_request *request)
+{
+ struct sieve_storage *storage = &conn->lstorage->storage;
+
+ i_assert(conn->conn_state == LDAP_CONN_STATE_BOUND);
+ i_assert(request->msgid == -1);
+
+ request->msgid =
+ ldap_search(conn->ld, *request->base == '\0' ? NULL :
+ request->base, request->scope,
+ request->filter, request->attributes, 0);
+ if (request->msgid == -1) {
+ e_error(storage->event, "db: "
+ "ldap_search(%s) parsing failed: %s",
+ request->filter, ldap_get_error(conn));
+ if (ldap_handle_error(conn) < 0) {
+ /* broken request, remove it */
+ return 0;
+ }
+ return -1;
+ }
+ return 1;
+}
+
+static bool db_ldap_request_queue_next(struct ldap_connection *conn)
+{
+ struct ldap_request *const *requestp, *request;
+ int ret = -1;
+
+ /* connecting may call db_ldap_connect_finish(), which gets us back
+ here. so do the connection before checking the request queue. */
+ if (sieve_ldap_db_connect(conn) < 0)
+ return FALSE;
+
+ if (conn->pending_count == aqueue_count(conn->request_queue)) {
+ /* no non-pending requests */
+ return FALSE;
+ }
+ if (conn->pending_count > DB_LDAP_MAX_PENDING_REQUESTS) {
+ /* wait until server has replied to some requests */
+ return FALSE;
+ }
+
+ requestp = array_idx(&conn->request_array,
+ aqueue_idx(conn->request_queue,
+ conn->pending_count));
+ request = *requestp;
+
+ switch (conn->conn_state) {
+ case LDAP_CONN_STATE_DISCONNECTED:
+ case LDAP_CONN_STATE_BINDING:
+ /* wait until we're in bound state */
+ return FALSE;
+ case LDAP_CONN_STATE_BOUND:
+ /* we can do anything in this state */
+ break;
+ }
+
+ ret = db_ldap_request_search(conn, request);
+ if (ret > 0) {
+ /* success */
+ i_assert(request->msgid != -1);
+ conn->pending_count++;
+ return TRUE;
+ } else if (ret < 0) {
+ /* disconnected */
+ return FALSE;
+ } else {
+ /* broken request, remove from queue */
+ aqueue_delete_tail(conn->request_queue);
+ request->callback(conn, request, NULL);
+ return TRUE;
+ }
+}
+
+static bool
+db_ldap_check_limits(struct ldap_connection *conn)
+{
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ struct ldap_request *const *first_requestp;
+ unsigned int count;
+ time_t secs_diff;
+
+ count = aqueue_count(conn->request_queue);
+ if (count == 0)
+ return TRUE;
+
+ first_requestp = array_idx(&conn->request_array,
+ aqueue_idx(conn->request_queue, 0));
+ secs_diff = ioloop_time - (*first_requestp)->create_time;
+ if (secs_diff > DB_LDAP_REQUEST_LOST_TIMEOUT_SECS) {
+ e_error(storage->event, "db: "
+ "Connection appears to be hanging, reconnecting");
+ ldap_conn_reconnect(conn);
+ return TRUE;
+ }
+ return TRUE;
+}
+
+void db_ldap_request(struct ldap_connection *conn,
+ struct ldap_request *request)
+{
+ request->msgid = -1;
+ request->create_time = ioloop_time;
+
+ if (!db_ldap_check_limits(conn)) {
+ request->callback(conn, request, NULL);
+ return;
+ }
+
+ aqueue_append(conn->request_queue, &request);
+ (void)db_ldap_request_queue_next(conn);
+}
+
+static int db_ldap_connect_finish(struct ldap_connection *conn, int ret)
+{
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ const struct sieve_ldap_storage_settings *set = &conn->lstorage->set;
+
+ if (ret == LDAP_SERVER_DOWN) {
+ e_error(storage->event, "db: "
+ "Can't connect to server: %s",
+ set->uris != NULL ?
+ set->uris : set->hosts);
+ return -1;
+ }
+ if (ret != LDAP_SUCCESS) {
+ e_error(storage->event, "db: "
+ "binding failed (dn %s): %s",
+ set->dn == NULL ? "(none)" : set->dn,
+ ldap_get_error(conn));
+ return -1;
+ }
+
+ timeout_remove(&conn->to);
+ conn->conn_state = LDAP_CONN_STATE_BOUND;
+ e_debug(storage->event, "db: "
+ "Successfully bound (dn %s)",
+ set->dn == NULL ? "(none)" : set->dn);
+ while (db_ldap_request_queue_next(conn))
+ ;
+ return 0;
+}
+
+static void db_ldap_default_bind_finished(struct ldap_connection *conn,
+ struct db_ldap_result *res)
+{
+ int ret;
+
+ i_assert(conn->pending_count == 0);
+ conn->default_bind_msgid = -1;
+
+ ret = ldap_result2error(conn->ld, res->msg, FALSE);
+ if (db_ldap_connect_finish(conn, ret) < 0) {
+ /* lost connection, close it */
+ db_ldap_conn_close(conn);
+ }
+}
+
+static void db_ldap_abort_requests(struct ldap_connection *conn,
+ unsigned int max_count,
+ unsigned int timeout_secs,
+ bool error, const char *reason)
+{
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ struct ldap_request *const *requestp, *request;
+ time_t diff;
+
+ while (aqueue_count(conn->request_queue) > 0 && max_count > 0) {
+ requestp = array_idx(&conn->request_array,
+ aqueue_idx(conn->request_queue, 0));
+ request = *requestp;
+
+ diff = ioloop_time - request->create_time;
+ if (diff < (time_t)timeout_secs)
+ break;
+
+ /* timed out, abort */
+ aqueue_delete_tail(conn->request_queue);
+
+ if (request->msgid != -1) {
+ i_assert(conn->pending_count > 0);
+ conn->pending_count--;
+ }
+ if (error)
+ e_error(storage->event, "db: %s", reason);
+ else
+ e_debug(storage->event, "db: %s", reason);
+ request->callback(conn, request, NULL);
+ max_count--;
+ }
+}
+
+static struct ldap_request *
+db_ldap_find_request(struct ldap_connection *conn, int msgid,
+ unsigned int *idx_r)
+{
+ struct ldap_request *const *requests, *request = NULL;
+ unsigned int i, count;
+
+ count = aqueue_count(conn->request_queue);
+ if (count == 0)
+ return NULL;
+
+ requests = array_idx(&conn->request_array, 0);
+ for (i = 0; i < count; i++) {
+ request = requests[aqueue_idx(conn->request_queue, i)];
+ if (request->msgid == msgid) {
+ *idx_r = i;
+ return request;
+ }
+ if (request->msgid == -1)
+ break;
+ }
+ return NULL;
+}
+
+static bool
+db_ldap_handle_request_result(struct ldap_connection *conn,
+ struct ldap_request *request, unsigned int idx,
+ struct db_ldap_result *res)
+{
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ int ret;
+ bool final_result;
+
+ i_assert(conn->pending_count > 0);
+
+ switch (ldap_msgtype(res->msg)) {
+ case LDAP_RES_SEARCH_ENTRY:
+ case LDAP_RES_SEARCH_RESULT:
+ break;
+ case LDAP_RES_SEARCH_REFERENCE:
+ /* we're going to ignore this */
+ return FALSE;
+ default:
+ e_error(storage->event, "db: Reply with unexpected type %d",
+ ldap_msgtype(res->msg));
+ return TRUE;
+ }
+
+ if (ldap_msgtype(res->msg) == LDAP_RES_SEARCH_ENTRY) {
+ ret = LDAP_SUCCESS;
+ final_result = FALSE;
+ } else {
+ final_result = TRUE;
+ ret = ldap_result2error(conn->ld, res->msg, 0);
+ }
+ if (ret != LDAP_SUCCESS) {
+ /* handle search failures here */
+ e_error(storage->event, "db: "
+ "ldap_search(base=%s filter=%s) failed: %s",
+ request->base, request->filter,
+ ldap_err2string(ret));
+ res = NULL;
+ } else {
+ if (!final_result && storage->svinst->debug) {
+ e_debug(storage->event,
+ "db: ldap_search(base=%s filter=%s) returned entry: %s",
+ request->base, request->filter,
+ ldap_get_dn(conn->ld, res->msg));
+ }
+ }
+ if (res == NULL && !final_result) {
+ /* wait for the final reply */
+ request->failed = TRUE;
+ return TRUE;
+ }
+ if (request->failed)
+ res = NULL;
+ if (final_result) {
+ conn->pending_count--;
+ aqueue_delete(conn->request_queue, idx);
+ }
+
+ T_BEGIN {
+ request->callback(conn, request, res == NULL ? NULL : res->msg);
+ } T_END;
+
+ if (idx > 0) {
+ /* see if there are timed out requests */
+ db_ldap_abort_requests(conn, idx,
+ DB_LDAP_REQUEST_LOST_TIMEOUT_SECS,
+ TRUE, "Request lost");
+ }
+ return TRUE;
+}
+
+static void db_ldap_result_unref(struct db_ldap_result **_res)
+{
+ struct db_ldap_result *res = *_res;
+
+ *_res = NULL;
+ i_assert(res->refcount > 0);
+ if (--res->refcount == 0) {
+ ldap_msgfree(res->msg);
+ i_free(res);
+ }
+}
+
+static void
+db_ldap_request_free(struct ldap_request *request)
+{
+ if (request->result != NULL)
+ db_ldap_result_unref(&request->result);
+}
+
+static void
+db_ldap_handle_result(struct ldap_connection *conn, struct db_ldap_result *res)
+{
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ struct ldap_request *request;
+ unsigned int idx;
+ int msgid;
+
+ msgid = ldap_msgid(res->msg);
+ if (msgid == conn->default_bind_msgid) {
+ db_ldap_default_bind_finished(conn, res);
+ return;
+ }
+
+ request = db_ldap_find_request(conn, msgid, &idx);
+ if (request == NULL) {
+ e_error(storage->event,
+ "db: Reply with unknown msgid %d", msgid);
+ return;
+ }
+
+ if (db_ldap_handle_request_result(conn, request, idx, res))
+ db_ldap_request_free(request);
+}
+
+static void ldap_input(struct ldap_connection *conn)
+{
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ struct timeval timeout;
+ struct db_ldap_result *res;
+ LDAPMessage *msg;
+ time_t prev_reply_diff;
+ int ret;
+
+ do {
+ if (conn->ld == NULL)
+ return;
+
+ i_zero(&timeout);
+ ret = ldap_result(conn->ld, LDAP_RES_ANY, 0, &timeout, &msg);
+#ifdef OPENLDAP_ASYNC_WORKAROUND
+ if (ret == 0) {
+ /* try again, there may be another in buffer */
+ ret = ldap_result(conn->ld, LDAP_RES_ANY, 0,
+ &timeout, &msg);
+ }
+#endif
+ if (ret <= 0)
+ break;
+
+ res = i_new(struct db_ldap_result, 1);
+ res->refcount = 1;
+ res->msg = msg;
+ db_ldap_handle_result(conn, res);
+ db_ldap_result_unref(&res);
+ } while (conn->io != NULL);
+
+ prev_reply_diff = ioloop_time - conn->last_reply_stamp;
+ conn->last_reply_stamp = ioloop_time;
+
+ if (ret > 0) {
+ /* input disabled, continue once it's enabled */
+ i_assert(conn->io == NULL);
+ } else if (ret == 0) {
+ /* send more requests */
+ while (db_ldap_request_queue_next(conn))
+ ;
+ } else if (ldap_get_errno(conn) != LDAP_SERVER_DOWN) {
+ e_error(storage->event, "db: ldap_result() failed: %s",
+ ldap_get_error(conn));
+ ldap_conn_reconnect(conn);
+ } else if (aqueue_count(conn->request_queue) > 0 ||
+ prev_reply_diff < DB_LDAP_IDLE_RECONNECT_SECS) {
+ e_error(storage->event,
+ "db: Connection lost to LDAP server, reconnecting");
+ ldap_conn_reconnect(conn);
+ } else {
+ /* server probably disconnected an idle connection. don't
+ reconnect until the next request comes. */
+ db_ldap_conn_close(conn);
+ }
+}
+
+#ifdef HAVE_LDAP_SASL
+static int
+sasl_interact(LDAP *ld ATTR_UNUSED, unsigned flags ATTR_UNUSED,
+ void *defaults, void *interact)
+{
+ struct db_ldap_sasl_bind_context *context = defaults;
+ sasl_interact_t *in;
+ const char *str;
+
+ for (in = interact; in->id != SASL_CB_LIST_END; in++) {
+ switch (in->id) {
+ case SASL_CB_GETREALM:
+ str = context->realm;
+ break;
+ case SASL_CB_AUTHNAME:
+ str = context->authcid;
+ break;
+ case SASL_CB_USER:
+ str = context->authzid;
+ break;
+ case SASL_CB_PASS:
+ str = context->passwd;
+ break;
+ default:
+ str = NULL;
+ break;
+ }
+ if (str != NULL) {
+ in->len = strlen(str);
+ in->result = str;
+ }
+
+ }
+ return LDAP_SUCCESS;
+}
+#endif
+
+static void ldap_connection_timeout(struct ldap_connection *conn)
+{
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ i_assert(conn->conn_state == LDAP_CONN_STATE_BINDING);
+
+ e_error(storage->event, "db: Initial binding to LDAP server timed out");
+ db_ldap_conn_close(conn);
+}
+
+static int db_ldap_bind(struct ldap_connection *conn)
+{
+ const struct sieve_ldap_storage_settings *set = &conn->lstorage->set;
+ int msgid;
+
+ i_assert(conn->conn_state != LDAP_CONN_STATE_BINDING);
+ i_assert(conn->default_bind_msgid == -1);
+ i_assert(conn->pending_count == 0);
+
+ msgid = ldap_bind(conn->ld, set->dn, set->dnpass,
+ LDAP_AUTH_SIMPLE);
+ if (msgid == -1) {
+ i_assert(ldap_get_errno(conn) != LDAP_SUCCESS);
+ if (db_ldap_connect_finish(conn, ldap_get_errno(conn)) < 0) {
+ /* lost connection, close it */
+ db_ldap_conn_close(conn);
+ }
+ return -1;
+ }
+
+ conn->conn_state = LDAP_CONN_STATE_BINDING;
+ conn->default_bind_msgid = msgid;
+
+ timeout_remove(&conn->to);
+ conn->to = timeout_add(DB_LDAP_REQUEST_LOST_TIMEOUT_SECS*1000,
+ ldap_connection_timeout, conn);
+ return 0;
+}
+
+static int db_ldap_get_fd(struct ldap_connection *conn)
+{
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ int ret;
+
+ /* get the connection's fd */
+ ret = ldap_get_option(conn->ld, LDAP_OPT_DESC, (void *)&conn->fd);
+ if (ret != LDAP_SUCCESS) {
+ e_error(storage->event, "db: Can't get connection fd: %s",
+ ldap_err2string(ret));
+ return -1;
+ }
+ if (conn->fd <= STDERR_FILENO) {
+ /* Solaris LDAP library seems to be broken */
+ e_error(storage->event,
+ "db: Buggy LDAP library returned wrong fd: %d",
+ conn->fd);
+ return -1;
+ }
+ i_assert(conn->fd != -1);
+ net_set_nonblock(conn->fd, TRUE);
+ return 0;
+}
+
+static int
+db_ldap_set_opt(struct ldap_connection *conn, int opt, const void *value,
+ const char *optname, const char *value_str)
+{
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ int ret;
+
+ ret = ldap_set_option(conn->ld, opt, value);
+ if (ret != LDAP_SUCCESS) {
+ e_error(storage->event, "db: Can't set option %s to %s: %s",
+ optname, value_str, ldap_err2string(ret));
+ return -1;
+ }
+ return 0;
+}
+
+static int
+db_ldap_set_opt_str(struct ldap_connection *conn, int opt, const char *value,
+ const char *optname)
+{
+ if (value != NULL)
+ return db_ldap_set_opt(conn, opt, value, optname, value);
+ return 0;
+}
+
+static int db_ldap_set_tls_options(struct ldap_connection *conn)
+{
+ const struct sieve_ldap_storage_settings *set = &conn->lstorage->set;
+
+ if (!set->tls)
+ return 0;
+
+#ifdef OPENLDAP_TLS_OPTIONS
+ if (db_ldap_set_opt_str(conn, LDAP_OPT_X_TLS_CACERTFILE,
+ set->tls_ca_cert_file, "tls_ca_cert_file") < 0)
+ return -1;
+ if (db_ldap_set_opt_str(conn, LDAP_OPT_X_TLS_CACERTDIR,
+ set->tls_ca_cert_dir, "tls_ca_cert_dir") < 0)
+ return -1;
+ if (db_ldap_set_opt_str(conn, LDAP_OPT_X_TLS_CERTFILE,
+ set->tls_cert_file, "tls_cert_file") < 0)
+ return -1;
+ if (db_ldap_set_opt_str(conn, LDAP_OPT_X_TLS_KEYFILE,
+ set->tls_key_file, "tls_key_file") < 0)
+ return -1;
+ if (db_ldap_set_opt_str(conn, LDAP_OPT_X_TLS_CIPHER_SUITE,
+ set->tls_cipher_suite, "tls_cipher_suite") < 0)
+ return -1;
+ if (set->tls_require_cert != NULL) {
+ if (db_ldap_set_opt(conn, LDAP_OPT_X_TLS_REQUIRE_CERT,
+ &set->ldap_tls_require_cert,
+ "tls_require_cert", set->tls_require_cert) < 0)
+ return -1;
+ }
+#else
+ if (set->tls_ca_cert_file != NULL ||
+ set->tls_ca_cert_dir != NULL ||
+ set->tls_cert_file != NULL ||
+ set->tls_key_file != NULL ||
+ set->tls_cipher_suite != NULL) {
+ e_warning(&conn->lstorage->storage, "db: "
+ "tls_* settings ignored, "
+ "your LDAP library doesn't seem to support them");
+ }
+#endif
+ return 0;
+}
+
+static int db_ldap_set_options(struct ldap_connection *conn)
+{
+ const struct sieve_ldap_storage_settings *set = &conn->lstorage->set;
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ unsigned int ldap_version;
+ int value;
+
+ if (db_ldap_set_opt(conn, LDAP_OPT_DEREF, &set->ldap_deref,
+ "deref", set->deref) < 0)
+ return -1;
+#ifdef LDAP_OPT_DEBUG_LEVEL
+ if (str_to_int(set->debug_level, &value) >= 0 && value != 0) {
+ if (db_ldap_set_opt(conn, LDAP_OPT_DEBUG_LEVEL, &value,
+ "debug_level", set->debug_level) < 0)
+ return -1;
+ }
+#endif
+
+ if (set->ldap_version < 3) {
+ if (set->sasl_bind) {
+ e_error(storage->event,
+ "db: sasl_bind=yes requires ldap_version=3");
+ return -1;
+ }
+ if (set->tls) {
+ e_error(storage->event,
+ "db: tls=yes requires ldap_version=3");
+ return -1;
+ }
+ }
+
+ ldap_version = set->ldap_version;
+ if (db_ldap_set_opt(conn, LDAP_OPT_PROTOCOL_VERSION, &ldap_version,
+ "protocol_version", dec2str(ldap_version)) < 0)
+ return -1;
+ if (db_ldap_set_tls_options(conn) < 0)
+ return -1;
+ return 0;
+}
+
+int sieve_ldap_db_connect(struct ldap_connection *conn)
+{
+ const struct sieve_ldap_storage_settings *set = &conn->lstorage->set;
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ struct timeval start, end;
+ int debug_level;
+ bool debug;
+#if defined(HAVE_LDAP_SASL) || defined(LDAP_HAVE_START_TLS_S)
+ int ret;
+#endif
+
+ if (conn->conn_state != LDAP_CONN_STATE_DISCONNECTED)
+ return 0;
+
+ debug = FALSE;
+ if (str_to_int(set->debug_level, &debug_level) >= 0)
+ debug = debug_level > 0;
+
+ if (debug)
+ i_gettimeofday(&start);
+ i_assert(conn->pending_count == 0);
+ if (conn->ld == NULL) {
+ if (set->uris != NULL) {
+#ifdef LDAP_HAVE_INITIALIZE
+ if (ldap_initialize(&conn->ld, set->uris) != LDAP_SUCCESS)
+ conn->ld = NULL;
+#else
+ e_error(storage->event, "db: "
+ "Your LDAP library doesn't support "
+ "'uris' setting, use 'hosts' instead.");
+ return -1;
+#endif
+ } else
+ conn->ld = ldap_init(set->hosts, LDAP_PORT);
+
+ if (conn->ld == NULL) {
+ e_error(storage->event, "db: "
+ "ldap_init() failed with hosts: %s", set->hosts);
+ return -1;
+ }
+
+ if (db_ldap_set_options(conn) < 0)
+ return -1;
+ }
+
+ if (set->tls) {
+#ifdef LDAP_HAVE_START_TLS_S
+ ret = ldap_start_tls_s(conn->ld, NULL, NULL);
+ if (ret != LDAP_SUCCESS) {
+ if (ret == LDAP_OPERATIONS_ERROR &&
+ set->uris != NULL &&
+ str_begins(set->uris, "ldaps:")) {
+ e_error(storage->event, "db: "
+ "Don't use both tls=yes and ldaps URI");
+ }
+ e_error(storage->event, "db: "
+ "ldap_start_tls_s() failed: %s",
+ ldap_err2string(ret));
+ return -1;
+ }
+#else
+ e_error(storage->event, "db: "
+ "Your LDAP library doesn't support TLS");
+ return -1;
+#endif
+ }
+
+ if (set->sasl_bind) {
+#ifdef HAVE_LDAP_SASL
+ struct db_ldap_sasl_bind_context context;
+
+ i_zero(&context);
+ context.authcid = set->dn;
+ context.passwd = set->dnpass;
+ context.realm = set->sasl_realm;
+ context.authzid = set->sasl_authz_id;
+
+ /* There doesn't seem to be a way to do SASL binding
+ asynchronously.. */
+ ret = ldap_sasl_interactive_bind_s(conn->ld, NULL,
+ set->sasl_mech,
+ NULL, NULL, LDAP_SASL_QUIET,
+ sasl_interact, &context);
+ if (db_ldap_connect_finish(conn, ret) < 0)
+ return -1;
+#else
+ e_error(storage->event, "db: "
+ "sasl_bind=yes but no SASL support compiled in");
+ return -1;
+#endif
+ conn->conn_state = LDAP_CONN_STATE_BOUND;
+ } else {
+ if (db_ldap_bind(conn) < 0)
+ return -1;
+ }
+ if (debug) {
+ i_gettimeofday(&end);
+ int msecs = timeval_diff_msecs(&end, &start);
+ e_debug(storage->event, "db: "
+ "Initialization took %d msecs", msecs);
+ }
+
+ if (db_ldap_get_fd(conn) < 0)
+ return -1;
+ conn->io = io_add(conn->fd, IO_READ, ldap_input, conn);
+ return 0;
+}
+
+void db_ldap_enable_input(struct ldap_connection *conn, bool enable)
+{
+ if (!enable) {
+ io_remove(&conn->io);
+ } else {
+ if (conn->io == NULL && conn->fd != -1) {
+ conn->io = io_add(conn->fd, IO_READ, ldap_input, conn);
+ ldap_input(conn);
+ }
+ }
+}
+
+static void db_ldap_disconnect_timeout(struct ldap_connection *conn)
+{
+ db_ldap_abort_requests(conn, UINT_MAX,
+ DB_LDAP_REQUEST_DISCONNECT_TIMEOUT_SECS, FALSE,
+ "Aborting (timeout), we're not connected to LDAP server");
+
+ if (aqueue_count(conn->request_queue) == 0) {
+ /* no requests left, remove this timeout handler */
+ timeout_remove(&conn->to);
+ }
+}
+
+static void db_ldap_conn_close(struct ldap_connection *conn)
+{
+ struct ldap_request *const *requests, *request;
+ unsigned int i;
+
+ conn->conn_state = LDAP_CONN_STATE_DISCONNECTED;
+ conn->default_bind_msgid = -1;
+
+ timeout_remove(&conn->to);
+
+ if (conn->pending_count != 0) {
+ requests = array_idx(&conn->request_array, 0);
+ for (i = 0; i < conn->pending_count; i++) {
+ request = requests[aqueue_idx(conn->request_queue, i)];
+
+ i_assert(request->msgid != -1);
+ request->msgid = -1;
+ }
+ conn->pending_count = 0;
+ }
+
+ if (conn->ld != NULL) {
+ ldap_unbind(conn->ld);
+ conn->ld = NULL;
+ }
+ conn->fd = -1;
+
+ /* the fd may have already been closed before ldap_unbind(),
+ so we'll have to use io_remove_closed(). */
+ io_remove_closed(&conn->io);
+
+ if (aqueue_count(conn->request_queue) > 0) {
+ conn->to = timeout_add(DB_LDAP_REQUEST_DISCONNECT_TIMEOUT_SECS *
+ 1000/2, db_ldap_disconnect_timeout, conn);
+ }
+}
+
+struct ldap_field_find_context {
+ ARRAY_TYPE(string) attr_names;
+ pool_t pool;
+};
+
+#define IS_LDAP_ESCAPED_CHAR(c) \
+ ((c) == '*' || (c) == '(' || (c) == ')' || (c) == '\\')
+
+const char *ldap_escape(const char *str)
+{
+ const char *p;
+ string_t *ret;
+
+ for (p = str; *p != '\0'; p++) {
+ if (IS_LDAP_ESCAPED_CHAR(*p))
+ break;
+ }
+
+ if (*p == '\0')
+ return str;
+
+ ret = t_str_new((size_t) (p - str) + 64);
+ str_append_data(ret, str, (size_t) (p - str));
+
+ for (; *p != '\0'; p++) {
+ if (IS_LDAP_ESCAPED_CHAR(*p))
+ str_append_c(ret, '\\');
+ str_append_c(ret, *p);
+ }
+ return str_c(ret);
+}
+
+struct ldap_connection *
+sieve_ldap_db_init(struct sieve_ldap_storage *lstorage)
+{
+ struct ldap_connection *conn;
+ pool_t pool;
+
+ pool = pool_alloconly_create("ldap_connection", 1024);
+ conn = p_new(pool, struct ldap_connection, 1);
+ conn->pool = pool;
+ conn->refcount = 1;
+ conn->lstorage = lstorage;
+
+ conn->conn_state = LDAP_CONN_STATE_DISCONNECTED;
+ conn->default_bind_msgid = -1;
+ conn->fd = -1;
+
+ i_array_init(&conn->request_array, 512);
+ conn->request_queue = aqueue_init(&conn->request_array.arr);
+
+ conn->next = ldap_connections;
+ ldap_connections = conn;
+ return conn;
+}
+
+void sieve_ldap_db_unref(struct ldap_connection **_conn)
+{
+ struct ldap_connection *conn = *_conn;
+ struct ldap_connection **p;
+
+ *_conn = NULL;
+ i_assert(conn->refcount >= 0);
+ if (--conn->refcount > 0)
+ return;
+
+ for (p = &ldap_connections; *p != NULL; p = &(*p)->next) {
+ if (*p == conn) {
+ *p = conn->next;
+ break;
+ }
+ }
+
+ db_ldap_abort_requests(conn, UINT_MAX, 0, FALSE, "Shutting down");
+ i_assert(conn->pending_count == 0);
+ db_ldap_conn_close(conn);
+ i_assert(conn->to == NULL);
+
+ array_free(&conn->request_array);
+ aqueue_deinit(&conn->request_queue);
+
+ pool_unref(&conn->pool);
+}
+
+static void db_ldap_switch_ioloop(struct ldap_connection *conn)
+{
+ if (conn->to != NULL)
+ conn->to = io_loop_move_timeout(&conn->to);
+ if (conn->io != NULL)
+ conn->io = io_loop_move_io(&conn->io);
+}
+
+static void db_ldap_wait(struct ldap_connection *conn)
+{
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ struct ioloop *prev_ioloop = current_ioloop;
+
+ i_assert(conn->ioloop == NULL);
+
+ if (aqueue_count(conn->request_queue) == 0)
+ return;
+
+ conn->ioloop = io_loop_create();
+ db_ldap_switch_ioloop(conn);
+ /* either we're waiting for network I/O or we're getting out of a
+ callback using timeout_add_short(0) */
+ i_assert(io_loop_have_ios(conn->ioloop) ||
+ io_loop_have_immediate_timeouts(conn->ioloop));
+
+ do {
+ e_debug(storage->event, "db: "
+ "Waiting for %d requests to finish",
+ aqueue_count(conn->request_queue) );
+ io_loop_run(conn->ioloop);
+ } while (aqueue_count(conn->request_queue) > 0);
+
+ e_debug(storage->event, "db: All requests finished");
+
+ current_ioloop = prev_ioloop;
+ db_ldap_switch_ioloop(conn);
+ current_ioloop = conn->ioloop;
+ io_loop_destroy(&conn->ioloop);
+}
+
+static void sieve_ldap_db_script_free(unsigned char *script)
+{
+ i_free(script);
+}
+
+static int
+sieve_ldap_db_get_script_modattr(struct ldap_connection *conn,
+ LDAPMessage *entry, pool_t pool, const char **modattr_r)
+{
+ const struct sieve_ldap_storage_settings *set = &conn->lstorage->set;
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ char *attr, **vals;
+ BerElement *ber;
+
+ *modattr_r = NULL;
+
+ attr = ldap_first_attribute(conn->ld, entry, &ber);
+ while (attr != NULL) {
+ if (strcmp(attr, set->sieve_ldap_mod_attr) == 0) {
+ vals = ldap_get_values(conn->ld, entry, attr);
+ if (vals == NULL || vals[0] == NULL)
+ return 0;
+
+ if (vals[1] != NULL) {
+ e_warning(storage->event, "db: "
+ "Search returned more than one Sieve modified attribute `%s'; "
+ "using only the first one.", set->sieve_ldap_mod_attr);
+ }
+
+ *modattr_r = p_strdup(pool, vals[0]);
+
+ ldap_value_free(vals);
+ ldap_memfree(attr);
+ return 1;
+ }
+ ldap_memfree(attr);
+ attr = ldap_next_attribute(conn->ld, entry, ber);
+ }
+ ber_free(ber, 0);
+
+ return 0;
+}
+
+static int
+sieve_ldap_db_get_script(struct ldap_connection *conn,
+ LDAPMessage *entry, struct istream **script_r)
+{
+ const struct sieve_ldap_storage_settings *set = &conn->lstorage->set;
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ char *attr;
+ unsigned char *data;
+ size_t size;
+ struct berval **vals;
+ BerElement *ber;
+
+ attr = ldap_first_attribute(conn->ld, entry, &ber);
+ while (attr != NULL) {
+ if (strcmp(attr, set->sieve_ldap_script_attr) == 0) {
+ vals = ldap_get_values_len(conn->ld, entry, attr);
+ if (vals == NULL || vals[0] == NULL)
+ return 0;
+
+ if (vals[1] != NULL) {
+ e_warning(storage->event, "db: "
+ "Search returned more than one Sieve script attribute `%s'; "
+ "using only the first one.", set->sieve_ldap_script_attr);
+ }
+
+ size = vals[0]->bv_len;
+ data = i_malloc(size);
+
+ e_debug(storage->event, "db: "
+ "Found script with length %zu", size);
+
+ memcpy(data, vals[0]->bv_val, size);
+
+ ldap_value_free_len(vals);
+ ldap_memfree(attr);
+
+ *script_r = i_stream_create_from_data(data, size);
+ i_stream_add_destroy_callback
+ (*script_r, sieve_ldap_db_script_free, data);
+ return 1;
+ }
+ ldap_memfree(attr);
+ attr = ldap_next_attribute(conn->ld, entry, ber);
+ }
+ ber_free(ber, 0);
+
+ return 0;
+}
+
+const struct var_expand_table
+auth_request_var_expand_static_tab[] = {
+ { 'u', NULL, "user" },
+ { 'n', NULL, "username" },
+ { 'd', NULL, "domain" },
+ { 'h', NULL, "home" },
+ { '\0', NULL, "name" },
+ { '\0', NULL, NULL }
+};
+
+static const struct var_expand_table *
+db_ldap_get_var_expand_table(struct ldap_connection *conn,
+ const char *name)
+{
+ struct sieve_ldap_storage *lstorage = conn->lstorage;
+ struct sieve_instance *svinst = lstorage->storage.svinst;
+ const unsigned int auth_count =
+ N_ELEMENTS(auth_request_var_expand_static_tab);
+ struct var_expand_table *tab;
+
+ /* keep the extra fields at the beginning. the last static_tab field
+ contains the ending NULL-fields. */
+ tab = t_malloc_no0((auth_count) * sizeof(*tab));
+
+ memcpy(tab, auth_request_var_expand_static_tab,
+ auth_count * sizeof(*tab));
+
+ tab[0].value = ldap_escape(lstorage->username);
+ tab[1].value = ldap_escape(t_strcut(lstorage->username, '@'));
+ tab[2].value = strchr(lstorage->username, '@');
+ if (tab[2].value != NULL)
+ tab[2].value = ldap_escape(tab[2].value+1);
+ tab[3].value = ldap_escape(svinst->home_dir);
+ tab[4].value = ldap_escape(name);
+ return tab;
+}
+
+struct sieve_ldap_script_lookup_request {
+ struct ldap_request request;
+
+ unsigned int entries;
+ const char *result_dn;
+ const char *result_modattr;
+};
+
+static void
+sieve_ldap_lookup_script_callback(struct ldap_connection *conn,
+ struct ldap_request *request, LDAPMessage *res)
+{
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ struct sieve_ldap_script_lookup_request *srequest =
+ (struct sieve_ldap_script_lookup_request *)request;
+
+ if (res == NULL) {
+ io_loop_stop(conn->ioloop);
+ return;
+ }
+
+ if (ldap_msgtype(res) != LDAP_RES_SEARCH_RESULT) {
+ if (srequest->result_dn == NULL) {
+ srequest->result_dn = p_strdup
+ (request->pool, ldap_get_dn(conn->ld, res));
+ (void)sieve_ldap_db_get_script_modattr
+ (conn, res, request->pool, &srequest->result_modattr);
+ } else if (srequest->entries++ == 0) {
+ e_warning(storage->event, "db: "
+ "Search returned more than one entry for Sieve script; "
+ "using only the first one.");
+ }
+ } else {
+ io_loop_stop(conn->ioloop);
+ return;
+ }
+}
+
+int sieve_ldap_db_lookup_script(struct ldap_connection *conn,
+ const char *name, const char **dn_r, const char **modattr_r)
+{
+ struct sieve_ldap_storage *lstorage = conn->lstorage;
+ struct sieve_storage *storage = &lstorage->storage;
+ const struct sieve_ldap_storage_settings *set = &lstorage->set;
+ struct sieve_ldap_script_lookup_request *request;
+ const struct var_expand_table *tab;
+ char **attr_names;
+ const char *error;
+ string_t *str;
+
+ pool_t pool = pool_alloconly_create
+ ("sieve_ldap_script_lookup_request", 512);
+ request = p_new(pool, struct sieve_ldap_script_lookup_request, 1);
+ request->request.pool = pool;
+
+ tab = db_ldap_get_var_expand_table(conn, name);
+
+ str = t_str_new(512);
+ if (var_expand(str, set->base, tab, &error) <= 0) {
+ e_error(storage->event, "db: "
+ "Failed to expand base=%s: %s",
+ set->base, error);
+ return -1;
+ }
+ request->request.base = p_strdup(pool, str_c(str));
+
+ attr_names = p_new(pool, char *, 3);
+ attr_names[0] = p_strdup(pool, set->sieve_ldap_mod_attr);
+
+ str_truncate(str, 0);
+ if (var_expand(str, set->sieve_ldap_filter, tab, &error) <= 0) {
+ e_error(storage->event, "db: "
+ "Failed to expand sieve_ldap_filter=%s: %s",
+ set->sieve_ldap_filter, error);
+ return -1;
+ }
+
+ request->request.scope = lstorage->set.ldap_scope;
+ request->request.filter = p_strdup(pool, str_c(str));
+ request->request.attributes = attr_names;
+
+ e_debug(storage->event, "base=%s scope=%s filter=%s fields=%s",
+ request->request.base, lstorage->set.scope,
+ request->request.filter,
+ t_strarray_join((const char **)attr_names, ","));
+
+ request->request.callback = sieve_ldap_lookup_script_callback;
+ db_ldap_request(conn, &request->request);
+ db_ldap_wait(conn);
+
+ *dn_r = t_strdup(request->result_dn);
+ *modattr_r = t_strdup(request->result_modattr);
+ pool_unref(&request->request.pool);
+ return (*dn_r == NULL ? 0 : 1);
+}
+
+struct sieve_ldap_script_read_request {
+ struct ldap_request request;
+
+ unsigned int entries;
+ struct istream *result;
+};
+
+static void
+sieve_ldap_read_script_callback(struct ldap_connection *conn,
+ struct ldap_request *request, LDAPMessage *res)
+{
+ struct sieve_storage *storage = &conn->lstorage->storage;
+ struct sieve_ldap_script_read_request *srequest =
+ (struct sieve_ldap_script_read_request *)request;
+
+ if (res == NULL) {
+ io_loop_stop(conn->ioloop);
+ return;
+ }
+
+ if (ldap_msgtype(res) != LDAP_RES_SEARCH_RESULT) {
+
+ if (srequest->result == NULL) {
+ (void)sieve_ldap_db_get_script(conn, res, &srequest->result);
+ } else {
+ e_error(storage->event, "db: "
+ "Search returned more than one entry for Sieve script DN");
+ i_stream_unref(&srequest->result);
+ }
+
+ } else {
+ io_loop_stop(conn->ioloop);
+ return;
+ }
+}
+
+int sieve_ldap_db_read_script(struct ldap_connection *conn,
+ const char *dn, struct istream **script_r)
+{
+ struct sieve_ldap_storage *lstorage = conn->lstorage;
+ struct sieve_storage *storage = &lstorage->storage;
+ const struct sieve_ldap_storage_settings *set = &lstorage->set;
+ struct sieve_ldap_script_read_request *request;
+ char **attr_names;
+
+ pool_t pool = pool_alloconly_create
+ ("sieve_ldap_script_read_request", 512);
+ request = p_new(pool, struct sieve_ldap_script_read_request, 1);
+ request->request.pool = pool;
+ request->request.base = p_strdup(pool, dn);
+
+ attr_names = p_new(pool, char *, 3);
+ attr_names[0] = p_strdup(pool, set->sieve_ldap_script_attr);
+
+ request->request.scope = LDAP_SCOPE_BASE;
+ request->request.filter = "(objectClass=*)";
+ request->request.attributes = attr_names;
+
+ e_debug(storage->event, "base=%s scope=base filter=%s fields=%s",
+ request->request.base, request->request.filter,
+ t_strarray_join((const char **)attr_names, ","));
+
+ request->request.callback = sieve_ldap_read_script_callback;
+ db_ldap_request(conn, &request->request);
+ db_ldap_wait(conn);
+
+ *script_r = request->result;
+ pool_unref(&request->request.pool);
+ return (*script_r == NULL ? 0 : 1);
+}
+
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-db.h b/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-db.h
new file mode 100644
index 0000000..d213026
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-db.h
@@ -0,0 +1,140 @@
+#ifndef DB_LDAP_H
+#define DB_LDAP_H
+
+/* Functions like ldap_bind() have been deprecated in OpenLDAP 2.3
+ This define enables them until the code here can be refactored */
+#define LDAP_DEPRECATED 1
+
+/* Maximum number of pending requests before delaying new requests. */
+#define DB_LDAP_MAX_PENDING_REQUESTS 8
+/* If LDAP connection is down, fail requests after waiting for this long. */
+#define DB_LDAP_REQUEST_DISCONNECT_TIMEOUT_SECS 4
+/* If request is still in queue after this many seconds and other requests
+ have been replied, assume the request was lost and abort it. */
+#define DB_LDAP_REQUEST_LOST_TIMEOUT_SECS 60
+/* If server disconnects us, don't reconnect if no requests have been sent
+ for this many seconds. */
+#define DB_LDAP_IDLE_RECONNECT_SECS 60
+
+#include <ldap.h>
+
+#define HAVE_LDAP_SASL
+#ifdef HAVE_SASL_SASL_H
+# include <sasl/sasl.h>
+#elif defined (HAVE_SASL_H)
+# include <sasl.h>
+#else
+# undef HAVE_LDAP_SASL
+#endif
+#ifdef LDAP_OPT_X_TLS
+# define OPENLDAP_TLS_OPTIONS
+#endif
+#if !defined(SASL_VERSION_MAJOR) || SASL_VERSION_MAJOR < 2
+# undef HAVE_LDAP_SASL
+#endif
+
+#ifndef LDAP_SASL_QUIET
+# define LDAP_SASL_QUIET 0 /* Doesn't exist in Solaris LDAP */
+#endif
+
+/* Older versions may require calling ldap_result() twice */
+#if LDAP_VENDOR_VERSION <= 20112
+# define OPENLDAP_ASYNC_WORKAROUND
+#endif
+
+/* Solaris LDAP library doesn't have LDAP_OPT_SUCCESS */
+#ifndef LDAP_OPT_SUCCESS
+# define LDAP_OPT_SUCCESS LDAP_SUCCESS
+#endif
+
+struct ldap_connection;
+struct ldap_request;
+
+typedef void db_search_callback_t(struct ldap_connection *conn,
+ struct ldap_request *request,
+ LDAPMessage *res);
+struct ldap_request {
+ pool_t pool;
+
+ /* msgid for sent requests, -1 if not sent */
+ int msgid;
+ /* timestamp when request was created */
+ time_t create_time;
+
+ bool failed;
+
+ db_search_callback_t *callback;
+
+ const char *base;
+ const char *filter;
+ int scope;
+ char **attributes;
+
+ struct db_ldap_result *result;
+};
+
+enum ldap_connection_state {
+ /* Not connected */
+ LDAP_CONN_STATE_DISCONNECTED,
+ /* Binding - either to default dn or doing auth bind */
+ LDAP_CONN_STATE_BINDING,
+ /* Bound */
+ LDAP_CONN_STATE_BOUND
+};
+
+struct ldap_connection {
+ struct ldap_connection *next;
+
+ struct sieve_ldap_storage *lstorage;
+
+ pool_t pool;
+ int refcount;
+
+ LDAP *ld;
+ enum ldap_connection_state conn_state;
+ int default_bind_msgid;
+
+ int fd;
+ struct io *io;
+ struct timeout *to;
+ struct ioloop *ioloop;
+
+ /* Request queue contains sent requests at tail (msgid != -1) and
+ queued requests at head (msgid == -1). */
+ struct aqueue *request_queue;
+ ARRAY(struct ldap_request *) request_array;
+ /* Number of messages in queue with msgid != -1 */
+ unsigned int pending_count;
+
+ /* Timestamp when we last received a reply */
+ time_t last_reply_stamp;
+};
+
+
+int ldap_deref_from_str(const char *str, int *deref_r);
+int ldap_scope_from_str(const char *str, int *scope_r);
+#ifdef OPENLDAP_TLS_OPTIONS
+int ldap_tls_require_cert_from_str(const char *str, int *opt_x_tls_r);
+#endif
+
+/* Send/queue request */
+void db_ldap_request(struct ldap_connection *conn,
+ struct ldap_request *request);
+
+void db_ldap_enable_input(struct ldap_connection *conn, bool enable);
+
+const char *ldap_escape(const char *str);
+const char *ldap_get_error(struct ldap_connection *conn);
+
+int sieve_ldap_db_connect(struct ldap_connection *conn);
+
+struct ldap_connection *
+sieve_ldap_db_init(struct sieve_ldap_storage *lstorage);
+void sieve_ldap_db_unref(struct ldap_connection **conn);
+
+int sieve_ldap_db_lookup_script(struct ldap_connection *conn,
+ const char *name, const char **dn_r, const char **modattr_r);
+int sieve_ldap_db_read_script(struct ldap_connection *conn,
+ const char *dn, struct istream **script_r);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-script.c b/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-script.c
new file mode 100644
index 0000000..1c732db
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-script.c
@@ -0,0 +1,369 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "time-util.h"
+#include "istream.h"
+
+#include "sieve-ldap-storage.h"
+
+#if defined(SIEVE_BUILTIN_LDAP) || defined(PLUGIN_BUILD)
+
+#include "str.h"
+#include "strfuncs.h"
+
+#include "sieve-error.h"
+#include "sieve-dump.h"
+#include "sieve-binary.h"
+
+/*
+ * Script file implementation
+ */
+
+static struct sieve_ldap_script *sieve_ldap_script_alloc(void)
+{
+ struct sieve_ldap_script *lscript;
+ pool_t pool;
+
+ pool = pool_alloconly_create("sieve_ldap_script", 1024);
+ lscript = p_new(pool, struct sieve_ldap_script, 1);
+ lscript->script = sieve_ldap_script;
+ lscript->script.pool = pool;
+
+ return lscript;
+}
+
+struct sieve_ldap_script *sieve_ldap_script_init
+(struct sieve_ldap_storage *lstorage, const char *name)
+{
+ struct sieve_storage *storage = &lstorage->storage;
+ struct sieve_ldap_script *lscript = NULL;
+ const char *location;
+
+ if ( name == NULL ) {
+ name = SIEVE_LDAP_SCRIPT_DEFAULT;
+ location = storage->location;
+ } else {
+ location = t_strconcat
+ (storage->location, ";name=", name, NULL);
+ }
+
+ lscript = sieve_ldap_script_alloc();
+ sieve_script_init(&lscript->script,
+ storage, &sieve_ldap_script, location, name);
+ return lscript;
+}
+
+static int sieve_ldap_script_open
+(struct sieve_script *script, enum sieve_error *error_r)
+{
+ struct sieve_ldap_script *lscript =
+ (struct sieve_ldap_script *)script;
+ struct sieve_storage *storage = script->storage;
+ struct sieve_ldap_storage *lstorage =
+ (struct sieve_ldap_storage *)storage;
+ int ret;
+
+ if ( sieve_ldap_db_connect(lstorage->conn) < 0 ) {
+ sieve_storage_set_critical(storage,
+ "Failed to connect to LDAP database");
+ *error_r = storage->error_code;
+ return -1;
+ }
+
+ if ( (ret=sieve_ldap_db_lookup_script(lstorage->conn,
+ script->name, &lscript->dn, &lscript->modattr)) <= 0 ) {
+ if ( ret == 0 ) {
+ e_debug(script->event, "Script entry not found");
+ sieve_script_set_error(script,
+ SIEVE_ERROR_NOT_FOUND,
+ "Sieve script not found");
+ } else {
+ sieve_script_set_internal_error(script);
+ }
+ *error_r = script->storage->error_code;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int sieve_ldap_script_get_stream
+(struct sieve_script *script, struct istream **stream_r,
+ enum sieve_error *error_r)
+{
+ struct sieve_ldap_script *lscript =
+ (struct sieve_ldap_script *)script;
+ struct sieve_storage *storage = script->storage;
+ struct sieve_ldap_storage *lstorage =
+ (struct sieve_ldap_storage *)storage;
+ int ret;
+
+ i_assert(lscript->dn != NULL);
+
+ if ( (ret=sieve_ldap_db_read_script(
+ lstorage->conn, lscript->dn, stream_r)) <= 0 ) {
+ if ( ret == 0 ) {
+ e_debug(script->event, "Script attribute not found");
+ sieve_script_set_error(script,
+ SIEVE_ERROR_NOT_FOUND,
+ "Sieve script not found");
+ } else {
+ sieve_script_set_internal_error(script);
+ }
+ *error_r = script->storage->error_code;
+ return -1;
+ }
+ return 0;
+}
+
+static int sieve_ldap_script_binary_read_metadata
+(struct sieve_script *script, struct sieve_binary_block *sblock,
+ sieve_size_t *offset)
+{
+ struct sieve_ldap_script *lscript =
+ (struct sieve_ldap_script *)script;
+ struct sieve_instance *svinst = script->storage->svinst;
+ struct sieve_ldap_storage *lstorage =
+ (struct sieve_ldap_storage *)script->storage;
+ struct sieve_binary *sbin =
+ sieve_binary_block_get_binary(sblock);
+ time_t bmtime = sieve_binary_mtime(sbin);
+ string_t *dn, *modattr;
+
+ /* config file changed? */
+ if ( bmtime <= lstorage->set_mtime ) {
+ if ( svinst->debug ) {
+ e_debug(script->event,
+ "Sieve binary `%s' is not newer "
+ "than the LDAP configuration `%s' (%s <= %s)",
+ sieve_binary_path(sbin), lstorage->config_file,
+ t_strflocaltime("%Y-%m-%d %H:%M:%S", bmtime),
+ t_strflocaltime("%Y-%m-%d %H:%M:%S", lstorage->set_mtime));
+ }
+ return 0;
+ }
+
+ /* open script if not open already */
+ if ( lscript->dn == NULL &&
+ sieve_script_open(script, NULL) < 0 )
+ return 0;
+
+ /* if modattr not found, recompile always */
+ if ( lscript->modattr == NULL || *lscript->modattr == '\0' ) {
+ e_error(script->event,
+ "LDAP entry for script `%s' "
+ "has no modified attribute `%s'",
+ sieve_script_location(script),
+ lstorage->set.sieve_ldap_mod_attr);
+ return 0;
+ }
+
+ /* compare DN in binary and from search result */
+ if ( !sieve_binary_read_string(sblock, offset, &dn) ) {
+ e_error(script->event,
+ "Binary `%s' has invalid metadata for script `%s': "
+ "Invalid DN",
+ sieve_binary_path(sbin), sieve_script_location(script));
+ return -1;
+ }
+ i_assert( lscript->dn != NULL );
+ if ( strcmp(str_c(dn), lscript->dn) != 0 ) {
+ e_debug(script->event,
+ "Binary `%s' reports different LDAP DN for script `%s' "
+ "(`%s' rather than `%s')",
+ sieve_binary_path(sbin), sieve_script_location(script),
+ str_c(dn), lscript->dn);
+ return 0;
+ }
+
+ /* compare modattr in binary and from search result */
+ if ( !sieve_binary_read_string(sblock, offset, &modattr) ) {
+ e_error(script->event,
+ "Binary `%s' has invalid metadata for script `%s': "
+ "Invalid modified attribute",
+ sieve_binary_path(sbin), sieve_script_location(script));
+ return -1;
+ }
+ if ( strcmp(str_c(modattr), lscript->modattr) != 0 ) {
+ e_debug(script->event,
+ "Binary `%s' reports different modified attribute content "
+ "for script `%s' (`%s' rather than `%s')",
+ sieve_binary_path(sbin), sieve_script_location(script),
+ str_c(modattr), lscript->modattr);
+ return 0;
+ }
+ return 1;
+}
+
+static void sieve_ldap_script_binary_write_metadata
+(struct sieve_script *script, struct sieve_binary_block *sblock)
+{
+ struct sieve_ldap_script *lscript =
+ (struct sieve_ldap_script *)script;
+
+ sieve_binary_emit_cstring(sblock, lscript->dn);
+ if (lscript->modattr == NULL)
+ sieve_binary_emit_cstring(sblock, "");
+ else
+ sieve_binary_emit_cstring(sblock, lscript->modattr);
+}
+
+static bool sieve_ldap_script_binary_dump_metadata
+(struct sieve_script *script ATTR_UNUSED, struct sieve_dumptime_env *denv,
+ struct sieve_binary_block *sblock, sieve_size_t *offset)
+{
+ string_t *dn, *modattr;
+
+ if ( !sieve_binary_read_string(sblock, offset, &dn) )
+ return FALSE;
+ sieve_binary_dumpf(denv, "ldap.dn = %s\n", str_c(dn));
+
+ if ( !sieve_binary_read_string(sblock, offset, &modattr) )
+ return FALSE;
+ sieve_binary_dumpf(denv, "ldap.mod_attr = %s\n", str_c(modattr));
+
+ return TRUE;
+}
+
+static const char *sieve_ldap_script_get_binpath
+(struct sieve_ldap_script *lscript)
+{
+ struct sieve_script *script = &lscript->script;
+ struct sieve_storage *storage = script->storage;
+
+ if ( lscript->binpath == NULL ) {
+ if ( storage->bin_dir == NULL )
+ return NULL;
+ lscript->binpath = p_strconcat(script->pool,
+ storage->bin_dir, "/",
+ sieve_binfile_from_name(script->name), NULL);
+ }
+
+ return lscript->binpath;
+}
+
+static struct sieve_binary *sieve_ldap_script_binary_load
+(struct sieve_script *script, enum sieve_error *error_r)
+{
+ struct sieve_storage *storage = script->storage;
+ struct sieve_ldap_script *lscript =
+ (struct sieve_ldap_script *)script;
+
+ if ( sieve_ldap_script_get_binpath(lscript) == NULL )
+ return NULL;
+
+ return sieve_binary_open(storage->svinst,
+ lscript->binpath, script, error_r);
+}
+
+static int sieve_ldap_script_binary_save
+(struct sieve_script *script, struct sieve_binary *sbin, bool update,
+ enum sieve_error *error_r)
+{
+ struct sieve_ldap_script *lscript =
+ (struct sieve_ldap_script *)script;
+
+ if ( sieve_ldap_script_get_binpath(lscript) == NULL )
+ return 0;
+
+ if ( sieve_storage_setup_bindir(script->storage, 0700) < 0 )
+ return -1;
+
+ return sieve_binary_save
+ (sbin, lscript->binpath, update, 0600, error_r);
+}
+
+static bool sieve_ldap_script_equals
+(const struct sieve_script *script, const struct sieve_script *other)
+{
+ struct sieve_storage *storage = script->storage;
+ struct sieve_storage *sother = other->storage;
+
+ if ( strcmp(storage->location, sother->location) != 0 )
+ return FALSE;
+
+ i_assert( script->name != NULL && other->name != NULL );
+
+ return ( strcmp(script->name, other->name) == 0 );
+}
+
+const struct sieve_script sieve_ldap_script = {
+ .driver_name = SIEVE_LDAP_STORAGE_DRIVER_NAME,
+ .v = {
+ .open = sieve_ldap_script_open,
+
+ .get_stream = sieve_ldap_script_get_stream,
+
+ .binary_read_metadata = sieve_ldap_script_binary_read_metadata,
+ .binary_write_metadata = sieve_ldap_script_binary_write_metadata,
+ .binary_dump_metadata = sieve_ldap_script_binary_dump_metadata,
+ .binary_load = sieve_ldap_script_binary_load,
+ .binary_save = sieve_ldap_script_binary_save,
+
+ .equals = sieve_ldap_script_equals
+ }
+};
+
+/*
+ * Script sequence
+ */
+
+struct sieve_ldap_script_sequence {
+ struct sieve_script_sequence seq;
+
+ bool done:1;
+};
+
+struct sieve_script_sequence *sieve_ldap_storage_get_script_sequence
+(struct sieve_storage *storage, enum sieve_error *error_r)
+{
+ struct sieve_ldap_script_sequence *lsec = NULL;
+
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_NONE;
+
+ /* Create sequence object */
+ lsec = i_new(struct sieve_ldap_script_sequence, 1);
+ sieve_script_sequence_init(&lsec->seq, storage);
+
+ return &lsec->seq;
+}
+
+struct sieve_script *sieve_ldap_script_sequence_next
+(struct sieve_script_sequence *seq, enum sieve_error *error_r)
+{
+ struct sieve_ldap_script_sequence *lsec =
+ (struct sieve_ldap_script_sequence *)seq;
+ struct sieve_ldap_storage *lstorage =
+ (struct sieve_ldap_storage *)seq->storage;
+ struct sieve_ldap_script *lscript;
+
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_NONE;
+
+ if ( lsec->done )
+ return NULL;
+ lsec->done = TRUE;
+
+ lscript = sieve_ldap_script_init
+ (lstorage, seq->storage->script_name);
+ if ( sieve_script_open(&lscript->script, error_r) < 0 ) {
+ struct sieve_script *script = &lscript->script;
+ sieve_script_unref(&script);
+ return NULL;
+ }
+
+ return &lscript->script;
+}
+
+void sieve_ldap_script_sequence_destroy
+(struct sieve_script_sequence *seq)
+{
+ struct sieve_ldap_script_sequence *lsec =
+ (struct sieve_ldap_script_sequence *)seq;
+ i_free(lsec);
+}
+
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-storage-settings.c b/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-storage-settings.c
new file mode 100644
index 0000000..35fe5cb
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-storage-settings.c
@@ -0,0 +1,169 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "env-util.h"
+#include "settings.h"
+
+#include "sieve-common.h"
+
+#include "sieve-ldap-storage.h"
+
+#if defined(SIEVE_BUILTIN_LDAP) || defined(PLUGIN_BUILD)
+
+#include "sieve-error.h"
+
+#include "sieve-ldap-db.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define DEF_STR(name) DEF_STRUCT_STR(name, sieve_ldap_storage_settings)
+#define DEF_INT(name) DEF_STRUCT_INT(name, sieve_ldap_storage_settings)
+#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, sieve_ldap_storage_settings)
+
+static struct setting_def setting_defs[] = {
+ DEF_STR(hosts),
+ DEF_STR(uris),
+ DEF_STR(dn),
+ DEF_STR(dnpass),
+ DEF_BOOL(tls),
+ DEF_BOOL(sasl_bind),
+ DEF_STR(sasl_mech),
+ DEF_STR(sasl_realm),
+ DEF_STR(sasl_authz_id),
+ DEF_STR(tls_ca_cert_file),
+ DEF_STR(tls_ca_cert_dir),
+ DEF_STR(tls_cert_file),
+ DEF_STR(tls_key_file),
+ DEF_STR(tls_cipher_suite),
+ DEF_STR(tls_require_cert),
+ DEF_STR(deref),
+ DEF_STR(scope),
+ DEF_STR(base),
+ DEF_INT(ldap_version),
+ DEF_STR(debug_level),
+ DEF_STR(ldaprc_path),
+ DEF_STR(sieve_ldap_script_attr),
+ DEF_STR(sieve_ldap_mod_attr),
+ DEF_STR(sieve_ldap_filter),
+
+ { 0, NULL, 0 }
+};
+
+static struct sieve_ldap_storage_settings default_settings = {
+ .hosts = NULL,
+ .uris = NULL,
+ .dn = NULL,
+ .dnpass = NULL,
+ .tls = FALSE,
+ .sasl_bind = FALSE,
+ .sasl_mech = NULL,
+ .sasl_realm = NULL,
+ .sasl_authz_id = NULL,
+ .tls_ca_cert_file = NULL,
+ .tls_ca_cert_dir = NULL,
+ .tls_cert_file = NULL,
+ .tls_key_file = NULL,
+ .tls_cipher_suite = NULL,
+ .tls_require_cert = NULL,
+ .deref = "never",
+ .scope = "subtree",
+ .base = NULL,
+ .ldap_version = 3,
+ .debug_level = "0",
+ .ldaprc_path = "",
+ .sieve_ldap_script_attr = "mailSieveRuleSource",
+ .sieve_ldap_mod_attr = "modifyTimestamp",
+ .sieve_ldap_filter = "(&(objectClass=posixAccount)(uid=%u))",
+};
+
+static const char *parse_setting(const char *key, const char *value,
+ struct sieve_ldap_storage *lstorage)
+{
+ return parse_setting_from_defs
+ (lstorage->storage.pool, setting_defs, &lstorage->set, key, value);
+}
+
+int sieve_ldap_storage_read_settings
+(struct sieve_ldap_storage *lstorage, const char *config_path)
+{
+ struct sieve_storage *storage = &lstorage->storage;
+ const char *str, *error;
+ struct stat st;
+
+ if ( stat(config_path, &st) < 0 ) {
+ e_error(storage->event,
+ "Failed to read LDAP storage config: "
+ "stat(%s) failed: %m", config_path);
+ return -1;
+ }
+
+ lstorage->set = default_settings;
+ lstorage->set_mtime = st.st_mtime;
+
+ if (!settings_read_nosection
+ (config_path, parse_setting, lstorage, &error)) {
+ sieve_storage_set_critical(storage,
+ "Failed to read LDAP storage config `%s': %s",
+ config_path, error);
+ return -1;
+ }
+
+ if (lstorage->set.base == NULL) {
+ sieve_storage_set_critical(storage,
+ "Invalid LDAP storage config `%s': "
+ "No search base given", config_path);
+ return -1;
+ }
+
+ if (lstorage->set.uris == NULL && lstorage->set.hosts == NULL) {
+ sieve_storage_set_critical(storage,
+ "Invalid LDAP storage config `%s': "
+ "No uris or hosts set", config_path);
+ return -1;
+ }
+
+ if (*lstorage->set.ldaprc_path != '\0') {
+ str = getenv("LDAPRC");
+ if (str != NULL && strcmp(str, lstorage->set.ldaprc_path) != 0) {
+ sieve_storage_set_critical(storage,
+ "Invalid LDAP storage config `%s': "
+ "Multiple different ldaprc_path settings not allowed "
+ "(%s and %s)", config_path, str, lstorage->set.ldaprc_path);
+ return -1;
+ }
+ env_put("LDAPRC", lstorage->set.ldaprc_path);
+ }
+
+ if ( ldap_deref_from_str
+ (lstorage->set.deref, &lstorage->set.ldap_deref) < 0 ) {
+ sieve_storage_set_critical(storage,
+ "Invalid LDAP storage config `%s': "
+ "Invalid deref option `%s'",
+ config_path, lstorage->set.deref);;
+ }
+
+ if ( ldap_scope_from_str
+ (lstorage->set.scope, &lstorage->set.ldap_scope) < 0 ) {
+ sieve_storage_set_critical(storage,
+ "Invalid LDAP storage config `%s': "
+ "Invalid scope option `%s'",
+ config_path, lstorage->set.scope);;
+ }
+
+#ifdef OPENLDAP_TLS_OPTIONS
+ if ( lstorage->set.tls_require_cert != NULL &&
+ ldap_tls_require_cert_from_str(lstorage->set.tls_require_cert,
+ &lstorage->set.ldap_tls_require_cert) < 0) {
+ sieve_storage_set_critical(storage,
+ "Invalid LDAP storage config `%s': "
+ "Invalid tls_require_cert option `%s'",
+ config_path, lstorage->set.tls_require_cert);
+ }
+#endif
+ return 0;
+}
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-storage.c b/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-storage.c
new file mode 100644
index 0000000..1f7922a
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-storage.c
@@ -0,0 +1,230 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+//#include "ldap.h"
+
+#include "sieve-common.h"
+
+#include "sieve-ldap-storage.h"
+
+#if defined(SIEVE_BUILTIN_LDAP) || defined(PLUGIN_BUILD)
+
+#include "sieve-error.h"
+
+#ifndef PLUGIN_BUILD
+const struct sieve_storage sieve_ldap_storage;
+#else
+const struct sieve_storage sieve_ldap_storage_plugin;
+#endif
+
+/*
+ * Storage class
+ */
+
+static struct sieve_storage *sieve_ldap_storage_alloc(void)
+{
+ struct sieve_ldap_storage *lstorage;
+ pool_t pool;
+
+ pool = pool_alloconly_create("sieve_ldap_storage", 1024);
+ lstorage = p_new(pool, struct sieve_ldap_storage, 1);
+#ifndef PLUGIN_BUILD
+ lstorage->storage = sieve_ldap_storage;
+#else
+ lstorage->storage = sieve_ldap_storage_plugin;
+#endif
+ lstorage->storage.pool = pool;
+
+ return &lstorage->storage;
+}
+
+static int sieve_ldap_storage_init
+(struct sieve_storage *storage, const char *const *options,
+ enum sieve_error *error_r)
+{
+ struct sieve_ldap_storage *lstorage =
+ (struct sieve_ldap_storage *)storage;
+ struct sieve_instance *svinst = storage->svinst;
+ const char *username = NULL;
+
+ if ( options != NULL ) {
+ while ( *options != NULL ) {
+ const char *option = *options;
+
+ if ( strncasecmp(option, "user=", 5) == 0 && option[5] != '\0' ) {
+ username = option+5;
+ } else {
+ sieve_storage_set_critical(storage,
+ "Invalid option `%s'", option);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+
+ options++;
+ }
+ }
+
+ if ( username == NULL ) {
+ if ( svinst->username == NULL ) {
+ sieve_storage_set_critical(storage,
+ "No username specified");
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+ username = svinst->username;
+ }
+
+ e_debug(storage->event, "user=%s, config=%s",
+ username, storage->location);
+
+ if ( sieve_ldap_storage_read_settings(lstorage, storage->location) < 0 )
+ return -1;
+
+ lstorage->username = p_strdup(storage->pool, username);
+ lstorage->config_file = p_strdup(storage->pool, storage->location);
+ lstorage->conn = sieve_ldap_db_init(lstorage);
+
+ storage->location = p_strconcat(storage->pool,
+ SIEVE_LDAP_STORAGE_DRIVER_NAME, ":", storage->location,
+ ";user=", username, NULL);
+
+ return 0;
+}
+
+static void sieve_ldap_storage_destroy
+(struct sieve_storage *storage)
+{
+ struct sieve_ldap_storage *lstorage =
+ (struct sieve_ldap_storage *)storage;
+
+ if ( lstorage->conn != NULL )
+ sieve_ldap_db_unref(&lstorage->conn);
+}
+
+/*
+ * Script access
+ */
+
+static struct sieve_script *sieve_ldap_storage_get_script
+(struct sieve_storage *storage, const char *name)
+{
+ struct sieve_ldap_storage *lstorage =
+ (struct sieve_ldap_storage *)storage;
+ struct sieve_ldap_script *lscript;
+
+ T_BEGIN {
+ lscript = sieve_ldap_script_init(lstorage, name);
+ } T_END;
+
+ return &lscript->script;
+}
+
+/*
+ * Active script
+ */
+
+struct sieve_script *sieve_ldap_storage_active_script_open
+(struct sieve_storage *storage)
+{
+ struct sieve_ldap_storage *lstorage =
+ (struct sieve_ldap_storage *)storage;
+ struct sieve_ldap_script *lscript;
+
+ lscript = sieve_ldap_script_init
+ (lstorage, storage->script_name);
+ if ( sieve_script_open(&lscript->script, NULL) < 0 ) {
+ struct sieve_script *script = &lscript->script;
+ sieve_script_unref(&script);
+ return NULL;
+ }
+
+ return &lscript->script;
+}
+
+int sieve_ldap_storage_active_script_get_name
+(struct sieve_storage *storage, const char **name_r)
+{
+ if ( storage->script_name != NULL )
+ *name_r = storage->script_name;
+ else
+ *name_r = SIEVE_LDAP_SCRIPT_DEFAULT;
+ return 0;
+}
+
+/*
+ * Driver definition
+ */
+
+#ifndef PLUGIN_BUILD
+const struct sieve_storage sieve_ldap_storage = {
+#else
+const struct sieve_storage sieve_ldap_storage_plugin = {
+#endif
+ .driver_name = SIEVE_LDAP_STORAGE_DRIVER_NAME,
+ .version = 0,
+ .v = {
+ .alloc = sieve_ldap_storage_alloc,
+ .init = sieve_ldap_storage_init,
+ .destroy = sieve_ldap_storage_destroy,
+
+ .get_script = sieve_ldap_storage_get_script,
+
+ .get_script_sequence = sieve_ldap_storage_get_script_sequence,
+ .script_sequence_next = sieve_ldap_script_sequence_next,
+ .script_sequence_destroy = sieve_ldap_script_sequence_destroy,
+
+ .active_script_get_name = sieve_ldap_storage_active_script_get_name,
+ .active_script_open = sieve_ldap_storage_active_script_open,
+
+ // FIXME: impement management interface
+ }
+};
+
+#ifndef SIEVE_BUILTIN_LDAP
+/* Building a plugin */
+
+const char *sieve_storage_ldap_plugin_version = PIGEONHOLE_ABI_VERSION;
+
+void sieve_storage_ldap_plugin_load
+(struct sieve_instance *svinst, void **context);
+void sieve_storage_ldap_plugin_unload
+(struct sieve_instance *svinst, void *context);
+void sieve_storage_ldap_plugin_init(void);
+void sieve_storage_ldap_plugin_deinit(void);
+
+void sieve_storage_ldap_plugin_load
+(struct sieve_instance *svinst, void **context ATTR_UNUSED)
+{
+ sieve_storage_class_register
+ (svinst, &sieve_ldap_storage_plugin);
+
+ e_debug(svinst->event,
+ "Sieve LDAP storage plugin for %s version %s loaded",
+ PIGEONHOLE_NAME, PIGEONHOLE_VERSION_FULL);
+}
+
+void sieve_storage_ldap_plugin_unload
+(struct sieve_instance *svinst ATTR_UNUSED,
+ void *context ATTR_UNUSED)
+{
+ sieve_storage_class_unregister
+ (svinst, &sieve_ldap_storage_plugin);
+}
+
+void sieve_storage_ldap_plugin_init(void)
+{
+ /* Nothing */
+}
+
+void sieve_storage_ldap_plugin_deinit(void)
+{
+ /* Nothing */
+}
+#endif
+
+#else /* !defined(SIEVE_BUILTIN_LDAP) && !defined(PLUGIN_BUILD) */
+const struct sieve_storage sieve_ldap_storage = {
+ .driver_name = SIEVE_LDAP_STORAGE_DRIVER_NAME
+};
+#endif
diff --git a/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-storage.h b/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-storage.h
new file mode 100644
index 0000000..f97ceba
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/ldap/sieve-ldap-storage.h
@@ -0,0 +1,108 @@
+#ifndef SIEVE_LDAP_STORAGE_H
+#define SIEVE_LDAP_STORAGE_H
+
+#include "sieve.h"
+#include "sieve-script-private.h"
+#include "sieve-storage-private.h"
+
+#define SIEVE_LDAP_SCRIPT_DEFAULT "default"
+
+#if defined(SIEVE_BUILTIN_LDAP) || defined(PLUGIN_BUILD)
+
+#include "sieve-ldap-db.h"
+
+struct sieve_ldap_storage;
+
+/*
+ * LDAP settings
+ */
+
+struct sieve_ldap_storage_settings {
+ const char *hosts;
+ const char *uris;
+ const char *dn;
+ const char *dnpass;
+
+ bool tls;
+ bool sasl_bind;
+ const char *sasl_mech;
+ const char *sasl_realm;
+ const char *sasl_authz_id;
+
+ const char *tls_ca_cert_file;
+ const char *tls_ca_cert_dir;
+ const char *tls_cert_file;
+ const char *tls_key_file;
+ const char *tls_cipher_suite;
+ const char *tls_require_cert;
+
+ const char *deref;
+ const char *scope;
+ const char *base;
+ unsigned int ldap_version;
+
+ const char *ldaprc_path;
+ const char *debug_level;
+
+ const char *sieve_ldap_script_attr;
+ const char *sieve_ldap_mod_attr;
+ const char *sieve_ldap_filter;
+
+ /* ... */
+ int ldap_deref, ldap_scope, ldap_tls_require_cert;
+};
+
+int sieve_ldap_storage_read_settings
+ (struct sieve_ldap_storage *lstorage, const char *config_path);
+
+/*
+ * Storage class
+ */
+
+struct sieve_ldap_storage {
+ struct sieve_storage storage;
+
+ struct sieve_ldap_storage_settings set;
+ time_t set_mtime;
+
+ const char *config_file;
+ const char *username; // FIXME: needed?
+
+ struct ldap_connection *conn;
+};
+
+struct sieve_script *sieve_ldap_storage_active_script_open
+ (struct sieve_storage *storage);
+int sieve_ldap_storage_active_script_get_name
+ (struct sieve_storage *storage, const char **name_r);
+
+/*
+ * Script class
+ */
+
+struct sieve_ldap_script {
+ struct sieve_script script;
+
+ const char *dn;
+ const char *modattr;
+
+ const char *binpath;
+};
+
+struct sieve_ldap_script *sieve_ldap_script_init
+ (struct sieve_ldap_storage *lstorage, const char *name);
+
+/*
+ * Script sequence
+ */
+
+struct sieve_script_sequence *sieve_ldap_storage_get_script_sequence
+ (struct sieve_storage *storage, enum sieve_error *error_r);
+
+struct sieve_script *sieve_ldap_script_sequence_next
+ (struct sieve_script_sequence *seq, enum sieve_error *error_r);
+void sieve_ldap_script_sequence_destroy(struct sieve_script_sequence *seq);
+
+#endif
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/tst-address.c b/pigeonhole/src/lib-sieve/tst-address.c
new file mode 100644
index 0000000..086679d
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/tst-address.c
@@ -0,0 +1,280 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-message.h"
+#include "sieve-address.h"
+#include "sieve-address-parts.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-match.h"
+
+#include <stdio.h>
+
+/*
+ * Address test
+ *
+ * Syntax:
+ * address [ADDRESS-PART] [COMPARATOR] [MATCH-TYPE]
+ * <header-list: string-list> <key-list: string-list>
+ */
+
+static bool tst_address_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool tst_address_validate
+ (struct sieve_validator *valdtr, struct sieve_command *tst);
+static bool tst_address_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+const struct sieve_command_def tst_address = {
+ .identifier = "address",
+ .type = SCT_TEST,
+ .positional_args = 2,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_address_registered,
+ .validate = tst_address_validate,
+ .generate = tst_address_generate
+};
+
+/*
+ * Address operation
+ */
+
+static bool tst_address_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int tst_address_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def tst_address_operation = {
+ .mnemonic = "ADDRESS",
+ .code = SIEVE_OPERATION_ADDRESS,
+ .dump = tst_address_operation_dump,
+ .execute = tst_address_operation_execute
+};
+
+/*
+ * Test registration
+ */
+
+static bool tst_address_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_command_registration *cmd_reg)
+{
+ /* The order of these is not significant */
+ sieve_comparators_link_tag
+ (valdtr, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR );
+ sieve_match_types_link_tags
+ (valdtr, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
+ sieve_address_parts_link_tags
+ (valdtr, cmd_reg, SIEVE_AM_OPT_ADDRESS_PART);
+ return TRUE;
+}
+
+/*
+ * Validation
+ */
+
+/* List of valid headers:
+ * Implementations MUST restrict the address test to headers that
+ * contain addresses, but MUST include at least From, To, Cc, Bcc,
+ * Sender, Resent-From, and Resent-To, and it SHOULD include any other
+ * header that utilizes an "address-list" structured header body.
+ *
+ * This list explicitly does not contain the envelope-to and return-path
+ * headers. The envelope test must be used to test against these addresses.
+ *
+ * FIXME: this restriction is somewhat odd. Sieve list advises to allow
+ * any other header as long as its content matches the address-list
+ * grammar.
+ */
+static const char * const _allowed_headers[] = {
+ /* Required */
+ "from", "to", "cc", "bcc", "sender", "resent-from", "resent-to",
+
+ /* Additional (RFC 822 / RFC 2822) */
+ "reply-to", "resent-reply-to", "resent-sender", "resent-cc", "resent-bcc",
+
+ /* Non-standard (RFC 2076, draft-palme-mailext-headers-08.txt) */
+ "for-approval", "for-handling", "for-comment", "apparently-to", "errors-to",
+ "delivered-to", "return-receipt-to", "x-admin", "read-receipt-to",
+ "x-confirm-reading-to", "return-receipt-requested",
+ "registered-mail-reply-requested-by", "mail-followup-to", "mail-reply-to",
+ "abuse-reports-to", "x-complaints-to", "x-report-abuse-to",
+
+ /* Undocumented */
+ "x-beenthere", "x-original-to",
+
+ NULL
+};
+
+static int _header_is_allowed
+(void *context ATTR_UNUSED, struct sieve_ast_argument *arg)
+{
+ if ( sieve_argument_is_string_literal(arg) ) {
+ const char *header = sieve_ast_strlist_strc(arg);
+
+ const char * const *hdsp = _allowed_headers;
+ while ( *hdsp != NULL ) {
+ if ( strcasecmp( *hdsp, header ) == 0 )
+ return 1;
+
+ hdsp++;
+ }
+
+ return 0;
+ }
+
+ return 1;
+}
+
+static bool tst_address_validate
+(struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+ struct sieve_ast_argument *header;
+ struct sieve_comparator cmp_default =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+ struct sieve_match_type mcht_default =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "header list", 1, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ if ( !sieve_command_verify_headers_argument(valdtr, arg) )
+ return FALSE;
+
+ /* Check if supplied header names are allowed
+ * FIXME: verify dynamic header names at runtime
+ */
+ header = arg;
+ if ( sieve_ast_stringlist_map
+ (&header, NULL, _header_is_allowed) <= 0 ) {
+ i_assert(header != NULL);
+ sieve_argument_validate_error(valdtr, header,
+ "specified header '%s' is not allowed for the address test",
+ str_sanitize(sieve_ast_strlist_strc(header), 64));
+ return FALSE;
+ }
+
+ /* Check key list */
+
+ arg = sieve_ast_argument_next(arg);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "key list", 2, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ /* Validate the key argument to a specified match type */
+ return sieve_match_type_validate
+ (valdtr, tst, arg, &mcht_default, &cmp_default);
+}
+
+/*
+ * Code generation
+ */
+
+static bool tst_address_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
+{
+ sieve_operation_emit(cgenv->sblock, NULL, &tst_address_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, tst, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool tst_address_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "ADDRESS");
+ sieve_code_descend(denv);
+
+ /* Handle any optional arguments */
+ if ( sieve_message_opr_optional_dump(denv, address, NULL) != 0 )
+ return FALSE;
+
+ return
+ sieve_opr_stringlist_dump(denv, address, "header list") &&
+ sieve_opr_stringlist_dump(denv, address, "key list");
+}
+
+/*
+ * Code execution
+ */
+
+static int tst_address_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ struct sieve_comparator cmp =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+ struct sieve_match_type mcht =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ struct sieve_address_part addrp =
+ SIEVE_ADDRESS_PART_DEFAULT(all_address_part);
+ struct sieve_stringlist *hdr_list, *hdr_value_list, *value_list, *key_list;
+ struct sieve_address_list *addr_list;
+ ARRAY_TYPE(sieve_message_override) svmos;
+ int match, ret;
+
+ /* Read optional operands */
+ i_zero(&svmos);
+ if ( sieve_message_opr_optional_read
+ (renv, address, NULL, &ret, &addrp, &mcht, &cmp, &svmos) < 0 )
+ return ret;
+
+ /* Read header-list */
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "header-list", &hdr_list))
+ <= 0 )
+ return ret;
+
+ /* Read key-list */
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "key-list", &key_list))
+ <= 0 )
+ return ret;
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "address test");
+
+ /* Get header */
+ sieve_runtime_trace_descend(renv);
+ if ( (ret=sieve_message_get_header_fields
+ (renv, hdr_list, &svmos, FALSE, &hdr_value_list)) <= 0 )
+ return ret;
+ sieve_runtime_trace_ascend(renv);
+
+ /* Create value stringlist */
+ addr_list = sieve_header_address_list_create(renv, hdr_value_list);
+ value_list = sieve_address_part_stringlist_create(renv, &addrp, addr_list);
+
+ /* Perform match */
+ if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret)) < 0 )
+ return ret;
+
+ /* Set test result for subsequent conditional jump */
+ sieve_interpreter_set_test_result(renv->interp, match > 0);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/tst-allof.c b/pigeonhole/src/lib-sieve/tst-allof.c
new file mode 100644
index 0000000..6d278b9
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/tst-allof.c
@@ -0,0 +1,108 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+
+/*
+ * Allof test
+ *
+ * Syntax
+ * allof <tests: test-list>
+ */
+
+static bool tst_allof_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx,
+ struct sieve_jumplist *jumps, bool jump_true);
+static bool tst_allof_validate_const
+ (struct sieve_validator *valdtr, struct sieve_command *tst,
+ int *const_current, int const_new);
+
+const struct sieve_command_def tst_allof = {
+ .identifier = "allof",
+ .type = SCT_TEST,
+ .positional_args = 0,
+ .subtests = 2,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate_const = tst_allof_validate_const,
+ .control_generate = tst_allof_generate
+};
+
+/*
+ * Code validation
+ */
+
+static bool tst_allof_validate_const
+(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_command *tst ATTR_UNUSED, int *const_current, int const_next)
+{
+ if ( const_next == 0 ) {
+ *const_current = 0;
+ return FALSE;
+ }
+
+ if ( *const_current != -1 )
+ *const_current = const_next;
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool tst_allof_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *ctx,
+ struct sieve_jumplist *jumps, bool jump_true)
+{
+ struct sieve_binary_block *sblock = cgenv->sblock;
+ struct sieve_ast_node *test;
+ struct sieve_jumplist false_jumps;
+
+ if ( sieve_ast_test_count(ctx->ast_node) > 1 ) {
+ if ( jump_true ) {
+ /* Prepare jumplist */
+ sieve_jumplist_init_temp(&false_jumps, sblock);
+ }
+
+ test = sieve_ast_test_first(ctx->ast_node);
+ while ( test != NULL ) {
+ bool result;
+
+ /* If this test list must jump on false, all sub-tests can simply add their jumps
+ * to the caller's jump list, otherwise this test redirects all false jumps to the
+ * end of the currently generated code. This is just after a final jump to the true
+ * case
+ */
+ if ( jump_true )
+ result = sieve_generate_test(cgenv, test, &false_jumps, FALSE);
+ else
+ result = sieve_generate_test(cgenv, test, jumps, FALSE);
+
+ if ( !result ) return FALSE;
+
+ test = sieve_ast_test_next(test);
+ }
+
+ if ( jump_true ) {
+ /* All tests succeeded, jump to case TRUE */
+ sieve_operation_emit(cgenv->sblock, NULL, &sieve_jmp_operation);
+ sieve_jumplist_add(jumps, sieve_binary_emit_offset(sblock, 0));
+
+ /* All false exits jump here */
+ sieve_jumplist_resolve(&false_jumps);
+ }
+ } else {
+ /* Script author is being inefficient; we can optimize the allof test away */
+ test = sieve_ast_test_first(ctx->ast_node);
+ sieve_generate_test(cgenv, test, jumps, jump_true);
+ }
+
+ return TRUE;
+}
+
diff --git a/pigeonhole/src/lib-sieve/tst-anyof.c b/pigeonhole/src/lib-sieve/tst-anyof.c
new file mode 100644
index 0000000..84bfedd
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/tst-anyof.c
@@ -0,0 +1,107 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-generator.h"
+#include "sieve-validator.h"
+#include "sieve-binary.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+
+/*
+ * Anyof test
+ *
+ * Syntax
+ * anyof <tests: test-list>
+ */
+
+static bool tst_anyof_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx,
+ struct sieve_jumplist *jumps, bool jump_true);
+static bool tst_anyof_validate_const
+ (struct sieve_validator *valdtr, struct sieve_command *tst,
+ int *const_current, int const_next);
+
+const struct sieve_command_def tst_anyof = {
+ .identifier = "anyof",
+ .type = SCT_TEST,
+ .positional_args = 0,
+ .subtests = 2,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate_const = tst_anyof_validate_const,
+ .control_generate = tst_anyof_generate
+};
+
+/*
+ * Code validation
+ */
+
+static bool tst_anyof_validate_const
+(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_command *tst ATTR_UNUSED, int *const_current, int const_next)
+{
+ if ( const_next > 0 ) {
+ *const_current = 1;
+ return FALSE;
+ }
+
+ if ( *const_current != -1 )
+ *const_current = const_next;
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool tst_anyof_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx,
+ struct sieve_jumplist *jumps, bool jump_true)
+{
+ struct sieve_binary_block *sblock = cgenv->sblock;
+ struct sieve_ast_node *test;
+ struct sieve_jumplist true_jumps;
+
+ if ( sieve_ast_test_count(ctx->ast_node) > 1 ) {
+ if ( !jump_true ) {
+ /* Prepare jumplist */
+ sieve_jumplist_init_temp(&true_jumps, sblock);
+ }
+
+ test = sieve_ast_test_first(ctx->ast_node);
+ while ( test != NULL ) {
+ bool result;
+
+ /* If this test list must jump on true, all sub-tests can simply add their jumps
+ * to the caller's jump list, otherwise this test redirects all true jumps to the
+ * end of the currently generated code. This is just after a final jump to the false
+ * case
+ */
+ if ( !jump_true )
+ result = sieve_generate_test(cgenv, test, &true_jumps, TRUE);
+ else
+ result = sieve_generate_test(cgenv, test, jumps, TRUE);
+
+ if ( !result ) return FALSE;
+
+ test = sieve_ast_test_next(test);
+ }
+
+ if ( !jump_true ) {
+ /* All tests failed, jump to case FALSE */
+ sieve_operation_emit(sblock, NULL, &sieve_jmp_operation);
+ sieve_jumplist_add(jumps, sieve_binary_emit_offset(sblock, 0));
+
+ /* All true exits jump here */
+ sieve_jumplist_resolve(&true_jumps);
+ }
+ } else {
+ /* Script author is being inefficient; we can optimize the allof test away */
+ test = sieve_ast_test_first(ctx->ast_node);
+ sieve_generate_test(cgenv, test, jumps, jump_true);
+ }
+
+ return TRUE;
+}
diff --git a/pigeonhole/src/lib-sieve/tst-exists.c b/pigeonhole/src/lib-sieve/tst-exists.c
new file mode 100644
index 0000000..0668c30
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/tst-exists.c
@@ -0,0 +1,179 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-message.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code-dumper.h"
+
+/*
+ * Exists test
+ *
+ * Syntax:
+ * exists <header-names: string-list>
+ */
+
+static bool tst_exists_validate
+ (struct sieve_validator *valdtr, struct sieve_command *tst);
+static bool tst_exists_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *tst);
+
+const struct sieve_command_def tst_exists = {
+ .identifier = "exists",
+ .type = SCT_TEST,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = tst_exists_validate,
+ .generate = tst_exists_generate
+};
+
+/*
+ * Exists operation
+ */
+
+static bool tst_exists_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int tst_exists_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def tst_exists_operation = {
+ .mnemonic = "EXISTS",
+ .code = SIEVE_OPERATION_EXISTS,
+ .dump = tst_exists_operation_dump,
+ .execute = tst_exists_operation_execute
+};
+
+/*
+ * Validation
+ */
+
+static bool tst_exists_validate
+ (struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "header names", 1, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ return sieve_command_verify_headers_argument(valdtr, arg);
+}
+
+/*
+ * Code generation
+ */
+
+static bool tst_exists_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
+{
+ sieve_operation_emit(cgenv->sblock, NULL, &tst_exists_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, tst, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool tst_exists_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "EXISTS");
+ sieve_code_descend(denv);
+
+ /* Optional operands */
+ if ( sieve_message_opr_optional_dump(denv, address, NULL) != 0 )
+ return FALSE;
+
+ return sieve_opr_stringlist_dump(denv, address, "header names");
+}
+
+/*
+ * Code execution
+ */
+
+static int tst_exists_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ struct sieve_stringlist *hdr_list;
+ ARRAY_TYPE(sieve_message_override) svmos;
+ string_t *hdr_item;
+ bool matched;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Optional operands */
+ i_zero(&svmos);
+ if ( sieve_message_opr_optional_read
+ (renv, address, NULL, &ret, NULL, NULL, NULL, &svmos) < 0 )
+ return ret;
+
+ /* Read header-list */
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "header-list", &hdr_list))
+ <= 0 )
+ return ret;
+
+ /*
+ * Perfrom test
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "exists test");
+ sieve_runtime_trace_descend(renv);
+
+ /* Iterate through all requested headers to match (must find all specified) */
+ hdr_item = NULL;
+ matched = TRUE;
+ while ( matched &&
+ (ret=sieve_stringlist_next_item(hdr_list, &hdr_item)) > 0 ) {
+ struct sieve_stringlist *value_list;
+ string_t *dummy;
+
+ /* Get header */
+ if ( (ret=sieve_message_get_header_fields
+ (renv, sieve_single_stringlist_create(renv, hdr_item, FALSE),
+ &svmos, FALSE, &value_list)) <= 0 )
+ return ret;
+
+ if ( (ret=sieve_stringlist_next_item(value_list, &dummy)) < 0)
+ return value_list->exec_status;
+
+ if ( ret == 0 )
+ matched = FALSE;
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
+ "header `%s' %s", str_sanitize(str_c(hdr_item), 80),
+ ( matched ? "exists" : "is missing" ));
+ }
+
+ if ( matched )
+ sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING, "all headers exist");
+ else
+ sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING, "headers are missing");
+
+ /* Set test result for subsequent conditional jump */
+ if ( ret >= 0 ) {
+ sieve_interpreter_set_test_result(renv->interp, matched);
+ return SIEVE_EXEC_OK;
+ }
+
+ sieve_runtime_trace_error(renv, "invalid header-list item");
+ return SIEVE_EXEC_BIN_CORRUPT;
+}
diff --git a/pigeonhole/src/lib-sieve/tst-header.c b/pigeonhole/src/lib-sieve/tst-header.c
new file mode 100644
index 0000000..6e553a2
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/tst-header.c
@@ -0,0 +1,204 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-message.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-match.h"
+
+/*
+ * Header test
+ *
+ * Syntax:
+ * header [COMPARATOR] [MATCH-TYPE]
+ * <header-names: string-list> <key-list: string-list>
+ */
+
+static bool tst_header_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool tst_header_validate
+ (struct sieve_validator *valdtr, struct sieve_command *tst);
+static bool tst_header_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *tst);
+
+const struct sieve_command_def tst_header = {
+ .identifier = "header",
+ .type = SCT_TEST,
+ .positional_args = 2,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_header_registered,
+ .validate = tst_header_validate,
+ .generate = tst_header_generate
+};
+
+/*
+ * Header operation
+ */
+
+static bool tst_header_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int tst_header_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def tst_header_operation = {
+ .mnemonic = "HEADER",
+ .code = SIEVE_OPERATION_HEADER,
+ .dump = tst_header_operation_dump,
+ .execute = tst_header_operation_execute
+};
+
+/*
+ * Test registration
+ */
+
+static bool tst_header_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_command_registration *cmd_reg)
+{
+ /* The order of these is not significant */
+ sieve_comparators_link_tag(valdtr, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
+ sieve_match_types_link_tags(valdtr, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
+
+ return TRUE;
+}
+
+/*
+ * Validation
+ */
+
+static bool tst_header_validate
+(struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+ struct sieve_comparator cmp_default =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+ struct sieve_match_type mcht_default =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "header names", 1, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ if ( !sieve_command_verify_headers_argument(valdtr, arg) )
+ return FALSE;
+
+ arg = sieve_ast_argument_next(arg);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "key list", 2, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ /* Validate the key argument to a specified match type */
+ return sieve_match_type_validate
+ (valdtr, tst, arg, &mcht_default, &cmp_default);
+}
+
+/*
+ * Code generation
+ */
+
+static bool tst_header_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
+{
+ sieve_operation_emit(cgenv->sblock, NULL, &tst_header_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, tst, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool tst_header_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "HEADER");
+ sieve_code_descend(denv);
+
+ /* Optional operands */
+ if ( sieve_message_opr_optional_dump(denv, address, NULL) != 0 )
+ return FALSE;
+
+ return
+ sieve_opr_stringlist_dump(denv, address, "header names") &&
+ sieve_opr_stringlist_dump(denv, address, "key list");
+}
+
+/*
+ * Code execution
+ */
+
+static int tst_header_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ struct sieve_comparator cmp =
+ SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
+ struct sieve_match_type mcht =
+ SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ struct sieve_stringlist *hdr_list, *key_list, *value_list;
+ ARRAY_TYPE(sieve_message_override) svmos;
+ int match, ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Optional operands */
+ i_zero(&svmos);
+ if ( sieve_message_opr_optional_read
+ (renv, address, NULL, &ret, NULL, &mcht, &cmp, &svmos) < 0 )
+ return ret;
+
+ /* Read header-list */
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "header-list", &hdr_list))
+ <= 0 )
+ return ret;
+
+ /* Read key-list */
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "key-list", &key_list))
+ <= 0 )
+ return ret;
+
+ /*
+ * Perform test
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "header test");
+
+ /* Get header */
+ sieve_runtime_trace_descend(renv);
+ if ( (ret=sieve_message_get_header_fields
+ (renv, hdr_list, &svmos, TRUE, &value_list)) <= 0 )
+ return ret;
+ sieve_runtime_trace_ascend(renv);
+
+ /* Perform match */
+ if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret)) < 0 )
+ return ret;
+
+ /* Set test result for subsequent conditional jump */
+ sieve_interpreter_set_test_result(renv->interp, match > 0);
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/tst-not.c b/pigeonhole/src/lib-sieve/tst-not.c
new file mode 100644
index 0000000..9687d49
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/tst-not.c
@@ -0,0 +1,67 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+
+/*
+ * Not test
+ *
+ * Syntax:
+ * not <tests: test-list>
+ */
+
+static bool tst_not_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx,
+ struct sieve_jumplist *jumps, bool jump_true);
+static bool tst_not_validate_const
+ (struct sieve_validator *valdtr, struct sieve_command *tst,
+ int *const_current, int const_next);
+
+const struct sieve_command_def tst_not = {
+ .identifier = "not",
+ .type = SCT_TEST,
+ .positional_args = 0,
+ .subtests = 1,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate_const = tst_not_validate_const,
+ .control_generate = tst_not_generate
+};
+
+/*
+ * Code validation
+ */
+
+static bool tst_not_validate_const
+(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_command *tst ATTR_UNUSED, int *const_current, int const_next)
+{
+ if ( const_next < 0 )
+ *const_current = -1;
+ else if ( const_next > 0 )
+ *const_current = 0;
+ else
+ *const_current = 1;
+
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool tst_not_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *ctx,
+ struct sieve_jumplist *jumps, bool jump_true)
+{
+ struct sieve_ast_node *test;
+
+ /* Validator verified the existance of the single test already */
+ test = sieve_ast_test_first(ctx->ast_node);
+
+ return sieve_generate_test(cgenv, test, jumps, !jump_true);
+}
+
diff --git a/pigeonhole/src/lib-sieve/tst-size.c b/pigeonhole/src/lib-sieve/tst-size.c
new file mode 100644
index 0000000..1ed101b
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/tst-size.c
@@ -0,0 +1,318 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "mail-storage.h"
+
+#include "sieve-common.h"
+#include "sieve-code.h"
+#include "sieve-message.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+/*
+ * Size test
+ *
+ * Syntax:
+ * size <":over" / ":under"> <limit: number>
+ */
+
+static bool
+tst_size_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool
+tst_size_pre_validate(struct sieve_validator *valdtr,
+ struct sieve_command *tst);
+static bool
+tst_size_validate(struct sieve_validator *valdtr, struct sieve_command *tst);
+static bool
+tst_size_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+const struct sieve_command_def tst_size = {
+ .identifier = "size",
+ .type = SCT_TEST,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_size_registered,
+ .pre_validate = tst_size_pre_validate,
+ .validate = tst_size_validate,
+ .generate = tst_size_generate
+};
+
+/*
+ * Size operations
+ */
+
+static bool
+tst_size_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+tst_size_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def tst_size_over_operation = {
+ .mnemonic = "SIZE-OVER",
+ .code = SIEVE_OPERATION_SIZE_OVER,
+ .dump = tst_size_operation_dump,
+ .execute = tst_size_operation_execute
+};
+
+const struct sieve_operation_def tst_size_under_operation = {
+ .mnemonic = "SIZE-UNDER",
+ .code = SIEVE_OPERATION_SIZE_UNDER,
+ .dump = tst_size_operation_dump,
+ .execute = tst_size_operation_execute
+};
+
+/*
+ * Context data
+ */
+
+struct tst_size_context_data {
+ enum { SIZE_UNASSIGNED, SIZE_UNDER, SIZE_OVER } type;
+};
+
+#define TST_SIZE_ERROR_DUP_TAG \
+ "exactly one of the ':under' or ':over' tags must be specified " \
+ "for the size test, but more were found"
+
+/*
+ * Tag validation
+ */
+
+static bool
+tst_size_validate_over_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *tst)
+{
+ struct tst_size_context_data *ctx_data =
+ (struct tst_size_context_data *)tst->data;
+
+ if (ctx_data->type != SIZE_UNASSIGNED) {
+ sieve_argument_validate_error(valdtr, *arg,
+ TST_SIZE_ERROR_DUP_TAG);
+ return FALSE;
+ }
+
+ ctx_data->type = SIZE_OVER;
+
+ /* Delete this tag */
+ *arg = sieve_ast_arguments_detach(*arg, 1);
+
+ return TRUE;
+}
+
+static bool
+tst_size_validate_under_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg ATTR_UNUSED,
+ struct sieve_command *tst)
+{
+ struct tst_size_context_data *ctx_data =
+ (struct tst_size_context_data *)tst->data;
+
+ if (ctx_data->type != SIZE_UNASSIGNED) {
+ sieve_argument_validate_error(valdtr, *arg,
+ TST_SIZE_ERROR_DUP_TAG);
+ return FALSE;
+ }
+
+ ctx_data->type = SIZE_UNDER;
+
+ /* Delete this tag */
+ *arg = sieve_ast_arguments_detach(*arg, 1);
+
+ return TRUE;
+}
+
+/*
+ * Test registration
+ */
+
+static const struct sieve_argument_def size_over_tag = {
+ .identifier = "over",
+ .validate = tst_size_validate_over_tag
+};
+
+static const struct sieve_argument_def size_under_tag = {
+ .identifier = "under",
+ .validate = tst_size_validate_under_tag,
+};
+
+static bool
+tst_size_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_command_registration *cmd_reg)
+{
+ /* Register our tags */
+ sieve_validator_register_tag(valdtr, cmd_reg, NULL, &size_over_tag, 0);
+ sieve_validator_register_tag(valdtr, cmd_reg, NULL, &size_under_tag, 0);
+
+ return TRUE;
+}
+
+/*
+ * Test validation
+ */
+
+static bool
+tst_size_pre_validate(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_command *tst)
+{
+ struct tst_size_context_data *ctx_data;
+
+ /* Assign context */
+ ctx_data = p_new(sieve_command_pool(tst),
+ struct tst_size_context_data, 1);
+ ctx_data->type = SIZE_UNASSIGNED;
+ tst->data = ctx_data;
+
+ return TRUE;
+}
+
+static bool
+tst_size_validate(struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct tst_size_context_data *ctx_data =
+ (struct tst_size_context_data *)tst->data;
+ struct sieve_ast_argument *arg = tst->first_positional;
+
+ if (ctx_data->type == SIZE_UNASSIGNED) {
+ sieve_command_validate_error(valdtr, tst,
+ "the size test requires either the :under or the :over tag "
+ "to be specified");
+ return FALSE;
+ }
+
+ if (!sieve_validate_positional_argument(valdtr, tst, arg, "limit", 1,
+ SAAT_NUMBER))
+ return FALSE;
+
+ return sieve_validator_argument_activate(valdtr, tst, arg, FALSE);
+}
+
+/*
+ * Code generation
+ */
+
+bool tst_size_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *tst)
+{
+ struct tst_size_context_data *ctx_data =
+ (struct tst_size_context_data *)tst->data;
+
+ if (ctx_data->type == SIZE_OVER) {
+ sieve_operation_emit(cgenv->sblock, NULL,
+ &tst_size_over_operation);
+ } else {
+ sieve_operation_emit(cgenv->sblock, NULL,
+ &tst_size_under_operation);
+ }
+
+ /* Generate arguments */
+ if (!sieve_generate_arguments(cgenv, tst, NULL))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+tst_size_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "%s", sieve_operation_mnemonic(denv->oprtn));
+ sieve_code_descend(denv);
+
+ return sieve_opr_number_dump(denv, address, "limit");
+}
+
+/*
+ * Code execution
+ */
+
+static inline bool
+tst_size_get(const struct sieve_runtime_env *renv, sieve_number_t *size)
+{
+ struct mail *mail = sieve_message_get_mail(renv->msgctx);
+ uoff_t psize;
+
+ if (mail_get_physical_size(mail, &psize) < 0)
+ return FALSE;
+
+ *size = psize;
+ return TRUE;
+}
+
+static int
+tst_size_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ sieve_number_t mail_size, limit;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Read size limit */
+ if ((ret = sieve_opr_number_read(renv, address, "limit", &limit)) <= 0)
+ return ret;
+
+ /*
+ * Perform test
+ */
+
+ /* Get the size of the message */
+ if (!tst_size_get(renv, &mail_size)) {
+ /* FIXME: improve this error */
+ e_error(renv->event, "failed to assess message size");
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ /* Perform the test */
+ if (sieve_operation_is(renv->oprtn, tst_size_over_operation)) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "size :over test");
+
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING)) {
+ sieve_runtime_trace_descend(renv);
+
+ sieve_runtime_trace(
+ renv, 0, "comparing message size %llu",
+ (unsigned long long)mail_size);
+ sieve_runtime_trace(
+ renv, 0, "with upper limit %llu",
+ (unsigned long long)limit);
+ }
+
+ sieve_interpreter_set_test_result(renv->interp,
+ (mail_size > limit));
+ } else {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "size :under test");
+
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING)) {
+ sieve_runtime_trace_descend(renv);
+
+ sieve_runtime_trace(
+ renv, 0, "comparing message size %llu",
+ (unsigned long long)mail_size);
+ sieve_runtime_trace(
+ renv, 0, "with lower limit %llu",
+ (unsigned long long)limit);
+ }
+
+ sieve_interpreter_set_test_result(renv->interp,
+ (mail_size < limit));
+ }
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/lib-sieve/tst-truefalse.c b/pigeonhole/src/lib-sieve/tst-truefalse.c
new file mode 100644
index 0000000..6373ce3
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/tst-truefalse.c
@@ -0,0 +1,104 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-ast.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-interpreter.h"
+
+/*
+ * True/False test command
+ */
+
+static bool tst_false_validate_const
+ (struct sieve_validator *valdtr, struct sieve_command *tst,
+ int *const_current, int const_next);
+static bool tst_false_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd,
+ struct sieve_jumplist *jumps, bool jump_true);
+
+const struct sieve_command_def tst_false = {
+ .identifier = "false",
+ .type = SCT_TEST,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate_const = tst_false_validate_const,
+ .control_generate = tst_false_generate
+};
+
+static bool tst_true_validate_const
+ (struct sieve_validator *valdtr, struct sieve_command *tst,
+ int *const_current, int const_next);
+static bool tst_true_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd,
+ struct sieve_jumplist *jumps, bool jump_true);
+
+const struct sieve_command_def tst_true = {
+ .identifier = "true",
+ .type = SCT_TEST,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate_const = tst_true_validate_const,
+ .control_generate = tst_true_generate
+};
+
+/*
+ * Code validation
+ */
+
+static bool tst_false_validate_const
+(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_command *tst ATTR_UNUSED, int *const_current,
+ int const_next ATTR_UNUSED)
+{
+ *const_current = 0;
+ return TRUE;
+}
+
+static bool tst_true_validate_const
+(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_command *tst ATTR_UNUSED, int *const_current,
+ int const_next ATTR_UNUSED)
+{
+ *const_current = 1;
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool tst_false_generate
+(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd ATTR_UNUSED,
+ struct sieve_jumplist *jumps, bool jump_true)
+{
+ if ( !jump_true ) {
+ sieve_operation_emit(cgenv->sblock, NULL, &sieve_jmp_operation);
+ sieve_jumplist_add(jumps, sieve_binary_emit_offset(cgenv->sblock, 0));
+ }
+
+ return TRUE;
+}
+
+static bool tst_true_generate
+(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd ATTR_UNUSED,
+ struct sieve_jumplist *jumps, bool jump_true)
+{
+ if ( jump_true ) {
+ sieve_operation_emit(cgenv->sblock, NULL, &sieve_jmp_operation);
+ sieve_jumplist_add(jumps, sieve_binary_emit_offset(cgenv->sblock, 0));
+ }
+
+ return TRUE;
+}
+
diff --git a/pigeonhole/src/lib-sieve/util/Makefile.am b/pigeonhole/src/lib-sieve/util/Makefile.am
new file mode 100644
index 0000000..36cad8a
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/util/Makefile.am
@@ -0,0 +1,51 @@
+noinst_LTLIBRARIES = libsieve_util.la
+
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_SERVICE_INCLUDE) \
+ -DMODULEDIR=\""$(dovecot_moduledir)"\"
+
+libsieve_util_la_DEPENDENCIES = $(LIBDOVECOT_STORAGE_DEPS) $(LIBDOVECOT_DEPS)
+
+libsieve_util_la_SOURCES = \
+ mail-raw.c \
+ edit-mail.c \
+ rfc2822.c
+
+headers = \
+ mail-raw.h \
+ edit-mail.h \
+ rfc2822.h
+
+pkginc_libdir=$(dovecot_pkgincludedir)/sieve
+pkginc_lib_HEADERS = $(headers)
+
+test_programs = \
+ test-edit-mail \
+ test-rfc2822
+
+noinst_PROGRAMS = $(test_programs)
+
+test_libs = \
+ libsieve_util.la \
+ $(LIBDOVECOT_STORAGE) \
+ $(LIBDOVECOT)
+test_deps = \
+ libsieve_util.la \
+ $(LIBDOVECOT_STORAGE_DEPS) \
+ $(LIBDOVECOT_DEPS)
+
+test_edit_mail_SOURCES = test-edit-mail.c
+test_edit_mail_LDADD = $(test_libs)
+test_edit_mail_DEPENDENCIES = $(test_deps)
+
+test_rfc2822_SOURCES = test-rfc2822.c
+test_rfc2822_LDADD = $(test_libs)
+test_rfc2822_DEPENDENCIES = $(test_deps)
+
+check: check-am check-test
+check-test: all-am
+ for bin in $(test_programs); do \
+ if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
+ done
+
diff --git a/pigeonhole/src/lib-sieve/util/Makefile.in b/pigeonhole/src/lib-sieve/util/Makefile.in
new file mode 100644
index 0000000..a62ac20
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/util/Makefile.in
@@ -0,0 +1,810 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+noinst_PROGRAMS = $(am__EXEEXT_1)
+subdir = src/lib-sieve/util
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(pkginc_lib_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__EXEEXT_1 = test-edit-mail$(EXEEXT) test-rfc2822$(EXEEXT)
+PROGRAMS = $(noinst_PROGRAMS)
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsieve_util_la_LIBADD =
+am_libsieve_util_la_OBJECTS = mail-raw.lo edit-mail.lo rfc2822.lo
+libsieve_util_la_OBJECTS = $(am_libsieve_util_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+am_test_edit_mail_OBJECTS = test-edit-mail.$(OBJEXT)
+test_edit_mail_OBJECTS = $(am_test_edit_mail_OBJECTS)
+am__DEPENDENCIES_1 =
+am__DEPENDENCIES_2 = libsieve_util.la $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_test_rfc2822_OBJECTS = test-rfc2822.$(OBJEXT)
+test_rfc2822_OBJECTS = $(am_test_rfc2822_OBJECTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/edit-mail.Plo \
+ ./$(DEPDIR)/mail-raw.Plo ./$(DEPDIR)/rfc2822.Plo \
+ ./$(DEPDIR)/test-edit-mail.Po ./$(DEPDIR)/test-rfc2822.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libsieve_util_la_SOURCES) $(test_edit_mail_SOURCES) \
+ $(test_rfc2822_SOURCES)
+DIST_SOURCES = $(libsieve_util_la_SOURCES) $(test_edit_mail_SOURCES) \
+ $(test_rfc2822_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkginc_libdir)"
+HEADERS = $(pkginc_lib_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libsieve_util.la
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_SERVICE_INCLUDE) \
+ -DMODULEDIR=\""$(dovecot_moduledir)"\"
+
+libsieve_util_la_DEPENDENCIES = $(LIBDOVECOT_STORAGE_DEPS) $(LIBDOVECOT_DEPS)
+libsieve_util_la_SOURCES = \
+ mail-raw.c \
+ edit-mail.c \
+ rfc2822.c
+
+headers = \
+ mail-raw.h \
+ edit-mail.h \
+ rfc2822.h
+
+pkginc_libdir = $(dovecot_pkgincludedir)/sieve
+pkginc_lib_HEADERS = $(headers)
+test_programs = \
+ test-edit-mail \
+ test-rfc2822
+
+test_libs = \
+ libsieve_util.la \
+ $(LIBDOVECOT_STORAGE) \
+ $(LIBDOVECOT)
+
+test_deps = \
+ libsieve_util.la \
+ $(LIBDOVECOT_STORAGE_DEPS) \
+ $(LIBDOVECOT_DEPS)
+
+test_edit_mail_SOURCES = test-edit-mail.c
+test_edit_mail_LDADD = $(test_libs)
+test_edit_mail_DEPENDENCIES = $(test_deps)
+test_rfc2822_SOURCES = test-rfc2822.c
+test_rfc2822_LDADD = $(test_libs)
+test_rfc2822_DEPENDENCIES = $(test_deps)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/util/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/lib-sieve/util/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libsieve_util.la: $(libsieve_util_la_OBJECTS) $(libsieve_util_la_DEPENDENCIES) $(EXTRA_libsieve_util_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libsieve_util_la_OBJECTS) $(libsieve_util_la_LIBADD) $(LIBS)
+
+test-edit-mail$(EXEEXT): $(test_edit_mail_OBJECTS) $(test_edit_mail_DEPENDENCIES) $(EXTRA_test_edit_mail_DEPENDENCIES)
+ @rm -f test-edit-mail$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_edit_mail_OBJECTS) $(test_edit_mail_LDADD) $(LIBS)
+
+test-rfc2822$(EXEEXT): $(test_rfc2822_OBJECTS) $(test_rfc2822_DEPENDENCIES) $(EXTRA_test_rfc2822_DEPENDENCIES)
+ @rm -f test-rfc2822$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_rfc2822_OBJECTS) $(test_rfc2822_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edit-mail.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail-raw.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rfc2822.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-edit-mail.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-rfc2822.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
+ done
+
+uninstall-pkginc_libHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(pkginc_libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/edit-mail.Plo
+ -rm -f ./$(DEPDIR)/mail-raw.Plo
+ -rm -f ./$(DEPDIR)/rfc2822.Plo
+ -rm -f ./$(DEPDIR)/test-edit-mail.Po
+ -rm -f ./$(DEPDIR)/test-rfc2822.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkginc_libHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/edit-mail.Plo
+ -rm -f ./$(DEPDIR)/mail-raw.Plo
+ -rm -f ./$(DEPDIR)/rfc2822.Plo
+ -rm -f ./$(DEPDIR)/test-edit-mail.Po
+ -rm -f ./$(DEPDIR)/test-rfc2822.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkginc_libHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pkginc_libHEADERS \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am \
+ uninstall-pkginc_libHEADERS
+
+.PRECIOUS: Makefile
+
+
+check: check-am check-test
+check-test: all-am
+ for bin in $(test_programs); do \
+ if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
+ done
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/lib-sieve/util/edit-mail.c b/pigeonhole/src/lib-sieve/util/edit-mail.c
new file mode 100644
index 0000000..31d941e
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/util/edit-mail.c
@@ -0,0 +1,2254 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "mempool.h"
+#include "llist.h"
+#include "istream-private.h"
+#include "master-service.h"
+#include "master-service-settings.h"
+#include "message-parser.h"
+#include "message-header-encode.h"
+#include "message-header-decode.h"
+#include "mail-user.h"
+#include "mail-storage-private.h"
+#include "index-mail.h"
+#include "raw-storage.h"
+
+#include "rfc2822.h"
+
+#include "edit-mail.h"
+
+/*
+ * Forward declarations
+ */
+
+struct _header_field_index;
+struct _header_field;
+struct _header_index;
+struct _header;
+
+static struct mail_vfuncs edit_mail_vfuncs;
+
+struct edit_mail_istream;
+struct istream *edit_mail_istream_create(struct edit_mail *edmail);
+
+static struct _header_index *
+edit_mail_header_clone(struct edit_mail *edmail, struct _header *header);
+
+/*
+ * Raw storage
+ */
+
+static struct mail_user *edit_mail_user = NULL;
+static unsigned int edit_mail_refcount = 0;
+
+static struct mail_user *edit_mail_raw_storage_get(struct mail_user *mail_user)
+{
+ if (edit_mail_user == NULL) {
+ void **sets =
+ master_service_settings_get_others(master_service);
+
+ edit_mail_user = raw_storage_create_from_set(
+ mail_user->set_info, sets[0]);
+ }
+
+ edit_mail_refcount++;
+
+ return edit_mail_user;
+}
+
+static void edit_mail_raw_storage_drop(void)
+{
+ i_assert(edit_mail_refcount > 0);
+
+ if (--edit_mail_refcount != 0)
+ return;
+
+ mail_user_unref(&edit_mail_user);
+ edit_mail_user = NULL;
+}
+
+/*
+ * Headers
+ */
+
+struct _header_field {
+ struct _header *header;
+
+ unsigned int refcount;
+
+ char *data;
+ size_t size;
+ size_t virtual_size;
+ uoff_t offset;
+ unsigned int lines;
+
+ uoff_t body_offset;
+
+ char *utf8_value;
+};
+
+struct _header_field_index {
+ struct _header_field_index *prev, *next;
+
+ struct _header_field *field;
+ struct _header_index *header;
+};
+
+struct _header {
+ unsigned int refcount;
+
+ char *name;
+};
+
+struct _header_index {
+ struct _header_index *prev, *next;
+
+ struct _header *header;
+
+ struct _header_field_index *first, *last;
+
+ unsigned int count;
+};
+
+static inline struct _header *_header_create(const char *name)
+{
+ struct _header *header;
+
+ header = i_new(struct _header, 1);
+ header->name = i_strdup(name);
+ header->refcount = 1;
+
+ return header;
+}
+
+static inline void _header_ref(struct _header *header)
+{
+ header->refcount++;
+}
+
+static inline void _header_unref(struct _header *header)
+{
+ i_assert(header->refcount > 0);
+ if (--header->refcount != 0)
+ return;
+
+ i_free(header->name);
+ i_free(header);
+}
+
+static inline struct _header_field *_header_field_create(struct _header *header)
+{
+ struct _header_field *hfield;
+
+ hfield = i_new(struct _header_field, 1);
+ hfield->refcount = 1;
+ hfield->header = header;
+ if (header != NULL)
+ _header_ref(header);
+
+ return hfield;
+}
+
+static inline void _header_field_ref(struct _header_field *hfield)
+{
+ hfield->refcount++;
+}
+
+static inline void _header_field_unref(struct _header_field *hfield)
+{
+ i_assert(hfield->refcount > 0);
+ if (--hfield->refcount != 0)
+ return;
+
+ if (hfield->header != NULL)
+ _header_unref(hfield->header);
+
+ if (hfield->data != NULL)
+ i_free(hfield->data);
+ if (hfield->utf8_value != NULL)
+ i_free(hfield->utf8_value);
+ i_free(hfield);
+}
+
+/*
+ * Edit mail object
+ */
+
+struct edit_mail {
+ struct mail_private mail;
+ struct mail_private *wrapped;
+
+ struct edit_mail *parent;
+ unsigned int refcount;
+
+ struct istream *wrapped_stream;
+ struct istream *stream;
+
+ struct _header_index *headers_head, *headers_tail;
+ struct _header_field_index *header_fields_head, *header_fields_tail;
+ struct message_size hdr_size, body_size;
+
+ struct message_size wrapped_hdr_size, wrapped_body_size;
+
+ struct _header_field_index *header_fields_appended;
+ struct message_size appended_hdr_size;
+
+ bool modified:1;
+ bool snapshot_modified:1;
+ bool crlf:1;
+ bool eoh_crlf:1;
+ bool headers_parsed:1;
+ bool destroying_stream:1;
+};
+
+struct edit_mail *edit_mail_wrap(struct mail *mail)
+{
+ struct mail_private *mailp = (struct mail_private *) mail;
+ struct edit_mail *edmail;
+ struct mail_user *raw_mail_user;
+ struct mailbox *raw_box = NULL;
+ struct mailbox_transaction_context *raw_trans;
+ struct message_size hdr_size, body_size;
+ struct istream *wrapped_stream;
+ uoff_t size_diff;
+ pool_t pool;
+
+ if (mail_get_stream(mail, &hdr_size, &body_size, &wrapped_stream) < 0)
+ return NULL;
+
+ /* Create dummy raw mailbox for our wrapper */
+
+ raw_mail_user = edit_mail_raw_storage_get(mail->box->storage->user);
+
+ if (raw_mailbox_alloc_stream(raw_mail_user, wrapped_stream, (time_t)-1,
+ "editor@example.com", &raw_box) < 0) {
+ i_error("edit-mail: failed to open raw box: %s",
+ mailbox_get_last_internal_error(raw_box, NULL));
+ mailbox_free(&raw_box);
+ edit_mail_raw_storage_drop();
+ return NULL;
+ }
+
+ raw_trans = mailbox_transaction_begin(raw_box, 0, __func__);
+
+ /* Create the wrapper mail */
+
+ pool = pool_alloconly_create("edit_mail", 1024);
+ edmail = p_new(pool, struct edit_mail, 1);
+ edmail->refcount = 1;
+ edmail->mail.pool = pool;
+
+ edmail->wrapped = mailp;
+ edmail->wrapped_hdr_size = hdr_size;
+ edmail->wrapped_body_size = body_size;
+
+ edmail->wrapped_stream = wrapped_stream;
+ i_stream_ref(edmail->wrapped_stream);
+
+ /* Determine whether we should use CRLF or LF for the physical message
+ */
+ size_diff = ((hdr_size.virtual_size + body_size.virtual_size) -
+ (hdr_size.physical_size + body_size.physical_size));
+ if (size_diff == 0 || size_diff <= (hdr_size.lines + body_size.lines)/2)
+ edmail->crlf = edmail->eoh_crlf = TRUE;
+
+ array_create(&edmail->mail.module_contexts, pool, sizeof(void *), 5);
+
+ edmail->mail.v = edit_mail_vfuncs;
+ edmail->mail.mail.seq = 1;
+ edmail->mail.mail.box = raw_box;
+ edmail->mail.mail.transaction = raw_trans;
+ edmail->mail.wanted_fields = mailp->wanted_fields;
+ edmail->mail.wanted_headers = mailp->wanted_headers;
+
+ return edmail;
+}
+
+struct edit_mail *edit_mail_snapshot(struct edit_mail *edmail)
+{
+ struct _header_field_index *field_idx, *field_idx_new;
+ struct edit_mail *edmail_new;
+ pool_t pool;
+
+ if (!edmail->snapshot_modified)
+ return edmail;
+
+ pool = pool_alloconly_create("edit_mail", 1024);
+ edmail_new = p_new(pool, struct edit_mail, 1);
+ edmail_new->refcount = 1;
+ edmail_new->mail.pool = pool;
+
+ edmail_new->wrapped = edmail->wrapped;
+ edmail_new->wrapped_hdr_size = edmail->wrapped_hdr_size;
+ edmail_new->wrapped_body_size = edmail->wrapped_body_size;
+ edmail_new->hdr_size = edmail->hdr_size;
+ edmail_new->body_size = edmail->body_size;
+ edmail_new->appended_hdr_size = edmail->appended_hdr_size;
+
+ edmail_new->wrapped_stream = edmail->wrapped_stream;
+ i_stream_ref(edmail_new->wrapped_stream);
+
+ edmail_new->crlf = edmail->crlf;
+ edmail_new->eoh_crlf = edmail->eoh_crlf;
+
+ array_create(&edmail_new->mail.module_contexts, pool,
+ sizeof(void *), 5);
+
+ edmail_new->mail.v = edit_mail_vfuncs;
+ edmail_new->mail.mail.seq = 1;
+ edmail_new->mail.mail.box = edmail->mail.mail.box;
+ edmail_new->mail.mail.transaction = edmail->mail.mail.transaction;
+ edmail_new->mail.wanted_fields = edmail->mail.wanted_fields;
+ edmail_new->mail.wanted_headers = edmail->mail.wanted_headers;
+
+ edmail_new->stream = NULL;
+
+ if (edmail->modified) {
+ field_idx = edmail->header_fields_head;
+ while (field_idx != NULL) {
+ struct _header_field_index *next = field_idx->next;
+
+ field_idx_new = i_new(struct _header_field_index, 1);
+
+ field_idx_new->header = edit_mail_header_clone(
+ edmail_new, field_idx->header->header);
+
+ field_idx_new->field = field_idx->field;
+ _header_field_ref(field_idx_new->field);
+
+ DLLIST2_APPEND(&edmail_new->header_fields_head,
+ &edmail_new->header_fields_tail,
+ field_idx_new);
+
+ field_idx_new->header->count++;
+ if (field_idx->header->first == field_idx)
+ field_idx_new->header->first = field_idx_new;
+ if (field_idx->header->last == field_idx)
+ field_idx_new->header->last = field_idx_new;
+
+ if (field_idx == edmail->header_fields_appended) {
+ edmail_new->header_fields_appended =
+ field_idx_new;
+ }
+
+ field_idx = next;
+ }
+
+ edmail_new->modified = TRUE;
+ }
+
+ edmail_new->headers_parsed = edmail->headers_parsed;
+ edmail_new->parent = edmail;
+
+ return edmail_new;
+}
+
+void edit_mail_reset(struct edit_mail *edmail)
+{
+ struct _header_index *header_idx;
+ struct _header_field_index *field_idx;
+
+ i_stream_unref(&edmail->stream);
+
+ field_idx = edmail->header_fields_head;
+ while (field_idx != NULL) {
+ struct _header_field_index *next = field_idx->next;
+
+ _header_field_unref(field_idx->field);
+ i_free(field_idx);
+
+ field_idx = next;
+ }
+
+ header_idx = edmail->headers_head;
+ while (header_idx != NULL) {
+ struct _header_index *next = header_idx->next;
+
+ _header_unref(header_idx->header);
+ i_free(header_idx);
+
+ header_idx = next;
+ }
+
+ edmail->modified = FALSE;
+}
+
+void edit_mail_unwrap(struct edit_mail **edmail)
+{
+ struct edit_mail *parent;
+
+ i_assert((*edmail)->refcount > 0);
+ if (--(*edmail)->refcount != 0)
+ return;
+
+ edit_mail_reset(*edmail);
+ i_stream_unref(&(*edmail)->wrapped_stream);
+
+ parent = (*edmail)->parent;
+
+ if (parent == NULL) {
+ mailbox_transaction_rollback(&(*edmail)->mail.mail.transaction);
+ mailbox_free(&(*edmail)->mail.mail.box);
+ edit_mail_raw_storage_drop();
+ }
+
+ pool_unref(&(*edmail)->mail.pool);
+ *edmail = NULL;
+
+ if (parent != NULL)
+ edit_mail_unwrap(&parent);
+}
+
+struct mail *edit_mail_get_mail(struct edit_mail *edmail)
+{
+ /* Return wrapped mail when nothing is modified yet */
+ if (!edmail->modified)
+ return &edmail->wrapped->mail;
+
+ return &edmail->mail.mail;
+}
+
+/*
+ * Editing
+ */
+
+static inline void edit_mail_modify(struct edit_mail *edmail)
+{
+ edmail->mail.mail.seq++;
+ edmail->modified = TRUE;
+ edmail->snapshot_modified = TRUE;
+}
+
+/* Header modification */
+
+static inline char *_header_value_unfold(const char *value)
+{
+ string_t *out;
+ unsigned int i;
+
+ for (i = 0; value[i] != '\0'; i++) {
+ if (value[i] == '\r' || value[i] == '\n')
+ break;
+ }
+ if (value[i] == '\0')
+ return i_strdup(value);
+
+ out = t_str_new(i + strlen(value+i) + 10);
+ str_append_data(out, value, i);
+ for (; value[i] != '\0'; i++) {
+ if (value[i] == '\n') {
+ i++;
+ if (value[i] == '\0')
+ break;
+
+ switch (value[i]) {
+ case ' ':
+ str_append_c(out, ' ');
+ break;
+ case '\t':
+ default:
+ str_append_c(out, '\t');
+ }
+ } else {
+ if (value[i] != '\r')
+ str_append_c(out, value[i]);
+ }
+ }
+
+ return i_strndup(str_c(out), str_len(out));
+}
+
+static struct _header_index *
+edit_mail_header_find(struct edit_mail *edmail, const char *field_name)
+{
+ struct _header_index *header_idx;
+
+ header_idx = edmail->headers_head;
+ while (header_idx != NULL) {
+ if (strcasecmp(header_idx->header->name, field_name) == 0)
+ return header_idx;
+
+ header_idx = header_idx->next;
+ }
+
+ return NULL;
+}
+
+static struct _header_index *
+edit_mail_header_create(struct edit_mail *edmail, const char *field_name)
+{
+ struct _header_index *header_idx;
+
+ header_idx = edit_mail_header_find(edmail, field_name);
+ if (header_idx == NULL) {
+ header_idx = i_new(struct _header_index, 1);
+ header_idx->header = _header_create(field_name);
+
+ DLLIST2_APPEND(&edmail->headers_head, &edmail->headers_tail,
+ header_idx);
+ }
+
+ return header_idx;
+}
+
+static struct _header_index *
+edit_mail_header_clone(struct edit_mail *edmail, struct _header *header)
+{
+ struct _header_index *header_idx;
+
+ header_idx = edmail->headers_head;
+ while (header_idx != NULL) {
+ if (header_idx->header == header)
+ return header_idx;
+
+ header_idx = header_idx->next;
+ }
+
+ header_idx = i_new(struct _header_index, 1);
+ header_idx->header = header;
+ _header_ref(header);
+ DLLIST2_APPEND(&edmail->headers_head, &edmail->headers_tail,
+ header_idx);
+
+ return header_idx;
+}
+
+static struct _header_field_index *
+edit_mail_header_field_create(struct edit_mail *edmail, const char *field_name,
+ const char *value)
+{
+ struct _header_index *header_idx;
+ struct _header *header;
+ struct _header_field_index *field_idx;
+ struct _header_field *field;
+ unsigned int lines;
+
+ /* Get/create header index item */
+ header_idx = edit_mail_header_create(edmail, field_name);
+ header = header_idx->header;
+
+ /* Create new field index item */
+ field_idx = i_new(struct _header_field_index, 1);
+ field_idx->header = header_idx;
+ field_idx->field = field = _header_field_create(header);
+
+ /* Create header field data (folded if necessary) */
+ T_BEGIN {
+ string_t *enc_value, *data;
+
+ enc_value = t_str_new(strlen(field_name) + strlen(value) + 64);
+ data = t_str_new(strlen(field_name) + strlen(value) + 128);
+
+ message_header_encode(value, enc_value);
+
+ lines = rfc2822_header_append(data, field_name,
+ str_c(enc_value), edmail->crlf,
+ &field->body_offset);
+
+ /* Copy to new field */
+ field->data = i_strndup(str_data(data), str_len(data));
+ field->size = str_len(data);
+ field->virtual_size = (edmail->crlf ?
+ field->size : field->size + lines);
+ field->lines = lines;
+ } T_END;
+
+ /* Record original (utf8) value */
+ field->utf8_value = _header_value_unfold(value);
+
+ return field_idx;
+}
+
+static void
+edit_mail_header_field_delete(struct edit_mail *edmail,
+ struct _header_field_index *field_idx,
+ bool update_index)
+{
+ struct _header_index *header_idx = field_idx->header;
+ struct _header_field *field = field_idx->field;
+
+ i_assert(header_idx != NULL);
+
+ edmail->hdr_size.physical_size -= field->size;
+ edmail->hdr_size.virtual_size -= field->virtual_size;
+ edmail->hdr_size.lines -= field->lines;
+
+ header_idx->count--;
+ if (update_index) {
+ if (header_idx->count == 0) {
+ DLLIST2_REMOVE(&edmail->headers_head,
+ &edmail->headers_tail, header_idx);
+ _header_unref(header_idx->header);
+ i_free(header_idx);
+ } else if (header_idx->first == field_idx) {
+ struct _header_field_index *hfield =
+ header_idx->first->next;
+
+ while (hfield != NULL && hfield->header != header_idx)
+ hfield = hfield->next;
+
+ i_assert(hfield != NULL);
+ header_idx->first = hfield;
+ } else if (header_idx->last == field_idx) {
+ struct _header_field_index *hfield =
+ header_idx->last->prev;
+
+ while (hfield != NULL && hfield->header != header_idx)
+ hfield = hfield->prev;
+
+ i_assert(hfield != NULL);
+ header_idx->last = hfield;
+ }
+ }
+
+ DLLIST2_REMOVE(&edmail->header_fields_head, &edmail->header_fields_tail,
+ field_idx);
+ _header_field_unref(field_idx->field);
+ i_free(field_idx);
+}
+
+static struct _header_field_index *
+edit_mail_header_field_replace(struct edit_mail *edmail,
+ struct _header_field_index *field_idx,
+ const char *newname, const char *newvalue,
+ bool update_index)
+{
+ struct _header_field_index *field_idx_new;
+ struct _header_index *header_idx = field_idx->header, *header_idx_new;
+ struct _header_field *field = field_idx->field, *field_new;
+
+ i_assert(header_idx != NULL);
+ i_assert(newname != NULL || newvalue != NULL);
+
+ if (newname == NULL)
+ newname = header_idx->header->name;
+ if (newvalue == NULL)
+ newvalue = field_idx->field->utf8_value;
+ field_idx_new = edit_mail_header_field_create(
+ edmail, newname, newvalue);
+ field_new = field_idx_new->field;
+ header_idx_new = field_idx_new->header;
+
+ edmail->hdr_size.physical_size -= field->size;
+ edmail->hdr_size.virtual_size -= field->virtual_size;
+ edmail->hdr_size.lines -= field->lines;
+
+ edmail->hdr_size.physical_size += field_new->size;
+ edmail->hdr_size.virtual_size += field_new->virtual_size;
+ edmail->hdr_size.lines += field_new->lines;
+
+ /* Replace header field index */
+ field_idx_new->prev = field_idx->prev;
+ field_idx_new->next = field_idx->next;
+ if (field_idx->prev != NULL)
+ field_idx->prev->next = field_idx_new;
+ if (field_idx->next != NULL)
+ field_idx->next->prev = field_idx_new;
+ if (edmail->header_fields_head == field_idx)
+ edmail->header_fields_head = field_idx_new;
+ if (edmail->header_fields_tail == field_idx)
+ edmail->header_fields_tail = field_idx_new;
+
+ if (header_idx_new == header_idx) {
+ if (header_idx->first == field_idx)
+ header_idx->first = field_idx_new;
+ if (header_idx->last == field_idx)
+ header_idx->last = field_idx_new;
+ } else {
+ header_idx->count--;
+ header_idx_new->count++;
+
+ if (update_index) {
+ if (header_idx->count == 0) {
+ DLLIST2_REMOVE(&edmail->headers_head,
+ &edmail->headers_tail,
+ header_idx);
+ _header_unref(header_idx->header);
+ i_free(header_idx);
+ } else if (header_idx->first == field_idx) {
+ struct _header_field_index *hfield =
+ header_idx->first->next;
+
+ while (hfield != NULL &&
+ hfield->header != header_idx)
+ hfield = hfield->next;
+
+ i_assert(hfield != NULL);
+ header_idx->first = hfield;
+ } else if (header_idx->last == field_idx) {
+ struct _header_field_index *hfield =
+ header_idx->last->prev;
+
+ while (hfield != NULL &&
+ hfield->header != header_idx)
+ hfield = hfield->prev;
+
+ i_assert(hfield != NULL);
+ header_idx->last = hfield;
+ }
+ if (header_idx_new->count > 0) {
+ struct _header_field_index *hfield;
+
+ hfield = edmail->header_fields_head;
+ while (hfield != NULL &&
+ hfield->header != header_idx_new)
+ hfield = hfield->next;
+
+ i_assert(hfield != NULL);
+ header_idx_new->first = hfield;
+
+ hfield = edmail->header_fields_tail;
+ while (hfield != NULL &&
+ hfield->header != header_idx_new)
+ hfield = hfield->prev;
+
+ i_assert(hfield != NULL);
+ header_idx_new->last = hfield;
+ }
+ }
+ }
+
+ _header_field_unref(field_idx->field);
+ i_free(field_idx);
+ return field_idx_new;
+}
+
+static inline char *
+_header_decode(const unsigned char *hdr_data, size_t hdr_data_len)
+{
+ string_t *str = t_str_new(512);
+
+ /* hdr_data is already unfolded */
+
+ /* Decode MIME encoded-words. */
+ message_header_decode_utf8((const unsigned char *)hdr_data,
+ hdr_data_len, str, NULL);
+ return i_strdup(str_c(str));
+}
+
+static int edit_mail_headers_parse(struct edit_mail *edmail)
+{
+ struct message_header_parser_ctx *hparser;
+ enum message_header_parser_flags hparser_flags =
+ MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP |
+ MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE;
+ struct message_header_line *hdr;
+ struct _header_index *header_idx;
+ struct _header_field_index *head = NULL, *tail = NULL, *current;
+ string_t *hdr_data;
+ uoff_t offset = 0, body_offset = 0, vsize_diff = 0;
+ unsigned int lines = 0;
+ int ret;
+
+ if (edmail->headers_parsed)
+ return 1;
+
+ i_stream_seek(edmail->wrapped_stream, 0);
+ hparser = message_parse_header_init(edmail->wrapped_stream, NULL,
+ hparser_flags);
+
+ T_BEGIN {
+ hdr_data = t_str_new(1024);
+ while ((ret = message_parse_header_next(hparser, &hdr)) > 0) {
+ struct _header_field_index *field_idx_new;
+ struct _header_field *field;
+
+ if (hdr->eoh) {
+ /* Record whether header ends in CRLF or LF */
+ edmail->eoh_crlf = hdr->crlf_newline;
+ }
+
+ if (hdr == NULL || hdr->eoh)
+ break;
+
+ /* Skip bad headers */
+ if (hdr->name_len == 0)
+ continue;
+ /* We deny the existence of any `Content-Length:'
+ header. This header is non-standard and it can wreak
+ havok when the message is modified.
+ */
+ if (strcasecmp(hdr->name, "Content-Length" ) == 0)
+ continue;
+
+ if (hdr->continued) {
+ /* Continued line of folded header */
+ buffer_append(hdr_data, hdr->value,
+ hdr->value_len);
+ } else {
+ /* First line of header */
+ offset = hdr->name_offset;
+ body_offset = hdr->name_len + hdr->middle_len;
+ str_truncate(hdr_data, 0);
+ buffer_append(hdr_data, hdr->name,
+ hdr->name_len);
+ buffer_append(hdr_data, hdr->middle,
+ hdr->middle_len);
+ buffer_append(hdr_data, hdr->value,
+ hdr->value_len);
+ lines = 0;
+ vsize_diff = 0;
+ }
+
+ if (!hdr->no_newline) {
+ lines++;
+
+ if (hdr->crlf_newline) {
+ buffer_append(hdr_data, "\r\n", 2);
+ } else {
+ buffer_append(hdr_data, "\n", 1);
+ vsize_diff++;
+ }
+ }
+
+ if (hdr->continues) {
+ hdr->use_full_value = TRUE;
+ continue;
+ }
+
+ /* Create new header field index entry */
+
+ field_idx_new = i_new(struct _header_field_index, 1);
+
+ header_idx = edit_mail_header_create(edmail, hdr->name);
+ header_idx->count++;
+ field_idx_new->header = header_idx;
+ field_idx_new->field = field =
+ _header_field_create(header_idx->header);
+
+ i_assert(body_offset > 0);
+ field->body_offset = body_offset;
+
+ field->utf8_value = _header_decode(hdr->full_value,
+ hdr->full_value_len);
+
+ field->size = str_len(hdr_data);
+ field->virtual_size = field->size + vsize_diff;
+ field->data = i_strndup(str_data(hdr_data),
+ field->size);
+ field->offset = offset;
+ field->lines = lines;
+
+ DLLIST2_APPEND(&head, &tail, field_idx_new);
+
+ edmail->hdr_size.physical_size += field->size;
+ edmail->hdr_size.virtual_size += field->virtual_size;
+ edmail->hdr_size.lines += lines;
+ }
+ } T_END;
+
+ message_parse_header_deinit(&hparser);
+
+ /* Blocking i/o required */
+ i_assert(ret != 0);
+
+ if (ret < 0 && edmail->wrapped_stream->stream_errno != 0) {
+ /* Error; clean up */
+ i_error("read(%s) failed: %s",
+ i_stream_get_name(edmail->wrapped_stream),
+ i_stream_get_error(edmail->wrapped_stream));
+ current = head;
+ while (current != NULL) {
+ struct _header_field_index *next = current->next;
+
+ _header_field_unref(current->field);
+ i_free(current);
+
+ current = next;
+ }
+
+ return ret;
+ }
+
+ /* Insert header field index items in main list */
+ if (head != NULL && tail != NULL) {
+ if (edmail->header_fields_appended != NULL) {
+ if (edmail->header_fields_head !=
+ edmail->header_fields_appended) {
+ edmail->header_fields_appended->prev->next = head;
+ head->prev = edmail->header_fields_appended->prev;
+ } else {
+ edmail->header_fields_head = head;
+ }
+
+ tail->next = edmail->header_fields_appended;
+ edmail->header_fields_appended->prev = tail;
+ } else if (edmail->header_fields_tail != NULL) {
+ edmail->header_fields_tail->next = head;
+ head->prev = edmail->header_fields_tail;
+ edmail->header_fields_tail = tail;
+ } else {
+ edmail->header_fields_head = head;
+ edmail->header_fields_tail = tail;
+ }
+ }
+
+ /* Rebuild header index */
+ current = edmail->header_fields_head;
+ while (current != NULL) {
+ if (current->header->first == NULL)
+ current->header->first = current;
+ current->header->last = current;
+
+ current = current->next;
+ }
+
+ /* Clear appended headers */
+ edmail->header_fields_appended = NULL;
+ edmail->appended_hdr_size.physical_size = 0;
+ edmail->appended_hdr_size.virtual_size = 0;
+ edmail->appended_hdr_size.lines = 0;
+
+ /* Do not parse headers again */
+ edmail->headers_parsed = TRUE;
+
+ return 1;
+}
+
+void edit_mail_header_add(struct edit_mail *edmail, const char *field_name,
+ const char *value, bool last)
+{
+ struct _header_index *header_idx;
+ struct _header_field_index *field_idx;
+ struct _header_field *field;
+
+ edit_mail_modify(edmail);
+
+ field_idx = edit_mail_header_field_create(edmail, field_name, value);
+ header_idx = field_idx->header;
+ field = field_idx->field;
+
+ /* Add it to the header field index */
+ if (last) {
+ DLLIST2_APPEND(&edmail->header_fields_head,
+ &edmail->header_fields_tail, field_idx);
+
+ header_idx->last = field_idx;
+ if (header_idx->first == NULL)
+ header_idx->first = field_idx;
+
+ if (!edmail->headers_parsed) {
+ if (edmail->header_fields_appended == NULL) {
+ /* Record beginning of appended headers */
+ edmail->header_fields_appended = field_idx;
+ }
+
+ edmail->appended_hdr_size.physical_size += field->size;
+ edmail->appended_hdr_size.virtual_size += field->virtual_size;
+ edmail->appended_hdr_size.lines += field->lines;
+ }
+ } else {
+ DLLIST2_PREPEND(&edmail->header_fields_head,
+ &edmail->header_fields_tail, field_idx);
+
+ header_idx->first = field_idx;
+ if (header_idx->last == NULL)
+ header_idx->last = field_idx;
+ }
+
+ header_idx->count++;
+
+ edmail->hdr_size.physical_size += field->size;
+ edmail->hdr_size.virtual_size += field->virtual_size;
+ edmail->hdr_size.lines += field->lines;
+}
+
+int edit_mail_header_delete(struct edit_mail *edmail, const char *field_name,
+ int index)
+{
+ struct _header_index *header_idx;
+ struct _header_field_index *field_idx;
+ int pos = 0;
+ int ret = 0;
+
+ /* Make sure headers are parsed */
+ if (edit_mail_headers_parse(edmail) <= 0)
+ return -1;
+
+ /* Find the header entry */
+ header_idx = edit_mail_header_find(edmail, field_name);
+ if (header_idx == NULL) {
+ /* Not found */
+ return 0;
+ }
+
+ /* Signal modification */
+ edit_mail_modify(edmail);
+
+ /* Iterate through all header fields and remove those that match */
+ field_idx = (index >= 0 ? header_idx->first : header_idx->last);
+ while (field_idx != NULL) {
+ struct _header_field_index *next =
+ (index >= 0 ? field_idx->next : field_idx->prev);
+
+ if (field_idx->field->header == header_idx->header) {
+ bool final;
+
+ if (index >= 0) {
+ pos++;
+ final = (header_idx->last == field_idx);
+ } else {
+ pos--;
+ final = (header_idx->first == field_idx);
+ }
+
+ if (index == 0 || index == pos) {
+ if (header_idx->first == field_idx)
+ header_idx->first = NULL;
+ if (header_idx->last == field_idx)
+ header_idx->last = NULL;
+ edit_mail_header_field_delete(
+ edmail, field_idx, FALSE);
+ ret++;
+ }
+
+ if (final || (index != 0 && index == pos))
+ break;
+ }
+
+ field_idx = next;
+ }
+
+ if (index == 0 || header_idx->count == 0) {
+ DLLIST2_REMOVE(&edmail->headers_head,
+ &edmail->headers_tail, header_idx);
+ _header_unref(header_idx->header);
+ i_free(header_idx);
+ } else if (header_idx->first == NULL || header_idx->last == NULL) {
+ struct _header_field_index *current =
+ edmail->header_fields_head;
+
+ while (current != NULL) {
+ if (current->header == header_idx) {
+ if (header_idx->first == NULL)
+ header_idx->first = current;
+ header_idx->last = current;
+ }
+ current = current->next;
+ }
+ }
+
+ return ret;
+}
+
+int edit_mail_header_replace(struct edit_mail *edmail,
+ const char *field_name, int index,
+ const char *newname, const char *newvalue)
+{
+ struct _header_index *header_idx, *header_idx_new;
+ struct _header_field_index *field_idx, *field_idx_new;
+ int pos = 0;
+ int ret = 0;
+
+ /* Make sure headers are parsed */
+ if (edit_mail_headers_parse(edmail) <= 0)
+ return -1;
+
+ /* Find the header entry */
+ header_idx = edit_mail_header_find(edmail, field_name);
+ if (header_idx == NULL) {
+ /* Not found */
+ return 0;
+ }
+
+ /* Signal modification */
+ edit_mail_modify(edmail);
+
+ /* Iterate through all header fields and replace those that match */
+ field_idx = (index >= 0 ? header_idx->first : header_idx->last);
+ field_idx_new = NULL;
+ while (field_idx != NULL) {
+ struct _header_field_index *next =
+ (index >= 0 ? field_idx->next : field_idx->prev);
+
+ if (field_idx->field->header == header_idx->header) {
+ bool final;
+
+ if (index >= 0) {
+ pos++;
+ final = (header_idx->last == field_idx);
+ } else {
+ pos--;
+ final = (header_idx->first == field_idx);
+ }
+
+ if (index == 0 || index == pos) {
+ if (header_idx->first == field_idx)
+ header_idx->first = NULL;
+ if (header_idx->last == field_idx)
+ header_idx->last = NULL;
+ field_idx_new = edit_mail_header_field_replace(
+ edmail, field_idx, newname, newvalue,
+ FALSE);
+ ret++;
+ }
+
+ if (final || (index != 0 && index == pos))
+ break;
+ }
+
+ field_idx = next;
+ }
+
+ /* Update old header index */
+ if (header_idx->count == 0) {
+ DLLIST2_REMOVE(&edmail->headers_head, &edmail->headers_tail,
+ header_idx);
+ _header_unref(header_idx->header);
+ i_free(header_idx);
+ } else if (header_idx->first == NULL || header_idx->last == NULL) {
+ struct _header_field_index *current =
+ edmail->header_fields_head;
+
+ while (current != NULL) {
+ if (current->header == header_idx) {
+ if (header_idx->first == NULL)
+ header_idx->first = current;
+ header_idx->last = current;
+ }
+ current = current->next;
+ }
+ }
+
+ /* Update new header index */
+ if (field_idx_new != NULL) {
+ struct _header_field_index *current =
+ edmail->header_fields_head;
+
+ header_idx_new = field_idx_new->header;
+ while (current != NULL) {
+ if (current->header == header_idx_new) {
+ if (header_idx_new->first == NULL)
+ header_idx_new->first = current;
+ header_idx_new->last = current;
+ }
+ current = current->next;
+ }
+ }
+
+ return ret;
+}
+
+struct edit_mail_header_iter
+{
+ struct edit_mail *mail;
+ struct _header_index *header;
+ struct _header_field_index *current;
+
+ bool reverse:1;
+};
+
+int edit_mail_headers_iterate_init(struct edit_mail *edmail,
+ const char *field_name, bool reverse,
+ struct edit_mail_header_iter **edhiter_r)
+{
+ struct edit_mail_header_iter *edhiter;
+ struct _header_index *header_idx = NULL;
+ struct _header_field_index *current = NULL;
+
+ /* Make sure headers are parsed */
+ if (edit_mail_headers_parse(edmail) <= 0) {
+ /* Failure */
+ return -1;
+ }
+
+ header_idx = edit_mail_header_find(edmail, field_name);
+
+ if (field_name != NULL && header_idx == NULL) {
+ current = NULL;
+ } else if (!reverse) {
+ current = (header_idx != NULL ?
+ header_idx->first : edmail->header_fields_head);
+ } else {
+ current = (header_idx != NULL ?
+ header_idx->last : edmail->header_fields_tail);
+ if (current->header == NULL)
+ current = current->prev;
+ }
+
+ if (current == NULL)
+ return 0;
+
+ edhiter = i_new(struct edit_mail_header_iter, 1);
+ edhiter->mail = edmail;
+ edhiter->header = header_idx;
+ edhiter->reverse = reverse;
+ edhiter->current = current;
+
+ *edhiter_r = edhiter;
+ return 1;
+}
+
+void edit_mail_headers_iterate_deinit(struct edit_mail_header_iter **edhiter)
+{
+ i_free(*edhiter);
+ *edhiter = NULL;
+}
+
+void edit_mail_headers_iterate_get(struct edit_mail_header_iter *edhiter,
+ const char **value_r)
+{
+ const char *raw;
+ int i;
+
+ i_assert(edhiter->current != NULL && edhiter->current->header != NULL);
+
+ raw = edhiter->current->field->utf8_value;
+ for (i = strlen(raw)-1; i >= 0; i--) {
+ if (raw[i] != ' ' && raw[i] != '\t')
+ break;
+ }
+
+ *value_r = t_strndup(raw, i+1);
+}
+
+bool edit_mail_headers_iterate_next(struct edit_mail_header_iter *edhiter)
+{
+ if (edhiter->current == NULL)
+ return FALSE;
+
+ do {
+ edhiter->current = (!edhiter->reverse ?
+ edhiter->current->next :
+ edhiter->current->prev );
+ } while (edhiter->current != NULL && edhiter->current->header != NULL &&
+ edhiter->header != NULL &&
+ edhiter->current->header != edhiter->header);
+
+ return (edhiter->current != NULL && edhiter->current->header != NULL);
+}
+
+bool edit_mail_headers_iterate_remove(struct edit_mail_header_iter *edhiter)
+{
+ struct _header_field_index *field_idx;
+ bool next;
+
+ i_assert(edhiter->current != NULL && edhiter->current->header != NULL);
+
+ edit_mail_modify(edhiter->mail);
+
+ field_idx = edhiter->current;
+ next = edit_mail_headers_iterate_next(edhiter);
+ edit_mail_header_field_delete(edhiter->mail, field_idx, TRUE);
+
+ return next;
+}
+
+bool edit_mail_headers_iterate_replace(struct edit_mail_header_iter *edhiter,
+ const char *newname,
+ const char *newvalue)
+{
+ struct _header_field_index *field_idx;
+ bool next;
+
+ i_assert(edhiter->current != NULL && edhiter->current->header != NULL);
+
+ edit_mail_modify(edhiter->mail);
+
+ field_idx = edhiter->current;
+ next = edit_mail_headers_iterate_next(edhiter);
+ edit_mail_header_field_replace(edhiter->mail, field_idx,
+ newname, newvalue, TRUE);
+
+ return next;
+}
+
+/* Body modification */
+
+// FIXME: implement
+
+/*
+ * Mail API
+ */
+
+static void edit_mail_close(struct mail *mail)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ edmail->wrapped->v.close(&edmail->wrapped->mail);
+}
+
+static void edit_mail_free(struct mail *mail)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ edmail->wrapped->v.free(&edmail->wrapped->mail);
+
+ edit_mail_unwrap(&edmail);
+}
+
+static void
+edit_mail_set_seq(struct mail *mail ATTR_UNUSED, uint32_t seq ATTR_UNUSED,
+ bool saving ATTR_UNUSED)
+{
+ i_panic("edit_mail_set_seq() not implemented");
+}
+
+static bool ATTR_NORETURN
+edit_mail_set_uid(struct mail *mail ATTR_UNUSED, uint32_t uid ATTR_UNUSED)
+{
+ i_panic("edit_mail_set_uid() not implemented");
+}
+
+static void edit_mail_set_uid_cache_updates(struct mail *mail, bool set)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ edmail->wrapped->v.set_uid_cache_updates(&edmail->wrapped->mail, set);
+}
+
+static void
+edit_mail_add_temp_wanted_fields(
+ struct mail *mail ATTR_UNUSED, enum mail_fetch_field fields ATTR_UNUSED,
+ struct mailbox_header_lookup_ctx *headers ATTR_UNUSED)
+{
+ /* Nothing */
+}
+
+static enum mail_flags edit_mail_get_flags(struct mail *mail)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ return edmail->wrapped->v.get_flags(&edmail->wrapped->mail);
+}
+
+static const char *const *edit_mail_get_keywords(struct mail *mail)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ return edmail->wrapped->v.get_keywords(&edmail->wrapped->mail);
+}
+
+static const ARRAY_TYPE(keyword_indexes) *
+edit_mail_get_keyword_indexes(struct mail *mail)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ return edmail->wrapped->v.get_keyword_indexes(&edmail->wrapped->mail);
+}
+
+static uint64_t edit_mail_get_modseq(struct mail *mail)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ return edmail->wrapped->v.get_modseq(&edmail->wrapped->mail);
+}
+
+static uint64_t edit_mail_get_pvt_modseq(struct mail *mail)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ return edmail->wrapped->v.get_pvt_modseq(&edmail->wrapped->mail);
+}
+
+static int edit_mail_get_parts(struct mail *mail, struct message_part **parts_r)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ return edmail->wrapped->v.get_parts(&edmail->wrapped->mail, parts_r);
+}
+
+static int
+edit_mail_get_date(struct mail *mail, time_t *date_r, int *timezone_r)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ return edmail->wrapped->v.get_date(&edmail->wrapped->mail,
+ date_r, timezone_r);
+}
+
+static int edit_mail_get_received_date(struct mail *mail, time_t *date_r)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ return edmail->wrapped->v.get_received_date(&edmail->wrapped->mail,
+ date_r);
+}
+
+static int edit_mail_get_save_date(struct mail *mail, time_t *date_r)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ return edmail->wrapped->v.get_save_date(&edmail->wrapped->mail, date_r);
+}
+
+static int edit_mail_get_virtual_size(struct mail *mail, uoff_t *size_r)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ if (!edmail->headers_parsed) {
+ *size_r = (edmail->wrapped_hdr_size.virtual_size +
+ edmail->wrapped_body_size.virtual_size);
+
+ if (!edmail->modified)
+ return 0;
+ } else {
+ *size_r = edmail->wrapped_body_size.virtual_size + 2;
+ }
+
+ *size_r += (edmail->hdr_size.virtual_size +
+ edmail->body_size.virtual_size);
+ return 0;
+}
+
+static int edit_mail_get_physical_size(struct mail *mail, uoff_t *size_r)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ *size_r = 0;
+ if (!edmail->headers_parsed) {
+ *size_r = (edmail->wrapped_hdr_size.physical_size +
+ edmail->wrapped_body_size.physical_size);
+
+ if (!edmail->modified)
+ return 0;
+ } else {
+ *size_r = (edmail->wrapped_body_size.physical_size +
+ (edmail->eoh_crlf ? 2 : 1));
+ }
+
+ *size_r += (edmail->hdr_size.physical_size +
+ edmail->body_size.physical_size);
+ return 0;
+}
+
+static int
+edit_mail_get_first_header(struct mail *mail, const char *field_name,
+ bool decode_to_utf8, const char **value_r)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+ struct _header_index *header_idx;
+ struct _header_field *field;
+ int ret;
+
+ /* Check whether mail headers were modified at all */
+ if (!edmail->modified || edmail->headers_head == NULL) {
+ /* Unmodified */
+ return edmail->wrapped->v.get_first_header(
+ &edmail->wrapped->mail, field_name, decode_to_utf8,
+ value_r);
+ }
+
+ /* Try to find modified header */
+ header_idx = edit_mail_header_find(edmail, field_name);
+ if (header_idx == NULL || header_idx->count == 0 ) {
+ if (!edmail->headers_parsed) {
+ /* No new header */
+ return edmail->wrapped->v.get_first_header(
+ &edmail->wrapped->mail, field_name,
+ decode_to_utf8, value_r);
+ }
+
+ *value_r = NULL;
+ return 0;
+ }
+
+ /* Get the first occurrence */
+ if (edmail->header_fields_appended == NULL) {
+ /* There are no appended headers, so first is found directly */
+ field = header_idx->first->field;
+ } else {
+ struct _header_field_index *field_idx;
+
+ /* Scan prepended headers */
+ field_idx = edmail->header_fields_head;
+ while (field_idx != NULL) {
+ if (field_idx->header == header_idx)
+ break;
+
+ if (field_idx == edmail->header_fields_appended) {
+ field_idx = NULL;
+ break;
+ }
+ field_idx = field_idx->next;
+ }
+
+ if (field_idx == NULL) {
+ /* Check original message */
+ ret = edmail->wrapped->v.get_first_header(
+ &edmail->wrapped->mail, field_name,
+ decode_to_utf8, value_r);
+ if (ret != 0)
+ return ret;
+
+ /* Use first (apparently appended) header */
+ field = header_idx->first->field;
+ } else {
+ field = field_idx->field;
+ }
+ }
+
+ if (decode_to_utf8)
+ *value_r = field->utf8_value;
+ else
+ *value_r = (const char *)(field->data + field->body_offset);
+ return 1;
+}
+
+static int
+edit_mail_get_headers(struct mail *mail, const char *field_name,
+ bool decode_to_utf8, const char *const **value_r)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+ struct _header_index *header_idx;
+ struct _header_field_index *field_idx;
+ const char *const *headers;
+ ARRAY(const char *) header_values;
+
+ if (!edmail->modified || edmail->headers_head == NULL) {
+ /* Unmodified */
+ return edmail->wrapped->v.get_headers(
+ &edmail->wrapped->mail, field_name, decode_to_utf8,
+ value_r);
+ }
+
+ header_idx = edit_mail_header_find(edmail, field_name);
+ if (header_idx == NULL || header_idx->count == 0 ) {
+ if (!edmail->headers_parsed) {
+ /* No new header */
+ return edmail->wrapped->v.get_headers(
+ &edmail->wrapped->mail, field_name,
+ decode_to_utf8, value_r);
+ }
+
+ p_array_init(&header_values, edmail->mail.pool, 1);
+ (void)array_append_space(&header_values);
+ *value_r = array_idx(&header_values, 0);
+ return 0;
+ }
+
+ /* Merge */
+
+ /* Read original headers too if message headers are not parsed */
+ headers = NULL;
+ if (!edmail->headers_parsed &&
+ edmail->wrapped->v.get_headers(&edmail->wrapped->mail, field_name,
+ decode_to_utf8, &headers) < 0)
+ return -1;
+
+ /* Fill result array */
+ p_array_init(&header_values, edmail->mail.pool, 32);
+ field_idx = header_idx->first;
+ while (field_idx != NULL) {
+ /* If current field is the first appended one, we need to add
+ original headers first.
+ */
+ if (field_idx == edmail->header_fields_appended &&
+ headers != NULL) {
+ while (*headers != NULL) {
+ array_append(&header_values, headers, 1);
+ headers++;
+ }
+ }
+
+ /* Add modified header to the list */
+ if (field_idx->field->header == header_idx->header) {
+ struct _header_field *field = field_idx->field;
+
+ const char *value;
+ if (decode_to_utf8)
+ value = field->utf8_value;
+ else {
+ value = (const char *)(field->data +
+ field->body_offset);
+ }
+
+ array_append(&header_values, &value, 1);
+
+ if (field_idx == header_idx->last)
+ break;
+ }
+
+ field_idx = field_idx->next;
+ }
+
+ /* Add original headers if necessary */
+ if (headers != NULL) {
+ while (*headers != NULL) {
+ array_append(&header_values, headers, 1);
+ headers++;
+ }
+ }
+
+ (void)array_append_space(&header_values);
+ *value_r = array_idx(&header_values, 0);
+ return 1;
+}
+
+static int ATTR_NORETURN
+edit_mail_get_header_stream(
+ struct mail *mail ATTR_UNUSED,
+ struct mailbox_header_lookup_ctx *headers ATTR_UNUSED,
+ struct istream **stream_r ATTR_UNUSED)
+{
+ // FIXME: implement!
+ i_panic("edit_mail_get_header_stream() not implemented");
+}
+
+static int
+edit_mail_get_stream(struct mail *mail, bool get_body ATTR_UNUSED,
+ struct message_size *hdr_size,
+ struct message_size *body_size, struct istream **stream_r)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ if (edmail->stream == NULL)
+ edmail->stream = edit_mail_istream_create(edmail);
+
+ if (hdr_size != NULL) {
+ *hdr_size = edmail->wrapped_hdr_size;
+ hdr_size->physical_size += edmail->hdr_size.physical_size;
+ hdr_size->virtual_size += edmail->hdr_size.virtual_size;
+ hdr_size->lines += edmail->hdr_size.lines;
+ }
+
+ if (body_size != NULL)
+ *body_size = edmail->wrapped_body_size;
+
+ *stream_r = edmail->stream;
+ i_stream_seek(edmail->stream, 0);
+
+ return 0;
+}
+
+static int
+edit_mail_get_special(struct mail *mail, enum mail_fetch_field field,
+ const char **value_r)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ if (edmail->modified) {
+ /* Block certain fields when modified */
+
+ switch (field) {
+ case MAIL_FETCH_GUID:
+ /* This is in essence a new message */
+ *value_r = "";
+ return 0;
+ case MAIL_FETCH_STORAGE_ID:
+ /* Prevent hardlink copying */
+ *value_r = "";
+ return 0;
+ default:
+ break;
+ }
+ }
+
+ return edmail->wrapped->v.get_special(&edmail->wrapped->mail,
+ field, value_r);
+}
+
+static int
+edit_mail_get_backend_mail(struct mail *mail, struct mail **real_mail_r)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ *real_mail_r = edit_mail_get_mail(edmail);
+ return 0;
+}
+
+static void
+edit_mail_update_flags(struct mail *mail, enum modify_type modify_type,
+ enum mail_flags flags)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ edmail->wrapped->v.update_flags(&edmail->wrapped->mail,
+ modify_type, flags);
+}
+
+static void
+edit_mail_update_keywords(struct mail *mail, enum modify_type modify_type,
+ struct mail_keywords *keywords)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ edmail->wrapped->v.update_keywords(&edmail->wrapped->mail,
+ modify_type, keywords);
+}
+
+static void edit_mail_update_modseq(struct mail *mail, uint64_t min_modseq)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ edmail->wrapped->v.update_modseq(&edmail->wrapped->mail, min_modseq);
+}
+
+static void
+edit_mail_update_pvt_modseq(struct mail *mail, uint64_t min_pvt_modseq)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ edmail->wrapped->v.update_pvt_modseq(&edmail->wrapped->mail,
+ min_pvt_modseq);
+}
+
+static void edit_mail_update_pop3_uidl(struct mail *mail, const char *uidl)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ if (edmail->wrapped->v.update_pop3_uidl != NULL) {
+ edmail->wrapped->v.update_pop3_uidl(
+ &edmail->wrapped->mail, uidl);
+ }
+}
+
+static void edit_mail_expunge(struct mail *mail ATTR_UNUSED)
+{
+ /* NOOP */
+}
+
+static void
+edit_mail_set_cache_corrupted(struct mail *mail, enum mail_fetch_field field,
+ const char *reason)
+{
+ struct edit_mail *edmail = (struct edit_mail *)mail;
+
+ edmail->wrapped->v.set_cache_corrupted(&edmail->wrapped->mail,
+ field, reason);
+}
+
+static struct mail_vfuncs edit_mail_vfuncs = {
+ edit_mail_close,
+ edit_mail_free,
+ edit_mail_set_seq,
+ edit_mail_set_uid,
+ edit_mail_set_uid_cache_updates,
+ NULL,
+ NULL,
+ edit_mail_add_temp_wanted_fields,
+ edit_mail_get_flags,
+ edit_mail_get_keywords,
+ edit_mail_get_keyword_indexes,
+ edit_mail_get_modseq,
+ edit_mail_get_pvt_modseq,
+ edit_mail_get_parts,
+ edit_mail_get_date,
+ edit_mail_get_received_date,
+ edit_mail_get_save_date,
+ edit_mail_get_virtual_size,
+ edit_mail_get_physical_size,
+ edit_mail_get_first_header,
+ edit_mail_get_headers,
+ edit_mail_get_header_stream,
+ edit_mail_get_stream,
+ index_mail_get_binary_stream,
+ edit_mail_get_special,
+ edit_mail_get_backend_mail,
+ edit_mail_update_flags,
+ edit_mail_update_keywords,
+ edit_mail_update_modseq,
+ edit_mail_update_pvt_modseq,
+ edit_mail_update_pop3_uidl,
+ edit_mail_expunge,
+ edit_mail_set_cache_corrupted,
+ NULL,
+};
+
+/*
+ * Edit Mail Stream
+ */
+
+struct edit_mail_istream {
+ struct istream_private istream;
+ pool_t pool;
+
+ struct edit_mail *mail;
+
+ struct _header_field_index *cur_header;
+ uoff_t cur_header_v_offset;
+
+ bool parent_buffer:1;
+ bool header_read:1;
+ bool eof:1;
+};
+
+static void edit_mail_istream_destroy(struct iostream_private *stream)
+{
+ struct edit_mail_istream *edstream =
+ (struct edit_mail_istream *)stream;
+
+ i_stream_unref(&edstream->istream.parent);
+ i_stream_free_buffer(&edstream->istream);
+ pool_unref(&edstream->pool);
+}
+
+static ssize_t
+merge_from_parent(struct edit_mail_istream *edstream, uoff_t parent_v_offset,
+ uoff_t parent_end_v_offset, uoff_t copy_v_offset)
+{
+ struct istream_private *stream = &edstream->istream;
+ uoff_t v_offset, append_v_offset;
+ const unsigned char *data;
+ size_t pos, cur_pos, parent_bytes_left;
+ bool parent_buffer = edstream->parent_buffer;
+ ssize_t ret;
+
+ i_assert(parent_v_offset <= parent_end_v_offset);
+ edstream->parent_buffer = FALSE;
+
+ v_offset = stream->istream.v_offset;
+ if (v_offset >= copy_v_offset) {
+ i_assert((v_offset - copy_v_offset) <= parent_end_v_offset);
+ if ((v_offset - copy_v_offset) == parent_end_v_offset) {
+ /* Parent data is all read */
+ return 0;
+ }
+ }
+
+ /* Determine where we are appending more data to the stream */
+ append_v_offset = v_offset + (stream->pos - stream->skip);
+
+ if (v_offset >= copy_v_offset) {
+ /* Parent buffer used */
+ cur_pos = (stream->pos - stream->skip);
+ parent_v_offset += (v_offset - copy_v_offset);
+ } else {
+ cur_pos = 0;
+ i_assert(append_v_offset >= copy_v_offset);
+ parent_v_offset += (append_v_offset - copy_v_offset);
+ }
+
+ /* Seek parent to required position */
+ i_stream_seek(stream->parent, parent_v_offset);
+
+ /* Read from parent */
+ data = i_stream_get_data(stream->parent, &pos);
+ if (pos > cur_pos)
+ ret = 0;
+ else do {
+ /* Use normal read here, since parent data can be returned
+ directly to caller. */
+ ret = i_stream_read(stream->parent);
+
+ stream->istream.stream_errno = stream->parent->stream_errno;
+ stream->istream.eof = stream->parent->eof;
+ edstream->eof = stream->parent->eof;
+ data = i_stream_get_data(stream->parent, &pos);
+ /* Check again, in case the parent stream had been seeked
+ backwards and the previous read() didn't get us far
+ enough. */
+ } while (pos <= cur_pos && ret > 0);
+
+ /* Don't read beyond parent end offset */
+ if (parent_end_v_offset != (uoff_t)-1) {
+ parent_bytes_left = (size_t)(parent_end_v_offset -
+ parent_v_offset);
+ if (pos >= parent_bytes_left) {
+ pos = parent_bytes_left;
+ }
+ }
+
+ if (v_offset < copy_v_offset || ret == -2 ||
+ (parent_buffer && (append_v_offset + 1) >= parent_end_v_offset)) {
+ /* Merging with our local buffer; copying data from parent */
+ if (pos > 0) {
+ size_t avail;
+
+ if (parent_buffer) {
+ stream->pos = stream->skip = 0;
+ stream->buffer = NULL;
+ }
+ if (!i_stream_try_alloc(stream, pos, &avail))
+ return -2;
+ pos = (pos > avail ? avail : pos);
+
+ memcpy(stream->w_buffer + stream->pos, data, pos);
+ stream->pos += pos;
+ stream->buffer = stream->w_buffer;
+
+ if (cur_pos >= pos)
+ ret = 0;
+ else
+ ret = (ssize_t)(pos - cur_pos);
+ } else {
+ ret = (ret == 0 ? 0 : -1);
+ }
+ } else {
+ /* Just passing buffers from parent; no copying */
+ ret = (pos > cur_pos ?
+ (ssize_t)(pos - cur_pos) : (ret == 0 ? 0 : -1));
+ stream->buffer = data;
+ stream->pos = pos;
+ stream->skip = 0;
+ edstream->parent_buffer = TRUE;
+ }
+
+ i_assert(ret != -1 || stream->istream.eof ||
+ stream->istream.stream_errno != 0);
+ return ret;
+}
+
+static ssize_t merge_modified_headers(struct edit_mail_istream *edstream)
+{
+ struct istream_private *stream = &edstream->istream;
+ struct edit_mail *edmail = edstream->mail;
+ uoff_t v_offset = stream->istream.v_offset, append_v_offset;
+ size_t appended, written, avail, size;
+
+ if (edstream->cur_header == NULL) {
+ /* No (more) headers */
+ return 0;
+ }
+
+ /* Caller must already have committed remaining parent data to
+ our stream buffer. */
+ i_assert(!edstream->parent_buffer);
+
+ /* Add modified headers to buffer */
+ written = 0;
+ while (edstream->cur_header != NULL) {
+ size_t wsize;
+
+ /* Determine what part of the header was already buffered */
+ append_v_offset = v_offset + (stream->pos - stream->skip);
+ i_assert(append_v_offset >= edstream->cur_header_v_offset);
+ if (append_v_offset >= edstream->cur_header_v_offset)
+ appended = (size_t)(append_v_offset -
+ edstream->cur_header_v_offset);
+ else
+ appended = 0;
+ i_assert(appended <= edstream->cur_header->field->size);
+
+ /* Determine how much we want to write */
+ size = edstream->cur_header->field->size - appended;
+ if (size > 0) {
+ /* Determine how much we can write */
+ if (!i_stream_try_alloc(stream, size, &avail)) {
+ if (written == 0)
+ return -2;
+ break;
+ }
+ wsize = (size >= avail ? avail : size);
+
+ /* Write (part of) the header to buffer */
+ memcpy(stream->w_buffer + stream->pos,
+ edstream->cur_header->field->data + appended,
+ wsize);
+ stream->pos += wsize;
+ stream->buffer = stream->w_buffer;
+ written += wsize;
+
+ if (wsize < size) {
+ /* Could not write whole header; finish here */
+ break;
+ }
+ }
+
+ /* Skip to next header */
+ edstream->cur_header_v_offset +=
+ edstream->cur_header->field->size;
+ edstream->cur_header = edstream->cur_header->next;
+
+ /* Stop at end of prepended headers if original header is left
+ unparsed */
+ if (!edmail->headers_parsed &&
+ edstream->cur_header == edmail->header_fields_appended)
+ edstream->cur_header = NULL;
+ }
+
+ if (edstream->cur_header == NULL) {
+ /* Clear offset too, just to be tidy */
+ edstream->cur_header_v_offset = 0;
+ }
+
+ i_assert(written > 0);
+ return (ssize_t)written;
+}
+
+static ssize_t edit_mail_istream_read(struct istream_private *stream)
+{
+ struct edit_mail_istream *edstream =
+ (struct edit_mail_istream *)stream;
+ struct edit_mail *edmail = edstream->mail;
+ uoff_t v_offset, append_v_offset;
+ uoff_t parent_v_offset, parent_end_v_offset, copy_v_offset;
+ uoff_t prep_hdr_size, hdr_size;
+ ssize_t ret = 0;
+
+ if (edstream->eof) {
+ stream->istream.eof = TRUE;
+ return -1;
+ }
+
+ if (edstream->parent_buffer && stream->skip == stream->pos) {
+ edstream->parent_buffer = FALSE;
+ stream->pos = stream->skip = 0;
+ stream->buffer = NULL;
+ }
+
+ /* Merge prepended headers */
+ if (!edstream->parent_buffer) {
+ ret = merge_modified_headers(edstream);
+ if (ret != 0)
+ return ret;
+ }
+ v_offset = stream->istream.v_offset;
+ append_v_offset = v_offset + (stream->pos - stream->skip);
+
+ if (!edmail->headers_parsed && edmail->header_fields_appended != NULL &&
+ !edstream->header_read) {
+ /* Output headers from original stream */
+
+ /* Size of the prepended header */
+ i_assert(edmail->hdr_size.physical_size >=
+ edmail->appended_hdr_size.physical_size);
+ prep_hdr_size = (edmail->hdr_size.physical_size -
+ edmail->appended_hdr_size.physical_size);
+
+ /* Calculate offset of header end or appended header. Any final
+ CR is dealt with later.
+ */
+ hdr_size = (prep_hdr_size +
+ edmail->wrapped_hdr_size.physical_size);
+ i_assert(hdr_size > 0);
+ if (append_v_offset <= (hdr_size - 1) &&
+ edmail->wrapped_hdr_size.physical_size > 0) {
+ parent_v_offset = stream->parent_start_offset;
+ parent_end_v_offset =
+ (stream->parent_start_offset +
+ edmail->wrapped_hdr_size.physical_size - 1);
+ copy_v_offset = prep_hdr_size;
+
+ ret = merge_from_parent(edstream, parent_v_offset,
+ parent_end_v_offset,
+ copy_v_offset);
+ if (ret < 0)
+ return ret;
+ append_v_offset = (v_offset +
+ (stream->pos - stream->skip));
+ i_assert(append_v_offset <= hdr_size - 1);
+
+ if (append_v_offset == hdr_size - 1) {
+ /* Strip final CR too when it is present */
+ if (stream->buffer != NULL &&
+ stream->buffer[stream->pos-1] == '\r') {
+ stream->pos--;
+ append_v_offset--;
+ ret--;
+ }
+
+ i_assert(ret >= 0);
+ edstream->cur_header =
+ edmail->header_fields_appended;
+ edstream->cur_header_v_offset = append_v_offset;
+ if (!edstream->parent_buffer)
+ edstream->header_read = TRUE;
+ }
+
+ if (ret != 0)
+ return ret;
+ } else {
+ edstream->header_read = TRUE;
+ }
+
+ /* Merge appended headers */
+ ret = merge_modified_headers(edstream);
+ if (ret != 0)
+ return ret;
+ }
+
+ /* Header does not come from original mail at all */
+ if (edmail->headers_parsed) {
+ parent_v_offset = (stream->parent_start_offset +
+ edmail->wrapped_hdr_size.physical_size -
+ (edmail->eoh_crlf ? 2 : 1));
+ copy_v_offset = edmail->hdr_size.physical_size;
+ /* Header comes partially from original mail and headers are added
+ between header and body. */
+ } else if (edmail->header_fields_appended != NULL) {
+ parent_v_offset = (stream->parent_start_offset +
+ edmail->wrapped_hdr_size.physical_size -
+ (edmail->eoh_crlf ? 2 : 1));
+ copy_v_offset = (edmail->hdr_size.physical_size +
+ edmail->wrapped_hdr_size.physical_size -
+ (edmail->eoh_crlf ? 2 : 1));
+ /* Header comes partially from original mail, but headers are only
+ prepended. */
+ } else {
+ parent_v_offset = stream->parent_start_offset;
+ copy_v_offset = edmail->hdr_size.physical_size;
+ }
+
+ return merge_from_parent(edstream, parent_v_offset, (uoff_t)-1,
+ copy_v_offset);
+}
+
+static void
+stream_reset_to(struct edit_mail_istream *edstream, uoff_t v_offset)
+{
+ edstream->istream.istream.v_offset = v_offset;
+ edstream->istream.skip = 0;
+ edstream->istream.pos = 0;
+ edstream->istream.buffer = NULL;
+ edstream->parent_buffer = FALSE;
+ edstream->eof = FALSE;
+ i_stream_seek(edstream->istream.parent, 0);
+}
+
+static void
+edit_mail_istream_seek(struct istream_private *stream, uoff_t v_offset,
+ bool mark ATTR_UNUSED)
+{
+ struct edit_mail_istream *edstream =
+ (struct edit_mail_istream *)stream;
+ struct _header_field_index *cur_header;
+ struct edit_mail *edmail = edstream->mail;
+ uoff_t offset;
+
+ edstream->header_read = FALSE;
+ edstream->cur_header = NULL;
+ edstream->cur_header_v_offset = 0;
+
+ /* The beginning */
+ if (v_offset == 0) {
+ stream_reset_to(edstream, 0);
+
+ if (edmail->header_fields_head !=
+ edmail->header_fields_appended)
+ edstream->cur_header = edmail->header_fields_head;
+ return;
+ }
+
+ /* Inside (prepended) headers */
+ if (edmail->headers_parsed) {
+ offset = edmail->hdr_size.physical_size;
+ } else {
+ offset = (edmail->hdr_size.physical_size -
+ edmail->appended_hdr_size.physical_size);
+ }
+
+ if (v_offset < offset) {
+ stream_reset_to(edstream, v_offset);
+
+ /* Find the header */
+ cur_header = edmail->header_fields_head;
+ i_assert(cur_header != NULL &&
+ cur_header != edmail->header_fields_appended);
+ edstream->cur_header_v_offset = 0;
+ offset = cur_header->field->size;
+ while (v_offset > offset) {
+ cur_header = cur_header->next;
+ i_assert(cur_header != NULL &&
+ cur_header != edmail->header_fields_appended);
+
+ edstream->cur_header_v_offset = offset;
+ offset += cur_header->field->size;
+ }
+
+ edstream->cur_header = cur_header;
+ return;
+ }
+
+ if (!edmail->headers_parsed) {
+ /* Inside original header */
+ offset = (edmail->hdr_size.physical_size -
+ edmail->appended_hdr_size.physical_size +
+ edmail->wrapped_hdr_size.physical_size);
+ if (v_offset < offset) {
+ stream_reset_to(edstream, v_offset);
+ return;
+ }
+
+ edstream->header_read = TRUE;
+
+ /* Inside appended header */
+ offset = (edmail->hdr_size.physical_size +
+ edmail->wrapped_hdr_size.physical_size);
+ if (v_offset < offset) {
+ stream_reset_to(edstream, v_offset);
+
+ offset -= edmail->appended_hdr_size.physical_size;
+
+ cur_header = edmail->header_fields_appended;
+ i_assert(cur_header != NULL);
+ edstream->cur_header_v_offset = offset;
+ offset += cur_header->field->size;
+
+ while (v_offset > offset) {
+ cur_header = cur_header->next;
+ i_assert(cur_header != NULL);
+
+ edstream->cur_header_v_offset = offset;
+ offset += cur_header->field->size;
+ }
+
+ edstream->cur_header = cur_header;
+ return;
+ }
+ }
+
+ stream_reset_to(edstream, v_offset);
+ edstream->cur_header = NULL;
+}
+
+static void ATTR_NORETURN
+edit_mail_istream_sync(struct istream_private *stream ATTR_UNUSED)
+{
+ i_panic("edit-mail istream sync() not implemented");
+}
+
+static int
+edit_mail_istream_stat(struct istream_private *stream, bool exact)
+{
+ struct edit_mail_istream *edstream =
+ (struct edit_mail_istream *)stream;
+ struct edit_mail *edmail = edstream->mail;
+ const struct stat *st;
+
+ /* Stat the original stream */
+ if (i_stream_stat(stream->parent, exact, &st) < 0)
+ return -1;
+
+ stream->statbuf = *st;
+ if (st->st_size == -1 || !exact)
+ return 0;
+
+ if (!edmail->headers_parsed) {
+ if (!edmail->modified)
+ return 0;
+ } else {
+ stream->statbuf.st_size =
+ (edmail->wrapped_body_size.physical_size +
+ (edmail->eoh_crlf ? 2 : 1));
+ }
+
+ stream->statbuf.st_size += (edmail->hdr_size.physical_size +
+ edmail->body_size.physical_size);
+ return 0;
+}
+
+struct istream *edit_mail_istream_create(struct edit_mail *edmail)
+{
+ struct edit_mail_istream *edstream;
+ struct istream *wrapped = edmail->wrapped_stream;
+
+ edstream = i_new(struct edit_mail_istream, 1);
+ edstream->pool = pool_alloconly_create(MEMPOOL_GROWING
+ "edit mail stream", 4096);
+ edstream->mail = edmail;
+
+ edstream->istream.max_buffer_size =
+ wrapped->real_stream->max_buffer_size;
+
+ edstream->istream.iostream.destroy = edit_mail_istream_destroy;
+ edstream->istream.read = edit_mail_istream_read;
+ edstream->istream.seek = edit_mail_istream_seek;
+ edstream->istream.sync = edit_mail_istream_sync;
+ edstream->istream.stat = edit_mail_istream_stat;
+
+ edstream->istream.istream.readable_fd = FALSE;
+ edstream->istream.istream.blocking = wrapped->blocking;
+ edstream->istream.istream.seekable = wrapped->seekable;
+
+ if (edmail->header_fields_head != edmail->header_fields_appended)
+ edstream->cur_header = edmail->header_fields_head;
+
+ i_stream_seek(wrapped, 0);
+
+ return i_stream_create(&edstream->istream, wrapped, -1, 0);
+}
diff --git a/pigeonhole/src/lib-sieve/util/edit-mail.h b/pigeonhole/src/lib-sieve/util/edit-mail.h
new file mode 100644
index 0000000..14d2eaa
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/util/edit-mail.h
@@ -0,0 +1,47 @@
+#ifndef EDIT_MAIL_H
+#define EDIT_MAIL_H
+
+struct edit_mail;
+
+struct edit_mail *edit_mail_wrap(struct mail *mail);
+void edit_mail_unwrap(struct edit_mail **edmail);
+struct edit_mail *edit_mail_snapshot(struct edit_mail *edmail);
+
+void edit_mail_reset(struct edit_mail *edmail);
+
+struct mail *edit_mail_get_mail(struct edit_mail *edmail);
+
+/*
+ * Header modification
+ */
+
+/* Simple API */
+
+void edit_mail_header_add(struct edit_mail *edmail, const char *field_name,
+ const char *value, bool last);
+int edit_mail_header_delete(struct edit_mail *edmail,
+ const char *field_name, int index);
+int edit_mail_header_replace(struct edit_mail *edmail,
+ const char *field_name, int index,
+ const char *newname, const char *newvalue);
+
+/* Iterator */
+
+struct edit_mail_header_iter;
+
+int edit_mail_headers_iterate_init(struct edit_mail *edmail,
+ const char *field_name, bool reverse,
+ struct edit_mail_header_iter **edhiter_r);
+void edit_mail_headers_iterate_deinit(struct edit_mail_header_iter **edhiter);
+
+void edit_mail_headers_iterate_get(struct edit_mail_header_iter *edhiter,
+ const char **value_r);
+
+bool edit_mail_headers_iterate_next(struct edit_mail_header_iter *edhiter);
+
+bool edit_mail_headers_iterate_remove(struct edit_mail_header_iter *edhiter);
+bool edit_mail_headers_iterate_replace(struct edit_mail_header_iter *edhiter,
+ const char *newname,
+ const char *newvalue);
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/util/mail-raw.c b/pigeonhole/src/lib-sieve/util/mail-raw.c
new file mode 100644
index 0000000..b357fe1
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/util/mail-raw.c
@@ -0,0 +1,247 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "istream.h"
+#include "istream-seekable.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "strescape.h"
+#include "safe-mkstemp.h"
+#include "path-util.h"
+#include "message-address.h"
+#include "mbox-from.h"
+#include "raw-storage.h"
+#include "mail-namespace.h"
+#include "master-service.h"
+#include "master-service-settings.h"
+#include "settings-parser.h"
+#include "mail-raw.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pwd.h>
+
+/*
+ * Configuration
+ */
+
+#define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON"
+
+/* After buffer grows larger than this, create a temporary file to /tmp
+ where to read the mail. */
+#define MAIL_MAX_MEMORY_BUFFER (1024*128)
+
+static const char *wanted_headers[] = {
+ "From", "Message-ID", "Subject", "Return-Path",
+ NULL
+};
+
+/*
+ * Global data
+ */
+
+struct mail_raw_user {
+ struct mail_namespace *ns;
+ struct mail_user *mail_user;
+};
+
+/*
+ * Raw mail implementation
+ */
+
+static int seekable_fd_callback
+(const char **path_r, void *context)
+{
+ struct mail_user *ruser = (struct mail_user *)context;
+ string_t *path;
+ int fd;
+
+ path = t_str_new(128);
+ mail_user_set_get_temp_prefix(path, ruser->set);
+ fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
+ if (fd == -1) {
+ i_error("safe_mkstemp(%s) failed: %m", str_c(path));
+ return -1;
+ }
+
+ /* we just want the fd, unlink it */
+ if (i_unlink(str_c(path)) < 0) {
+ /* shouldn't happen.. */
+ i_close_fd(&fd);
+ return -1;
+ }
+
+ *path_r = str_c(path);
+ return fd;
+}
+
+static struct istream *mail_raw_create_stream
+(struct mail_user *ruser, int fd, time_t *mtime_r, const char **sender)
+{
+ struct istream *input, *input2, *input_list[2];
+ const unsigned char *data;
+ size_t i, size;
+ int ret, tz;
+ char *env_sender = NULL;
+
+ *mtime_r = (time_t)-1;
+ fd_set_nonblock(fd, FALSE);
+
+ input = i_stream_create_fd(fd, 4096);
+ input->blocking = TRUE;
+ /* If input begins with a From-line, drop it */
+ ret = i_stream_read_bytes(input, &data, &size, 5);
+ if (ret > 0 && memcmp(data, "From ", 5) == 0) {
+ /* skip until the first LF */
+ i_stream_skip(input, 5);
+ while ( i_stream_read_more(input, &data, &size) > 0 ) {
+ for (i = 0; i < size; i++) {
+ if (data[i] == '\n')
+ break;
+ }
+ if (i != size) {
+ (void)mbox_from_parse(data, i, mtime_r, &tz, &env_sender);
+ i_stream_skip(input, i + 1);
+ break;
+ }
+ i_stream_skip(input, size);
+ }
+ }
+
+ if (env_sender != NULL && sender != NULL) {
+ *sender = t_strdup(env_sender);
+ }
+ i_free(env_sender);
+
+ if (input->v_offset == 0) {
+ input2 = input;
+ i_stream_ref(input2);
+ } else {
+ input2 = i_stream_create_limit(input, (uoff_t)-1);
+ }
+ i_stream_unref(&input);
+
+ input_list[0] = input2; input_list[1] = NULL;
+ input = i_stream_create_seekable(input_list, MAIL_MAX_MEMORY_BUFFER,
+ seekable_fd_callback, (void*)ruser);
+ i_stream_unref(&input2);
+ return input;
+}
+
+/*
+ * Init/Deinit
+ */
+
+struct mail_user *mail_raw_user_create
+(struct master_service *service, struct mail_user *mail_user)
+{
+ void **sets = master_service_settings_get_others(service);
+
+ return raw_storage_create_from_set(mail_user->set_info, sets[0]);
+}
+
+/*
+ * Open raw mail data
+ */
+
+static struct mail_raw *mail_raw_create
+(struct mail_user *ruser, struct istream *input,
+ const char *mailfile, const char *sender, time_t mtime)
+{
+ struct mail_raw *mailr;
+ struct mailbox_header_lookup_ctx *headers_ctx;
+ const char *envelope_sender, *error;
+ int ret;
+
+ if ( mailfile != NULL && *mailfile != '/' )
+ if (t_abspath(mailfile, &mailfile, &error) < 0)
+ i_fatal("t_abspath(%s) failed: %s",
+ mailfile, error);
+
+ mailr = i_new(struct mail_raw, 1);
+
+ envelope_sender = sender != NULL ? sender : DEFAULT_ENVELOPE_SENDER;
+ if ( mailfile == NULL ) {
+ ret = raw_mailbox_alloc_stream(ruser, input, mtime,
+ envelope_sender, &mailr->box);
+ } else {
+ ret = raw_mailbox_alloc_path(ruser, mailfile, (time_t)-1,
+ envelope_sender, &mailr->box);
+ }
+
+ if ( ret < 0 ) {
+ if ( mailfile == NULL ) {
+ i_fatal("Can't open delivery mail as raw: %s",
+ mailbox_get_last_internal_error(mailr->box, NULL));
+ } else {
+ i_fatal("Can't open delivery mail as raw (file=%s): %s",
+ mailfile, mailbox_get_last_internal_error(mailr->box, NULL));
+ }
+ }
+
+ mailr->trans = mailbox_transaction_begin(mailr->box, 0, __func__);
+ headers_ctx = mailbox_header_lookup_init(mailr->box, wanted_headers);
+ mailr->mail = mail_alloc(mailr->trans, 0, headers_ctx);
+ mailbox_header_lookup_unref(&headers_ctx);
+ mail_set_seq(mailr->mail, 1);
+
+ return mailr;
+}
+
+struct mail_raw *mail_raw_open_stream
+(struct mail_user *ruser, struct istream *input)
+{
+ struct mail_raw *mailr;
+
+ i_assert(input->seekable);
+ i_stream_set_name(input, "data");
+ mailr = mail_raw_create(ruser, input, NULL, NULL, (time_t)-1);
+
+ return mailr;
+}
+
+struct mail_raw *mail_raw_open_data
+(struct mail_user *ruser, string_t *mail_data)
+{
+ struct mail_raw *mailr;
+ struct istream *input;
+
+ input = i_stream_create_from_data(str_data(mail_data), str_len(mail_data));
+
+ mailr = mail_raw_open_stream(ruser, input);
+
+ i_stream_unref(&input);
+ return mailr;
+}
+
+struct mail_raw *mail_raw_open_file
+(struct mail_user *ruser, const char *path)
+{
+ struct mail_raw *mailr;
+ struct istream *input = NULL;
+ time_t mtime = (time_t)-1;
+ const char *sender = NULL;
+
+ if ( path == NULL || strcmp(path, "-") == 0 ) {
+ path = NULL;
+ input = mail_raw_create_stream(ruser, 0, &mtime, &sender);
+ }
+
+ mailr = mail_raw_create(ruser, input, path, sender, mtime);
+ i_stream_unref(&input);
+
+ return mailr;
+}
+
+void mail_raw_close(struct mail_raw **mailr)
+{
+ mail_free(&(*mailr)->mail);
+ mailbox_transaction_rollback(&(*mailr)->trans);
+ mailbox_free(&(*mailr)->box);
+
+ i_free(*mailr);
+ *mailr = NULL;
+}
+
diff --git a/pigeonhole/src/lib-sieve/util/mail-raw.h b/pigeonhole/src/lib-sieve/util/mail-raw.h
new file mode 100644
index 0000000..a942d06
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/util/mail-raw.h
@@ -0,0 +1,27 @@
+#ifndef MAIL_RAW_H
+#define MAIL_RAW_H
+
+#include "lib.h"
+#include "master-service.h"
+
+struct mail_raw {
+ pool_t pool;
+ struct mail *mail;
+
+ struct mailbox *box;
+ struct mailbox_transaction_context *trans;
+};
+
+struct mail_user *mail_raw_user_create
+ (struct master_service *service, struct mail_user *mail_user);
+
+struct mail_raw *mail_raw_open_stream
+ (struct mail_user *ruser, struct istream *input);
+struct mail_raw *mail_raw_open_file
+ (struct mail_user *ruser, const char *path);
+struct mail_raw *mail_raw_open_data
+ (struct mail_user *ruser, string_t *mail_data);
+void mail_raw_close(struct mail_raw **mailr);
+
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/util/rfc2822.c b/pigeonhole/src/lib-sieve/util/rfc2822.c
new file mode 100644
index 0000000..ff3a9ad
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/util/rfc2822.c
@@ -0,0 +1,277 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* NOTE: much of the functionality implemented here should eventually appear
+ * somewhere in Dovecot itself.
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "unichar.h"
+
+#include "rfc2822.h"
+
+#include "message-header-encode.h"
+
+#include <stdio.h>
+#include <ctype.h>
+
+bool rfc2822_header_field_name_verify
+(const char *field_name, unsigned int len)
+{
+ const char *p = field_name;
+ const char *pend = p + len;
+
+ /* field-name = 1*ftext
+ * ftext = %d33-57 / ; Any character except
+ * %d59-126 ; controls, SP, and
+ * ; ":".
+ */
+
+ while ( p < pend ) {
+ if ( *p < 33 || *p == ':' )
+ return FALSE;
+
+ p++;
+ }
+
+ return TRUE;
+}
+
+bool rfc2822_header_field_body_verify
+(const char *field_body, unsigned int len, bool allow_crlf, bool allow_utf8)
+{
+ const unsigned char *p = (const unsigned char *)field_body;
+ const unsigned char *pend = p + len;
+ bool is8bit = FALSE;
+
+ /* RFC5322:
+ *
+ * unstructured = (*([FWS] VCHAR) *WSP)
+ * VCHAR = %x21-7E
+ * FWS = ([*WSP CRLF] 1*WSP) / ; Folding white space
+ * WSP = SP / HTAB ; White space
+ */
+
+ while ( p < pend ) {
+ if ( *p < 0x20 ) {
+ if ( (*p == '\r' || *p == '\n') ) {
+ if ( !allow_crlf )
+ return FALSE;
+ } else if ( *p != '\t' ) {
+ return FALSE;
+ }
+ }
+
+ if ( !is8bit && *p > 127 ) {
+ if ( !allow_utf8 )
+ return FALSE;
+
+ is8bit = TRUE;
+ }
+
+ p++;
+ }
+
+ if ( is8bit && !uni_utf8_str_is_valid(field_body) ) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ *
+ */
+
+const char *rfc2822_header_field_name_sanitize(const char *name)
+{
+ char *result = t_strdup_noconst(name);
+ char *p;
+
+ /* Make the whole name lower case ... */
+ result = str_lcase(result);
+
+ /* ... except for the first letter and those that follow '-' */
+ p = result;
+ *p = i_toupper(*p);
+ while ( *p != '\0' ) {
+ if ( *p == '-' ) {
+ p++;
+
+ if ( *p != '\0' )
+ *p = i_toupper(*p);
+
+ continue;
+ }
+
+ p++;
+ }
+
+ return result;
+}
+
+/*
+ * Message construction
+ */
+
+/* FIXME: This should be collected into a Dovecot API for composing internet
+ * mail messages.
+ */
+
+unsigned int rfc2822_header_append
+(string_t *header, const char *name, const char *body, bool crlf,
+ uoff_t *body_offset_r)
+{
+ static const unsigned int max_line = 80;
+
+ const char *bp = body; /* Pointer */
+ const char *sp = body; /* Start pointer */
+ const char *wp = NULL; /* Whitespace pointer */
+ const char *nlp = NULL; /* New-line pointer */
+ unsigned int line_len = strlen(name);
+ unsigned int lines = 0;
+
+ /* Write header field name first */
+ str_append(header, name);
+ str_append(header, ": ");
+
+ if ( body_offset_r != NULL )
+ *body_offset_r = str_len(header);
+
+ line_len += 2;
+
+ /* Add field body; fold it if necessary and account for existing folding */
+ while ( *bp != '\0' ) {
+ bool ws_first = TRUE;
+
+ while ( *bp != '\0' && nlp == NULL &&
+ (wp == NULL || line_len < max_line) ) {
+ if ( *bp == ' ' || *bp == '\t' ) {
+ if (ws_first)
+ wp = bp;
+ ws_first = FALSE;
+ } else if ( *bp == '\r' || *bp == '\n' ) {
+ if (ws_first)
+ nlp = bp;
+ else
+ nlp = wp;
+ break;
+ } else {
+ ws_first = TRUE;
+ }
+
+ bp++; line_len++;
+ }
+
+ if ( *bp == '\0' ) break;
+
+ /* Existing newline ? */
+ if ( nlp != NULL ) {
+ /* Replace any consecutive newline and whitespace for
+ consistency */
+ while ( *bp == ' ' || *bp == '\t' || *bp == '\r' || *bp == '\n' )
+ bp++;
+
+ str_append_data(header, sp, nlp-sp);
+
+ if ( crlf )
+ str_append(header, "\r\n");
+ else
+ str_append(header, "\n");
+
+ while ( *bp == ' ' || *bp == '\t' )
+ bp++;
+ if ( *bp != '\0' ) {
+ /* Continued line; replace leading whitespace with single TAB */
+ str_append_c(header, '\t');
+ }
+
+ sp = bp;
+ } else {
+ /* Insert newline at last whitespace within the max_line limit */
+ i_assert(wp >= sp);
+ str_append_data(header, sp, wp-sp);
+
+ /* Force continued line; drop any existing whitespace */
+ while ( *wp == ' ' || *wp == '\t' )
+ wp++;
+
+ if ( crlf )
+ str_append(header, "\r\n");
+ else
+ str_append(header, "\n");
+
+ /* Insert single TAB instead of the original whitespace */
+ str_append_c(header, '\t');
+
+ sp = wp;
+ if (sp > bp)
+ bp = sp;
+ }
+
+ lines++;
+
+ line_len = bp - sp;
+ wp = NULL;
+ nlp = NULL;
+ }
+
+ if ( bp != sp || lines == 0 ) {
+ str_append_data(header, sp, bp-sp);
+ if ( crlf )
+ str_append(header, "\r\n");
+ else
+ str_append(header, "\n");
+ lines++;
+ }
+
+ return lines;
+}
+
+void rfc2822_header_printf
+(string_t *header, const char *name, const char *fmt, ...)
+{
+ const char *body;
+ va_list args;
+
+ va_start(args, fmt);
+ body = t_strdup_vprintf(fmt, args);
+ va_end(args);
+
+ rfc2822_header_write(header, name, body);
+}
+
+void rfc2822_header_utf8_printf
+(string_t *header, const char *name, const char *fmt, ...)
+{
+ string_t *body = t_str_new(256);
+ va_list args;
+
+ va_start(args, fmt);
+ message_header_encode(t_strdup_vprintf(fmt, args), body);
+ va_end(args);
+
+ rfc2822_header_write(header, name, str_c(body));
+}
+
+
+void rfc2822_header_write_address(string_t *header,
+ const char *name, const char *address)
+{
+ bool has_8bit = FALSE;
+ const char *p;
+
+ for (p = address; *p != '\0'; p++) {
+ if ((*p & 0x80) != 0)
+ has_8bit = TRUE;
+ }
+
+ if (!has_8bit) {
+ rfc2822_header_write(header, name, address);
+ } else {
+ string_t *body = t_str_new(256);
+ message_header_encode(address, body);
+ rfc2822_header_write(header, name, str_c(body));
+ }
+}
diff --git a/pigeonhole/src/lib-sieve/util/rfc2822.h b/pigeonhole/src/lib-sieve/util/rfc2822.h
new file mode 100644
index 0000000..02266a9
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/util/rfc2822.h
@@ -0,0 +1,46 @@
+#ifndef RFC2822_H
+#define RFC2822_H
+
+#include "lib.h"
+
+#include <stdio.h>
+
+/*
+ * Verification
+ */
+
+bool rfc2822_header_field_name_verify
+ (const char *field_name, unsigned int len);
+bool rfc2822_header_field_body_verify
+ (const char *field_body, unsigned int len, bool allow_crlf, bool allow_utf8);
+
+/*
+ *
+ */
+
+const char *rfc2822_header_field_name_sanitize(const char *name);
+
+/*
+ * Message composition
+ */
+
+unsigned int rfc2822_header_append
+ (string_t *header, const char *name, const char *body, bool crlf,
+ uoff_t *body_offset_r);
+
+static inline void rfc2822_header_write
+(string_t *header, const char *name, const char *body)
+{
+ (void)rfc2822_header_append(header, name, body, TRUE, NULL);
+}
+
+void rfc2822_header_printf
+ (string_t *header, const char *name, const char *fmt, ...) ATTR_FORMAT(3, 4);
+void rfc2822_header_utf8_printf
+ (string_t *header, const char *name, const char *fmt, ...) ATTR_FORMAT(3, 4);
+
+void rfc2822_header_write_address(string_t *header,
+ const char *name, const char *address);
+
+
+#endif
diff --git a/pigeonhole/src/lib-sieve/util/test-edit-mail.c b/pigeonhole/src/lib-sieve/util/test-edit-mail.c
new file mode 100644
index 0000000..0e263a2
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/util/test-edit-mail.c
@@ -0,0 +1,842 @@
+/* Copyright (c) 2018 Pigeonhole authors, see the included COPYING file */
+
+#include "lib.h"
+#include "test-common.h"
+#include "path-util.h"
+#include "buffer.h"
+#include "str.h"
+#include "istream.h"
+#include "istream-concat.h"
+#include "istream-crlf.h"
+#include "unlink-directory.h"
+#include "master-service.h"
+#include "istream-header-filter.h"
+#include "mail-storage.h"
+#include "mail-storage-service.h"
+#include "mail-user.h"
+
+#include "mail-raw.h"
+#include "edit-mail.h"
+
+#include <time.h>
+
+static pool_t test_pool;
+
+static struct mail_storage_service_ctx *mail_storage_service = NULL;
+static struct mail_user *test_mail_user = NULL;
+static struct mail_storage_service_user *test_service_user = NULL;
+static const char *mail_home;
+static char *test_dir;
+
+static struct mail_user *test_raw_mail_user = NULL;
+
+static void str_append_no_cr(string_t *str, const char *cstr)
+{
+ const char *p, *poff;
+
+ poff = p = cstr;
+ while (*p != '\0') {
+ if (*p == '\r') {
+ str_append_data(str, poff, (p - poff));
+ poff = p+1;
+ }
+ p++;
+ }
+ str_append_data(str, poff, (p - poff));
+}
+
+static int test_init_mail_user(void)
+{
+ const char *error;
+
+ mail_home = p_strdup_printf(test_pool, "%s/test_user.%ld.%ld",
+ test_dir, (long)time(NULL), (long)getpid());
+
+ struct mail_storage_service_input input = {
+ .userdb_fields = (const char*const[]){
+ t_strdup_printf("mail=maildir:~/"),
+ t_strdup_printf("home=%s", mail_home),
+ NULL
+ },
+ .username = "test@example.com",
+ .no_userdb_lookup = TRUE,
+ .debug = TRUE,
+ };
+
+ mail_storage_service = mail_storage_service_init(
+ master_service, NULL,
+ (MAIL_STORAGE_SERVICE_FLAG_NO_RESTRICT_ACCESS |
+ MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT |
+ MAIL_STORAGE_SERVICE_FLAG_NO_PLUGINS));
+
+ if (mail_storage_service_lookup(mail_storage_service, &input,
+ &test_service_user, &error) < 0)
+ {
+ i_error("Cannot lookup test user: %s", error);
+ return -1;
+ }
+
+ if (mail_storage_service_next(mail_storage_service, test_service_user,
+ &test_mail_user, &error) < 0)
+ {
+ i_error("Cannot lookup test user: %s", error);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void test_deinit_mail_user()
+{
+ const char *error;
+ mail_user_unref(&test_mail_user);
+ mail_storage_service_user_unref(&test_service_user);
+ mail_storage_service_deinit(&mail_storage_service);
+ if (unlink_directory(mail_home, UNLINK_DIRECTORY_FLAG_RMDIR,
+ &error) < 0)
+ i_error("unlink_directory(%s) failed: %s", mail_home, error);
+}
+
+static void test_init(void)
+{
+ test_pool = pool_alloconly_create(MEMPOOL_GROWING"test pool", 128);
+
+ test_init_mail_user();
+ test_raw_mail_user =
+ mail_raw_user_create(master_service, test_mail_user);
+}
+
+static void test_deinit(void)
+{
+ mail_user_unref(&test_raw_mail_user);
+ test_deinit_mail_user();
+ pool_unref(&test_pool);
+}
+
+static void test_stream_data(struct istream *input, buffer_t *buffer)
+{
+ const unsigned char *data;
+ size_t size;
+
+ while (i_stream_read_more(input, &data, &size) > 0) {
+ buffer_append(buffer, data, size);
+ i_stream_skip(input, size);
+ }
+
+ test_assert(!i_stream_have_bytes_left(input));
+ test_assert(input->stream_errno == 0);
+}
+
+static void test_stream_data_slow(struct istream *input, buffer_t *buffer)
+{
+ const unsigned char *data;
+ size_t size;
+ int ret;
+
+ ret = i_stream_read(input);
+ while (ret > 0 || i_stream_have_bytes_left(input) || ret == -2) {
+ data = i_stream_get_data(input, &size);
+ buffer_append(buffer, data, 1);
+ i_stream_skip(input, 1);
+
+ ret = i_stream_read(input);
+ }
+
+ test_assert(!i_stream_have_bytes_left(input));
+ test_assert(input->stream_errno == 0);
+}
+
+static void test_edit_mail_concatenated(void)
+{
+ static const char *hide_headers[] =
+ { "Return-Path", "X-Sieve", "X-Sieve-Redirected-From" };
+ static const char *msg_part1 =
+ "Received: from example.com ([127.0.0.1] helo=example.com)\r\n"
+ " by example.org with LMTP (Dovecot)\r\n"
+ " (envelope-from <frop-bounces@example.com>)\r\n"
+ " id 1er3e8-0015df-QO\r\n"
+ " for timo@example.org;\r\n"
+ " Sat, 03 Mar 2018 10:40:05 +0100\r\n";
+ static const char *msg_part2 =
+ "Return-Path: <stephan@example.com>\r\n";
+ static const char *msg_part3 =
+ "Delivered-To: <timo@example.org>\r\n";
+ static const char *msg_part4 =
+ "From: <stephan@example.com>\r\n"
+ "To: <timo@example.org>\r\n"
+ "Subject: Sieve editheader breaks with LMTP\r\n"
+ "\r\n"
+ "Hi,\r\n"
+ "\r\n"
+ "Sieve editheader seems to be broken when used from LMTP\r\n"
+ "\r\n"
+ "Regards,\r\n"
+ "\r\n"
+ "Stephan.\r\n";
+ static const char *msg_added =
+ "X-Filter-Junk-Type: NONE\r\n"
+ "X-Filter-Junk-Flag: NO\r\n";
+ struct istream *inputs[5], *input_msg, *input_filt, *input_mail, *input;
+ buffer_t *buffer;
+ struct mail_raw *rawmail;
+ struct edit_mail *edmail;
+ struct mail *mail;
+ string_t *expected;
+ const char *value;
+
+ test_begin("edit-mail - concatenated");
+ test_init();
+
+ /* Compose the message */
+
+ inputs[0] = i_stream_create_from_data(msg_part1, strlen(msg_part1));
+ inputs[1] = i_stream_create_from_data(msg_part2, strlen(msg_part2));
+ inputs[2] = i_stream_create_from_data(msg_part3, strlen(msg_part3));
+ inputs[3] = i_stream_create_from_data(msg_part4, strlen(msg_part4));
+ inputs[4] = NULL;
+
+ input_msg = i_stream_create_concat(inputs);
+
+ i_stream_unref(&inputs[0]);
+ i_stream_unref(&inputs[1]);
+ i_stream_unref(&inputs[2]);
+ i_stream_unref(&inputs[3]);
+
+ rawmail = mail_raw_open_stream(test_raw_mail_user, input_msg);
+
+ /* Add headers */
+
+ edmail = edit_mail_wrap(rawmail->mail);
+
+ edit_mail_header_add(edmail, "X-Filter-Junk-Flag", "NO", FALSE);
+ edit_mail_header_add(edmail, "X-Filter-Junk-Type", "NONE", FALSE);
+
+ mail = edit_mail_get_mail(edmail);
+
+ /* Evaluate modified header */
+
+ test_assert(mail_get_first_header_utf8(mail, "Subject", &value) > 0);
+ test_assert(strcmp(value, "Sieve editheader breaks with LMTP") == 0);
+
+ test_assert(mail_get_first_header_utf8(mail, "X-Filter-Junk-Flag",
+ &value) > 0);
+ test_assert(strcmp(value, "NO") == 0);
+ test_assert(mail_get_first_header_utf8(mail, "X-Filter-Junk-Type",
+ &value) > 0);
+ test_assert(strcmp(value, "NONE") == 0);
+
+ test_assert(mail_get_first_header_utf8(mail, "Delivered-To",
+ &value) > 0);
+
+ /* Prepare tests */
+
+ if (mail_get_stream(mail, NULL, NULL, &input_mail) < 0) {
+ i_fatal("Failed to open mail stream: %s",
+ mailbox_get_last_internal_error(mail->box, NULL));
+ }
+
+ buffer = buffer_create_dynamic(default_pool, 1024);
+ expected = t_str_new(1024);
+
+ /* Added */
+
+ i_stream_seek(input_mail, 0);
+ buffer_set_used_size(buffer, 0);
+ input = input_mail;
+
+ test_stream_data(input_mail, buffer);
+
+ str_truncate(expected, 0);
+ str_append(expected, msg_added);
+ str_append(expected, msg_part1);
+ str_append(expected, msg_part2);
+ str_append(expected, msg_part3);
+ str_append(expected, msg_part4);
+
+ test_out("added", strcmp(str_c(buffer), str_c(expected)) == 0);
+
+ /* Added, slow */
+
+ i_stream_seek(input_mail, 0);
+ buffer_set_used_size(buffer, 0);
+
+ test_stream_data_slow(input_mail, buffer);
+
+ str_truncate(expected, 0);
+ str_append(expected, msg_added);
+ str_append(expected, msg_part1);
+ str_append(expected, msg_part2);
+ str_append(expected, msg_part3);
+ str_append(expected, msg_part4);
+
+ test_out("added, slow", strcmp(str_c(buffer), str_c(expected)) == 0);
+
+ /* Added, filtered */
+
+ i_stream_seek(input_mail, 0);
+ buffer_set_used_size(buffer, 0);
+
+ input_filt = i_stream_create_header_filter(
+ input_mail, (HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR),
+ hide_headers, N_ELEMENTS(hide_headers),
+ *null_header_filter_callback, (void *)NULL);
+ input = i_stream_create_lf(input_filt);
+ i_stream_unref(&input_filt);
+
+ test_stream_data(input, buffer);
+ test_assert(!i_stream_have_bytes_left(input_mail));
+ test_assert(input_mail->stream_errno == 0);
+
+ str_truncate(expected, 0);
+ str_append_no_cr(expected, msg_added);
+ str_append_no_cr(expected, msg_part1);
+ str_append_no_cr(expected, msg_part3);
+ str_append_no_cr(expected, msg_part4);
+
+ test_out("added, filtered",
+ strcmp(str_c(buffer), str_c(expected)) == 0);
+
+ i_stream_unref(&input);
+
+ /* Added, filtered, slow */
+
+ i_stream_seek(input_mail, 0);
+ buffer_set_used_size(buffer, 0);
+
+ input_filt = i_stream_create_header_filter(
+ input_mail, (HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR),
+ hide_headers, N_ELEMENTS(hide_headers),
+ *null_header_filter_callback, (void *)NULL);
+ input = i_stream_create_lf(input_filt);
+ i_stream_unref(&input_filt);
+
+ test_stream_data_slow(input, buffer);
+ test_assert(!i_stream_have_bytes_left(input_mail));
+ test_assert(input_mail->stream_errno == 0);
+
+ str_truncate(expected, 0);
+ str_append_no_cr(expected, msg_added);
+ str_append_no_cr(expected, msg_part1);
+ str_append_no_cr(expected, msg_part3);
+ str_append_no_cr(expected, msg_part4);
+
+ test_out("added, filtered, slow",
+ strcmp(str_c(buffer), str_c(expected)) == 0);
+
+ i_stream_unref(&input);
+
+ /* Delete header */
+
+ edit_mail_header_delete(edmail, "Delivered-To", 0);
+
+ /* Evaluate modified header */
+
+ test_assert(mail_get_first_header_utf8(mail, "Subject", &value) > 0);
+ test_assert(strcmp(value, "Sieve editheader breaks with LMTP") == 0);
+
+ test_assert(mail_get_first_header_utf8(mail, "X-Filter-Junk-Flag",
+ &value) > 0);
+ test_assert(strcmp(value, "NO") == 0);
+ test_assert(mail_get_first_header_utf8(mail, "X-Filter-Junk-Type",
+ &value) > 0);
+ test_assert(strcmp(value, "NONE") == 0);
+
+ test_assert(mail_get_first_header_utf8(mail, "Delivered-To",
+ &value) == 0);
+
+ /* Deleted */
+
+ i_stream_seek(input_mail, 0);
+ buffer_set_used_size(buffer, 0);
+ input = input_mail;
+
+ test_stream_data(input_mail, buffer);
+
+ str_truncate(expected, 0);
+ str_append(expected, msg_added);
+ str_append(expected, msg_part1);
+ str_append(expected, msg_part2);
+ str_append(expected, msg_part4);
+
+ test_out("deleted", strcmp(str_c(buffer), str_c(expected)) == 0);
+
+ /* Deleted, slow */
+
+ i_stream_seek(input_mail, 0);
+ buffer_set_used_size(buffer, 0);
+
+ test_stream_data_slow(input_mail, buffer);
+
+ str_truncate(expected, 0);
+ str_append(expected, msg_added);
+ str_append(expected, msg_part1);
+ str_append(expected, msg_part2);
+ str_append(expected, msg_part4);
+
+ test_out("deleted, slow", strcmp(str_c(buffer), str_c(expected)) == 0);
+
+ /* Deleted, filtered */
+
+ i_stream_seek(input_mail, 0);
+ buffer_set_used_size(buffer, 0);
+
+ input_filt = i_stream_create_header_filter(
+ input_mail, (HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR),
+ hide_headers, N_ELEMENTS(hide_headers),
+ *null_header_filter_callback, (void *)NULL);
+ input = i_stream_create_lf(input_filt);
+ i_stream_unref(&input_filt);
+
+ test_stream_data(input, buffer);
+ test_assert(!i_stream_have_bytes_left(input_mail));
+ test_assert(input_mail->stream_errno == 0);
+
+ str_truncate(expected, 0);
+ str_append_no_cr(expected, msg_added);
+ str_append_no_cr(expected, msg_part1);
+ str_append_no_cr(expected, msg_part4);
+
+ test_out("deleted, filtered",
+ strcmp(str_c(buffer), str_c(expected)) == 0);
+
+ i_stream_unref(&input);
+
+ /* Deleted, filtered, slow */
+
+ i_stream_seek(input_mail, 0);
+ buffer_set_used_size(buffer, 0);
+
+ input_filt = i_stream_create_header_filter(input_mail,
+ HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR, hide_headers,
+ N_ELEMENTS(hide_headers), *null_header_filter_callback,
+ (void *)NULL);
+ input = i_stream_create_lf(input_filt);
+ i_stream_unref(&input_filt);
+
+ test_stream_data_slow(input, buffer);
+ test_assert(!i_stream_have_bytes_left(input_mail));
+ test_assert(input_mail->stream_errno == 0);
+
+ str_truncate(expected, 0);
+ str_append_no_cr(expected, msg_added);
+ str_append_no_cr(expected, msg_part1);
+ str_append_no_cr(expected, msg_part4);
+
+ test_out("deleted, filtered, slow",
+ strcmp(str_c(buffer), str_c(expected)) == 0);
+
+ i_stream_unref(&input);
+
+ /* clean up */
+
+ buffer_free(&buffer);
+ edit_mail_unwrap(&edmail);
+ mail_raw_close(&rawmail);
+ i_stream_unref(&input_msg);
+ test_deinit();
+ test_end();
+}
+
+static const char *big_header =
+ "X-A: AAAA\n"
+ "X-Big-One: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ "X-B: BBBB\n"
+ "\n"
+ "Frop!\n";
+
+static void test_edit_mail_big_header(void)
+{
+ struct istream *input_msg, *input_mail;
+ buffer_t *buffer;
+ struct mail_raw *rawmail;
+ struct edit_mail *edmail;
+ struct mail *mail;
+ const char *value;
+
+ test_begin("edit-mail - big header");
+ test_init();
+
+ /* compose the message */
+
+ input_msg = i_stream_create_from_data(big_header, strlen(big_header));
+
+ rawmail = mail_raw_open_stream(test_raw_mail_user, input_msg);
+
+ edmail = edit_mail_wrap(rawmail->mail);
+
+ /* delete header */
+
+ edit_mail_header_delete(edmail, "X-B", 0);
+ mail = edit_mail_get_mail(edmail);
+
+ /* prepare tests */
+
+ if (mail_get_stream(mail, NULL, NULL, &input_mail) < 0) {
+ i_fatal("Failed to open mail stream: %s",
+ mailbox_get_last_internal_error(mail->box, NULL));
+ }
+
+ buffer = buffer_create_dynamic(default_pool, 1024);
+
+ /* evaluate modified header */
+
+ test_assert(mail_get_first_header_utf8(mail, "X-B", &value) == 0);
+
+ /* deleted */
+
+ i_stream_seek(input_mail, 0);
+ buffer_set_used_size(buffer, 0);
+
+ test_stream_data(input_mail, buffer);
+
+ /* clean up */
+
+ buffer_free(&buffer);
+ edit_mail_unwrap(&edmail);
+ mail_raw_close(&rawmail);
+ i_stream_unref(&input_msg);
+ test_deinit();
+ test_end();
+}
+
+static void test_edit_mail_small_buffer(void)
+{
+ static const char *message =
+ "X-A: AAAA\n"
+ "X-B: BBBB\n"
+ "\n"
+ "Frop!\n";
+ struct istream *input_msg, *input_mail;
+ buffer_t *buffer;
+ struct mail_raw *rawmail;
+ struct edit_mail *edmail;
+ struct mail *mail;
+ const char *value;
+ unsigned int i;
+
+ test_begin("edit-mail - small buffer");
+ test_init();
+
+ /* compose the message */
+
+ input_msg = i_stream_create_from_data(message, strlen(message));
+ i_stream_set_max_buffer_size(input_msg, 16);
+
+ rawmail = mail_raw_open_stream(test_raw_mail_user, input_msg);
+
+ edmail = edit_mail_wrap(rawmail->mail);
+
+ /* add headers */
+
+ for (i = 0; i < 16; i++) {
+ edit_mail_header_add(edmail, "X-F", "FF", FALSE);
+ edit_mail_header_add(edmail, "X-L", "LL", TRUE);
+ }
+
+ mail = edit_mail_get_mail(edmail);
+
+ /* prepare tests */
+
+ if (mail_get_stream(mail, NULL, NULL, &input_mail) < 0) {
+ i_fatal("Failed to open mail stream: %s",
+ mailbox_get_last_internal_error(mail->box, NULL));
+ }
+
+ buffer = buffer_create_dynamic(default_pool, 1024);
+
+ /* evaluate modified header */
+
+ test_assert(mail_get_first_header_utf8(mail, "X-F", &value) > 0);
+ test_assert(mail_get_first_header_utf8(mail, "X-A", &value) > 0);
+ test_assert(mail_get_first_header_utf8(mail, "X-B", &value) > 0);
+ test_assert(mail_get_first_header_utf8(mail, "X-L", &value) > 0);
+
+ /* check stream read */
+
+ i_stream_seek(input_mail, 0);
+ buffer_set_used_size(buffer, 0);
+
+ test_stream_data(input_mail, buffer);
+
+ /* clean up */
+
+ buffer_free(&buffer);
+ edit_mail_unwrap(&edmail);
+ mail_raw_close(&rawmail);
+ i_stream_unref(&input_msg);
+ test_deinit();
+ test_end();
+}
+
+int main(int argc, char *argv[])
+{
+ static void (*test_functions[])(void) = {
+ test_edit_mail_concatenated,
+ test_edit_mail_big_header,
+ test_edit_mail_small_buffer,
+ NULL
+ };
+ const enum master_service_flags service_flags =
+ MASTER_SERVICE_FLAG_STANDALONE |
+ MASTER_SERVICE_FLAG_DONT_SEND_STATS |
+ MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS;
+ const char *cwd, *error;
+ int ret;
+
+ master_service = master_service_init("test-edit-header", service_flags,
+ &argc, &argv, "");
+ master_service_init_finish(master_service);
+
+ if (t_get_working_dir(&cwd, &error) < 0)
+ i_fatal("getcwd() failed: %s", error);
+ test_dir = i_strdup(cwd);
+
+ ret = test_run(test_functions);
+
+ i_free(test_dir);
+ master_service_deinit(&master_service);
+
+ return ret;
+}
+
diff --git a/pigeonhole/src/lib-sieve/util/test-rfc2822.c b/pigeonhole/src/lib-sieve/util/test-rfc2822.c
new file mode 100644
index 0000000..66e8ee5
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/util/test-rfc2822.c
@@ -0,0 +1,197 @@
+/* Copyright (c) 2018 Pigeonhole authors, see the included COPYING file */
+
+#include "lib.h"
+#include "test-common.h"
+#include "str.h"
+
+#include "rfc2822.h"
+
+struct test_header_write {
+ const char *name;
+ const char *body;
+ const char *output;
+};
+
+static const struct test_header_write header_write_tests[] = {
+ {
+ .name = "Frop",
+ .body = "Bladiebla",
+ .output = "Frop: Bladiebla\r\n"
+ },{
+ .name = "Subject",
+ .body = "This is a very long subject that well exceeds the "
+ "boundary of 80 characters. It should therefore "
+ "trigger the header folding algorithm.",
+ .output =
+ "Subject: This is a very long subject that well "
+ "exceeds the boundary of 80\r\n"
+ "\tcharacters. It should therefore trigger the header "
+ "folding algorithm.\r\n"
+ },{
+ .name = "Subject",
+ .body = "This\tis\ta\tvery\tlong\tsubject\tthat\twell\texceeds"
+ "\tthe\tboundary\tof\t80\tcharacters.\tIt\tshould\t"
+ "therefore\ttrigger\tthe\theader\tfolding\talgorithm.",
+ .output =
+ "Subject: This\tis\ta\tvery\tlong\tsubject\tthat\twell"
+ "\texceeds\tthe\tboundary\tof\t80\r\n"
+ "\tcharacters.\tIt\tshould\ttherefore\ttrigger\tthe\t"
+ "header\tfolding\talgorithm.\r\n"
+ },{
+ .name = "Comment",
+ .body = "This header already contains newlines.\n"
+ "The header folding algorithm should respect these.\n"
+ "It also should convert between CRLF and LF when "
+ "needed.",
+ .output = "Comment: This header already contains newlines.\r\n"
+ "\tThe header folding algorithm should respect "
+ "these.\r\n"
+ "\tIt also should convert between CRLF and LF when "
+ "needed.\r\n"
+ },{
+ .name = "References",
+ .body = "<messageid1@example.com> <messageid2@example.com> "
+ "<extremelylonglonglonglonglonglonglonglonglonglong"
+ "longlongmessageid3@example.com> "
+ "<messageid4@example.com>",
+ .output = "References: <messageid1@example.com> "
+ "<messageid2@example.com>\r\n"
+ "\t<extremelylonglonglonglonglonglonglonglonglonglong"
+ "longlongmessageid3@example.com>\r\n"
+ "\t<messageid4@example.com>\r\n",
+ },{
+ .name = "Cc",
+ .body = "\"Richard Edgar Cipient\" "
+ "<r.e.cipient@example.com>, \"Albert Buser\" "
+ "<a.buser@example.com>, \"Steven Pammer\" "
+ "<s.pammer@example.com>",
+ .output = "Cc: \"Richard Edgar Cipient\" "
+ "<r.e.cipient@example.com>, \"Albert Buser\"\r\n"
+ "\t<a.buser@example.com>, \"Steven Pammer\" "
+ "<s.pammer@example.com>\r\n"
+ },{
+ .name = "References",
+ .body = "<00fd01d31b6c$33d98e30$9b8caa90$@karel@aa.example.org"
+ "> <00f201d31c36$afbfa320$0f3ee960$@karel@aa.example.o"
+ "rg> <015c01d32023$fe3840c0$faa8c240$@karel@aa.examp"
+ "le.org> <014601d325a4$ece1ed90$c6a5c8b0$@karel@aa."
+ "example.org> <012801d32b24$7734c380$659e4a80$@karel"
+ "@aa.example.org> <00da01d32be9$2d9944b0$88cbce10$@kar"
+ "el@aa.example.org> <006a01d336ef$6825d5b0$387181"
+ "10$@karel@aa.example.org> <018501d33880$58b654f0$0a2"
+ "2fed0$@frederik@aa.example.org> <00e601d33ba3$be50f10"
+ "0$3af2d300$@frederik@aa.example.org> <016501d341ee$e"
+ "678e1a0$b36aa4e0$@frederik@aa.example.org> <00ab01"
+ "d348f9$ae2e1ab0$0a8a5010$@karel@aa.example.org> <0086"
+ "01d349c1$98ff4ba0$cafde2e0$@frederik@aa.example.org> "
+ " <019301d357e6$a2190680$e64b1380$@frederik@aa.example"
+ ".org> <025f01d384b0$24d2c"
+ "660$6e785320$@karel@aa.example.org> <01cf01d3889e$7"
+ "280cb90$578262b0$@karel@aa.example.org> <013701d38"
+ "bc2$9164b950$b42e2bf0$@karel@aa.example.org> "
+ " <014f01d3a5b1$a51afc80$ef\n"
+ " \n"
+ "\t \t \t \t \t \t \t \t5\t0\tf\t5\t8\t0\t$\t@\tk\ta\t"
+ "r\te\tl\t@\taa.example.org> <01cb01d3af29$dd7d"
+ "1b40$987751c0$@karel@aa.example.org> "
+ " <00b401d3f2bc$6ad8c180$408a4480"
+ "$@karel@aa.example.org> <011a01d3f6ab$0eeb0480$2cc1"
+ "0d80$@frederik@aa.example.org> <005c01d3f774$37f1b210"
+ "$a7d51630$@richard@aa.example.org> <01a801d3fc2d$59"
+ "0f7730$0b2e6590$@frederik@aa.example.org> <007501d3fc"
+ "f5$23d75ce0$6b8616a0$@frederik@aa.example.org> <015d0"
+ "1d3fdbf$136da510$3a48ef30$@frederik@aa.example.org> <"
+ "021a01d3fe87$556d68b0$00483a10$@frederik@aa.example.o"
+ "rg> <013f01d3ff4e$a2d13d30$e873b790$@frederik@aa.exam"
+ "ple.org> <001f01d401ab$31e7b090$95b711b0$@frederik@aa"
+ ".example.org> <017201d40273$a118d200$e34a7600$@freder"
+ "ik@aa.example.org> <017401d4033e$ca3602e0$5ea208a0$@f"
+ "rederik@aa.example.org> <02a601d40404$608b9e10$21a2da"
+ "30$@frederik@aa.example.org> <014301d404d0$b65269b0$2"
+ "2f73d10$@frederik@aa.example.org> <015901d4072b$b5a1b"
+ "950$20e52bf0$@frederik@aa.example.org> <01b401d407f3$"
+ "bef52050$3cdf\n"
+ " 60 \n"
+ "\tf0 \t$@ \tfr \ted \teri\tk@aa.example.org> <012801d"
+ "408bd$6602fce0$3208f6a0$@frederik@aa.example.org> <01"
+ "c801d40984$ae4b23c0$0ae16b40$@frederik@aa.example.org"
+ "> <00ec01d40a4d$12859190$3790b4b0$@frederik@aa.exampl"
+ "e.org> <02af01d40d74$589c9050$09d5b0f0$@frederik@aa.e"
+ "xample.org> <000d01d40ec8$d3d337b0$7b79a710$@richard@"
+ "aa.example.org>\n",
+ .output = "References: <00fd01d31b6c$33d98e30$9b8caa90$@karel@aa.example.org>\r\n"
+ "\t<00f201d31c36$afbfa320$0f3ee960$@karel@aa.example.org>\r\n"
+ "\t<015c01d32023$fe3840c0$faa8c240$@karel@aa.example.org>\r\n"
+ "\t<014601d325a4$ece1ed90$c6a5c8b0$@karel@aa.example.org>\r\n"
+ "\t<012801d32b24$7734c380$659e4a80$@karel@aa.example.org>\r\n"
+ "\t<00da01d32be9$2d9944b0$88cbce10$@karel@aa.example.org>\r\n"
+ "\t<006a01d336ef$6825d5b0$38718110$@karel@aa.example.org>\r\n"
+ "\t<018501d33880$58b654f0$0a22fed0$@frederik@aa.example.org>\r\n"
+ "\t<00e601d33ba3$be50f100$3af2d300$@frederik@aa.example.org>\r\n"
+ "\t<016501d341ee$e678e1a0$b36aa4e0$@frederik@aa.example.org>\r\n"
+ "\t<00ab01d348f9$ae2e1ab0$0a8a5010$@karel@aa.example.org>\r\n"
+ "\t<008601d349c1$98ff4ba0$cafde2e0$@frederik@aa.example.org>\r\n"
+ "\t<019301d357e6$a2190680$e64b1380$@frederik@aa.example.org>\r\n"
+ "\t<025f01d384b0$24d2c660$6e785320$@karel@aa.example.org>\r\n"
+ "\t<01cf01d3889e$7280cb90$578262b0$@karel@aa.example.org>\r\n"
+ "\t<013701d38bc2$9164b950$b42e2bf0$@karel@aa.example.org>\r\n"
+ "\t<014f01d3a5b1$a51afc80$ef\r\n"
+ "\t5\t0\tf\t5\t8\t0\t$\t@\tk\ta\tr\te\tl\t@\taa.example.org>\r\n"
+ "\t<01cb01d3af29$dd7d1b40$987751c0$@karel@aa.example.org>\r\n"
+ "\t<00b401d3f2bc$6ad8c180$408a4480$@karel@aa.example.org>\r\n"
+ "\t<011a01d3f6ab$0eeb0480$2cc10d80$@frederik@aa.example.org>\r\n"
+ "\t<005c01d3f774$37f1b210$a7d51630$@richard@aa.example.org>\r\n"
+ "\t<01a801d3fc2d$590f7730$0b2e6590$@frederik@aa.example.org>\r\n"
+ "\t<007501d3fcf5$23d75ce0$6b8616a0$@frederik@aa.example.org>\r\n"
+ "\t<015d01d3fdbf$136da510$3a48ef30$@frederik@aa.example.org>\r\n"
+ "\t<021a01d3fe87$556d68b0$00483a10$@frederik@aa.example.org>\r\n"
+ "\t<013f01d3ff4e$a2d13d30$e873b790$@frederik@aa.example.org>\r\n"
+ "\t<001f01d401ab$31e7b090$95b711b0$@frederik@aa.example.org>\r\n"
+ "\t<017201d40273$a118d200$e34a7600$@frederik@aa.example.org>\r\n"
+ "\t<017401d4033e$ca3602e0$5ea208a0$@frederik@aa.example.org>\r\n"
+ "\t<02a601d40404$608b9e10$21a2da30$@frederik@aa.example.org>\r\n"
+ "\t<014301d404d0$b65269b0$22f73d10$@frederik@aa.example.org>\r\n"
+ "\t<015901d4072b$b5a1b950$20e52bf0$@frederik@aa.example.org>\r\n"
+ "\t<01b401d407f3$bef52050$3cdf\r\n"
+ "\t60\r\n"
+ "\tf0 \t$@ \tfr \ted \teri\tk@aa.example.org>\r\n"
+ "\t<012801d408bd$6602fce0$3208f6a0$@frederik@aa.example.org>\r\n"
+ "\t<01c801d40984$ae4b23c0$0ae16b40$@frederik@aa.example.org>\r\n"
+ "\t<00ec01d40a4d$12859190$3790b4b0$@frederik@aa.example.org>\r\n"
+ "\t<02af01d40d74$589c9050$09d5b0f0$@frederik@aa.example.org>\r\n"
+ "\t<000d01d40ec8$d3d337b0$7b79a710$@richard@aa.example.org>\r\n"
+ }
+};
+
+static const unsigned int header_write_tests_count =
+ N_ELEMENTS(header_write_tests);
+
+static void test_rfc2822_header_write(void)
+{
+ string_t *header;
+ unsigned int i;
+
+ test_begin("rfc2822 - header write");
+
+ header = t_str_new(1024);
+ for (i = 0; i < header_write_tests_count; i++) {
+ const struct test_header_write *test = &header_write_tests[i];
+
+ str_truncate(header, 0);
+ rfc2822_header_write(header, test->name, test->body);
+
+ test_assert_idx(strcmp(str_c(header), test->output) == 0, i);
+ }
+
+ test_end();
+}
+
+int main(void)
+{
+ static void (*test_functions[])(void) = {
+ test_rfc2822_header_write,
+ NULL
+ };
+ return test_run(test_functions);
+}
+
diff --git a/pigeonhole/src/managesieve-login/Makefile.am b/pigeonhole/src/managesieve-login/Makefile.am
new file mode 100644
index 0000000..3bfbc75
--- /dev/null
+++ b/pigeonhole/src/managesieve-login/Makefile.am
@@ -0,0 +1,43 @@
+settingsdir = $(dovecot_moduledir)/settings
+
+dovecot_pkglibexec_PROGRAMS = managesieve-login
+
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_SERVICE_INCLUDE) \
+ $(LIBDOVECOT_LOGIN_INCLUDE) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src/lib-managesieve
+
+libmanagesieve_login_settings_la_LDFLAGS = -module -avoid-version
+
+settings_LTLIBRARIES = \
+ libmanagesieve_login_settings.la
+
+libmanagesieve_login_settings_la_SOURCES = \
+ managesieve-login-settings.c \
+ managesieve-login-settings-plugin.c
+
+libmanagesieve_login_settings_la_CFLAGS = \
+ $(AM_CFLAGS) $(LIBDOVECOT_CONFIG_INCLUDE) -DPKG_LIBEXECDIR=\""$(dovecot_pkglibexecdir)"\"
+
+libs = \
+ $(top_builddir)/src/lib-managesieve/libmanagesieve.la
+
+managesieve_login_CPPFLAGS = $(AM_CPPFLAGS) $(BINARY_CFLAGS)
+managesieve_login_LDFLAGS = $(BINARY_LDFLAGS)
+managesieve_login_LDADD = $(libs) $(LIBDOVECOT_LOGIN) $(LIBDOVECOT)
+managesieve_login_DEPENDENCIES = $(libs) $(LIBDOVECOT_LOGIN_DEPS) $(LIBDOVECOT_DEPS)
+
+managesieve_login_SOURCES = \
+ client.c \
+ client-authenticate.c \
+ managesieve-login-settings.c \
+ managesieve-proxy.c
+
+noinst_HEADERS = \
+ client.h \
+ client-authenticate.h \
+ managesieve-login-settings.h \
+ managesieve-login-settings-plugin.h \
+ managesieve-proxy.h
diff --git a/pigeonhole/src/managesieve-login/Makefile.in b/pigeonhole/src/managesieve-login/Makefile.in
new file mode 100644
index 0000000..14d7b78
--- /dev/null
+++ b/pigeonhole/src/managesieve-login/Makefile.in
@@ -0,0 +1,931 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+dovecot_pkglibexec_PROGRAMS = managesieve-login$(EXEEXT)
+subdir = src/managesieve-login
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(dovecot_pkglibexecdir)" \
+ "$(DESTDIR)$(settingsdir)"
+PROGRAMS = $(dovecot_pkglibexec_PROGRAMS)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+LTLIBRARIES = $(settings_LTLIBRARIES)
+libmanagesieve_login_settings_la_LIBADD =
+am_libmanagesieve_login_settings_la_OBJECTS = libmanagesieve_login_settings_la-managesieve-login-settings.lo \
+ libmanagesieve_login_settings_la-managesieve-login-settings-plugin.lo
+libmanagesieve_login_settings_la_OBJECTS = \
+ $(am_libmanagesieve_login_settings_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libmanagesieve_login_settings_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(libmanagesieve_login_settings_la_CFLAGS) $(CFLAGS) \
+ $(libmanagesieve_login_settings_la_LDFLAGS) $(LDFLAGS) -o $@
+am_managesieve_login_OBJECTS = managesieve_login-client.$(OBJEXT) \
+ managesieve_login-client-authenticate.$(OBJEXT) \
+ managesieve_login-managesieve-login-settings.$(OBJEXT) \
+ managesieve_login-managesieve-proxy.$(OBJEXT)
+managesieve_login_OBJECTS = $(am_managesieve_login_OBJECTS)
+am__DEPENDENCIES_1 =
+managesieve_login_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(managesieve_login_LDFLAGS) $(LDFLAGS) \
+ -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/libmanagesieve_login_settings_la-managesieve-login-settings-plugin.Plo \
+ ./$(DEPDIR)/libmanagesieve_login_settings_la-managesieve-login-settings.Plo \
+ ./$(DEPDIR)/managesieve_login-client-authenticate.Po \
+ ./$(DEPDIR)/managesieve_login-client.Po \
+ ./$(DEPDIR)/managesieve_login-managesieve-login-settings.Po \
+ ./$(DEPDIR)/managesieve_login-managesieve-proxy.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libmanagesieve_login_settings_la_SOURCES) \
+ $(managesieve_login_SOURCES)
+DIST_SOURCES = $(libmanagesieve_login_settings_la_SOURCES) \
+ $(managesieve_login_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+settingsdir = $(dovecot_moduledir)/settings
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_SERVICE_INCLUDE) \
+ $(LIBDOVECOT_LOGIN_INCLUDE) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src/lib-managesieve
+
+libmanagesieve_login_settings_la_LDFLAGS = -module -avoid-version
+settings_LTLIBRARIES = \
+ libmanagesieve_login_settings.la
+
+libmanagesieve_login_settings_la_SOURCES = \
+ managesieve-login-settings.c \
+ managesieve-login-settings-plugin.c
+
+libmanagesieve_login_settings_la_CFLAGS = \
+ $(AM_CFLAGS) $(LIBDOVECOT_CONFIG_INCLUDE) -DPKG_LIBEXECDIR=\""$(dovecot_pkglibexecdir)"\"
+
+libs = \
+ $(top_builddir)/src/lib-managesieve/libmanagesieve.la
+
+managesieve_login_CPPFLAGS = $(AM_CPPFLAGS) $(BINARY_CFLAGS)
+managesieve_login_LDFLAGS = $(BINARY_LDFLAGS)
+managesieve_login_LDADD = $(libs) $(LIBDOVECOT_LOGIN) $(LIBDOVECOT)
+managesieve_login_DEPENDENCIES = $(libs) $(LIBDOVECOT_LOGIN_DEPS) $(LIBDOVECOT_DEPS)
+managesieve_login_SOURCES = \
+ client.c \
+ client-authenticate.c \
+ managesieve-login-settings.c \
+ managesieve-proxy.c
+
+noinst_HEADERS = \
+ client.h \
+ client-authenticate.h \
+ managesieve-login-settings.h \
+ managesieve-login-settings-plugin.h \
+ managesieve-proxy.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/managesieve-login/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/managesieve-login/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-dovecot_pkglibexecPROGRAMS: $(dovecot_pkglibexec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(dovecot_pkglibexec_PROGRAMS)'; test -n "$(dovecot_pkglibexecdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(dovecot_pkglibexecdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(dovecot_pkglibexecdir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(dovecot_pkglibexecdir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(dovecot_pkglibexecdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-dovecot_pkglibexecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dovecot_pkglibexec_PROGRAMS)'; test -n "$(dovecot_pkglibexecdir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(dovecot_pkglibexecdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(dovecot_pkglibexecdir)" && rm -f $$files
+
+clean-dovecot_pkglibexecPROGRAMS:
+ @list='$(dovecot_pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+install-settingsLTLIBRARIES: $(settings_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(settings_LTLIBRARIES)'; test -n "$(settingsdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(settingsdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(settingsdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(settingsdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(settingsdir)"; \
+ }
+
+uninstall-settingsLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(settings_LTLIBRARIES)'; test -n "$(settingsdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(settingsdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(settingsdir)/$$f"; \
+ done
+
+clean-settingsLTLIBRARIES:
+ -test -z "$(settings_LTLIBRARIES)" || rm -f $(settings_LTLIBRARIES)
+ @list='$(settings_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libmanagesieve_login_settings.la: $(libmanagesieve_login_settings_la_OBJECTS) $(libmanagesieve_login_settings_la_DEPENDENCIES) $(EXTRA_libmanagesieve_login_settings_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libmanagesieve_login_settings_la_LINK) -rpath $(settingsdir) $(libmanagesieve_login_settings_la_OBJECTS) $(libmanagesieve_login_settings_la_LIBADD) $(LIBS)
+
+managesieve-login$(EXEEXT): $(managesieve_login_OBJECTS) $(managesieve_login_DEPENDENCIES) $(EXTRA_managesieve_login_DEPENDENCIES)
+ @rm -f managesieve-login$(EXEEXT)
+ $(AM_V_CCLD)$(managesieve_login_LINK) $(managesieve_login_OBJECTS) $(managesieve_login_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmanagesieve_login_settings_la-managesieve-login-settings-plugin.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmanagesieve_login_settings_la-managesieve-login-settings.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve_login-client-authenticate.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve_login-client.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve_login-managesieve-login-settings.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve_login-managesieve-proxy.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libmanagesieve_login_settings_la-managesieve-login-settings.lo: managesieve-login-settings.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmanagesieve_login_settings_la_CFLAGS) $(CFLAGS) -MT libmanagesieve_login_settings_la-managesieve-login-settings.lo -MD -MP -MF $(DEPDIR)/libmanagesieve_login_settings_la-managesieve-login-settings.Tpo -c -o libmanagesieve_login_settings_la-managesieve-login-settings.lo `test -f 'managesieve-login-settings.c' || echo '$(srcdir)/'`managesieve-login-settings.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmanagesieve_login_settings_la-managesieve-login-settings.Tpo $(DEPDIR)/libmanagesieve_login_settings_la-managesieve-login-settings.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managesieve-login-settings.c' object='libmanagesieve_login_settings_la-managesieve-login-settings.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmanagesieve_login_settings_la_CFLAGS) $(CFLAGS) -c -o libmanagesieve_login_settings_la-managesieve-login-settings.lo `test -f 'managesieve-login-settings.c' || echo '$(srcdir)/'`managesieve-login-settings.c
+
+libmanagesieve_login_settings_la-managesieve-login-settings-plugin.lo: managesieve-login-settings-plugin.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmanagesieve_login_settings_la_CFLAGS) $(CFLAGS) -MT libmanagesieve_login_settings_la-managesieve-login-settings-plugin.lo -MD -MP -MF $(DEPDIR)/libmanagesieve_login_settings_la-managesieve-login-settings-plugin.Tpo -c -o libmanagesieve_login_settings_la-managesieve-login-settings-plugin.lo `test -f 'managesieve-login-settings-plugin.c' || echo '$(srcdir)/'`managesieve-login-settings-plugin.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmanagesieve_login_settings_la-managesieve-login-settings-plugin.Tpo $(DEPDIR)/libmanagesieve_login_settings_la-managesieve-login-settings-plugin.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managesieve-login-settings-plugin.c' object='libmanagesieve_login_settings_la-managesieve-login-settings-plugin.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmanagesieve_login_settings_la_CFLAGS) $(CFLAGS) -c -o libmanagesieve_login_settings_la-managesieve-login-settings-plugin.lo `test -f 'managesieve-login-settings-plugin.c' || echo '$(srcdir)/'`managesieve-login-settings-plugin.c
+
+managesieve_login-client.o: client.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve_login-client.o -MD -MP -MF $(DEPDIR)/managesieve_login-client.Tpo -c -o managesieve_login-client.o `test -f 'client.c' || echo '$(srcdir)/'`client.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve_login-client.Tpo $(DEPDIR)/managesieve_login-client.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='client.c' object='managesieve_login-client.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve_login-client.o `test -f 'client.c' || echo '$(srcdir)/'`client.c
+
+managesieve_login-client.obj: client.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve_login-client.obj -MD -MP -MF $(DEPDIR)/managesieve_login-client.Tpo -c -o managesieve_login-client.obj `if test -f 'client.c'; then $(CYGPATH_W) 'client.c'; else $(CYGPATH_W) '$(srcdir)/client.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve_login-client.Tpo $(DEPDIR)/managesieve_login-client.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='client.c' object='managesieve_login-client.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve_login-client.obj `if test -f 'client.c'; then $(CYGPATH_W) 'client.c'; else $(CYGPATH_W) '$(srcdir)/client.c'; fi`
+
+managesieve_login-client-authenticate.o: client-authenticate.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve_login-client-authenticate.o -MD -MP -MF $(DEPDIR)/managesieve_login-client-authenticate.Tpo -c -o managesieve_login-client-authenticate.o `test -f 'client-authenticate.c' || echo '$(srcdir)/'`client-authenticate.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve_login-client-authenticate.Tpo $(DEPDIR)/managesieve_login-client-authenticate.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='client-authenticate.c' object='managesieve_login-client-authenticate.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve_login-client-authenticate.o `test -f 'client-authenticate.c' || echo '$(srcdir)/'`client-authenticate.c
+
+managesieve_login-client-authenticate.obj: client-authenticate.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve_login-client-authenticate.obj -MD -MP -MF $(DEPDIR)/managesieve_login-client-authenticate.Tpo -c -o managesieve_login-client-authenticate.obj `if test -f 'client-authenticate.c'; then $(CYGPATH_W) 'client-authenticate.c'; else $(CYGPATH_W) '$(srcdir)/client-authenticate.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve_login-client-authenticate.Tpo $(DEPDIR)/managesieve_login-client-authenticate.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='client-authenticate.c' object='managesieve_login-client-authenticate.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve_login-client-authenticate.obj `if test -f 'client-authenticate.c'; then $(CYGPATH_W) 'client-authenticate.c'; else $(CYGPATH_W) '$(srcdir)/client-authenticate.c'; fi`
+
+managesieve_login-managesieve-login-settings.o: managesieve-login-settings.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve_login-managesieve-login-settings.o -MD -MP -MF $(DEPDIR)/managesieve_login-managesieve-login-settings.Tpo -c -o managesieve_login-managesieve-login-settings.o `test -f 'managesieve-login-settings.c' || echo '$(srcdir)/'`managesieve-login-settings.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve_login-managesieve-login-settings.Tpo $(DEPDIR)/managesieve_login-managesieve-login-settings.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managesieve-login-settings.c' object='managesieve_login-managesieve-login-settings.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve_login-managesieve-login-settings.o `test -f 'managesieve-login-settings.c' || echo '$(srcdir)/'`managesieve-login-settings.c
+
+managesieve_login-managesieve-login-settings.obj: managesieve-login-settings.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve_login-managesieve-login-settings.obj -MD -MP -MF $(DEPDIR)/managesieve_login-managesieve-login-settings.Tpo -c -o managesieve_login-managesieve-login-settings.obj `if test -f 'managesieve-login-settings.c'; then $(CYGPATH_W) 'managesieve-login-settings.c'; else $(CYGPATH_W) '$(srcdir)/managesieve-login-settings.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve_login-managesieve-login-settings.Tpo $(DEPDIR)/managesieve_login-managesieve-login-settings.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managesieve-login-settings.c' object='managesieve_login-managesieve-login-settings.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve_login-managesieve-login-settings.obj `if test -f 'managesieve-login-settings.c'; then $(CYGPATH_W) 'managesieve-login-settings.c'; else $(CYGPATH_W) '$(srcdir)/managesieve-login-settings.c'; fi`
+
+managesieve_login-managesieve-proxy.o: managesieve-proxy.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve_login-managesieve-proxy.o -MD -MP -MF $(DEPDIR)/managesieve_login-managesieve-proxy.Tpo -c -o managesieve_login-managesieve-proxy.o `test -f 'managesieve-proxy.c' || echo '$(srcdir)/'`managesieve-proxy.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve_login-managesieve-proxy.Tpo $(DEPDIR)/managesieve_login-managesieve-proxy.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managesieve-proxy.c' object='managesieve_login-managesieve-proxy.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve_login-managesieve-proxy.o `test -f 'managesieve-proxy.c' || echo '$(srcdir)/'`managesieve-proxy.c
+
+managesieve_login-managesieve-proxy.obj: managesieve-proxy.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve_login-managesieve-proxy.obj -MD -MP -MF $(DEPDIR)/managesieve_login-managesieve-proxy.Tpo -c -o managesieve_login-managesieve-proxy.obj `if test -f 'managesieve-proxy.c'; then $(CYGPATH_W) 'managesieve-proxy.c'; else $(CYGPATH_W) '$(srcdir)/managesieve-proxy.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve_login-managesieve-proxy.Tpo $(DEPDIR)/managesieve_login-managesieve-proxy.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managesieve-proxy.c' object='managesieve_login-managesieve-proxy.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve_login-managesieve-proxy.obj `if test -f 'managesieve-proxy.c'; then $(CYGPATH_W) 'managesieve-proxy.c'; else $(CYGPATH_W) '$(srcdir)/managesieve-proxy.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(dovecot_pkglibexecdir)" "$(DESTDIR)$(settingsdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-dovecot_pkglibexecPROGRAMS clean-generic clean-libtool \
+ clean-settingsLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/libmanagesieve_login_settings_la-managesieve-login-settings-plugin.Plo
+ -rm -f ./$(DEPDIR)/libmanagesieve_login_settings_la-managesieve-login-settings.Plo
+ -rm -f ./$(DEPDIR)/managesieve_login-client-authenticate.Po
+ -rm -f ./$(DEPDIR)/managesieve_login-client.Po
+ -rm -f ./$(DEPDIR)/managesieve_login-managesieve-login-settings.Po
+ -rm -f ./$(DEPDIR)/managesieve_login-managesieve-proxy.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-settingsLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-dovecot_pkglibexecPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/libmanagesieve_login_settings_la-managesieve-login-settings-plugin.Plo
+ -rm -f ./$(DEPDIR)/libmanagesieve_login_settings_la-managesieve-login-settings.Plo
+ -rm -f ./$(DEPDIR)/managesieve_login-client-authenticate.Po
+ -rm -f ./$(DEPDIR)/managesieve_login-client.Po
+ -rm -f ./$(DEPDIR)/managesieve_login-managesieve-login-settings.Po
+ -rm -f ./$(DEPDIR)/managesieve_login-managesieve-proxy.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dovecot_pkglibexecPROGRAMS \
+ uninstall-settingsLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-dovecot_pkglibexecPROGRAMS clean-generic clean-libtool \
+ clean-settingsLTLIBRARIES cscopelist-am ctags ctags-am \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dovecot_pkglibexecPROGRAMS install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-settingsLTLIBRARIES install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am \
+ uninstall-dovecot_pkglibexecPROGRAMS \
+ uninstall-settingsLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/managesieve-login/client-authenticate.c b/pigeonhole/src/managesieve-login/client-authenticate.c
new file mode 100644
index 0000000..b186f84
--- /dev/null
+++ b/pigeonhole/src/managesieve-login/client-authenticate.c
@@ -0,0 +1,308 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "login-common.h"
+#include "base64.h"
+#include "buffer.h"
+#include "ioloop.h"
+#include "istream.h"
+#include "ostream.h"
+#include "safe-memset.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "auth-client.h"
+
+#include "managesieve-parser.h"
+#include "managesieve-quote.h"
+#include "client.h"
+
+#include "client-authenticate.h"
+#include "managesieve-proxy.h"
+
+
+const char *client_authenticate_get_capabilities
+(struct client *client)
+{
+ const struct auth_mech_desc *mech;
+ unsigned int i, count;
+ string_t *str;
+
+ str = t_str_new(128);
+ mech = sasl_server_get_advertised_mechs(client, &count);
+
+ for (i = 0; i < count; i++) {
+ if (i > 0)
+ str_append_c(str, ' ');
+ str_append(str, mech[i].name);
+ }
+
+ return str_c(str);
+}
+
+void managesieve_client_auth_result(struct client *client,
+ enum client_auth_result result,
+ const struct client_auth_reply *reply, const char *text)
+{
+ struct managesieve_client *msieve_client =
+ (struct managesieve_client *)client;
+ string_t *referral;
+
+ switch (result) {
+ case CLIENT_AUTH_RESULT_SUCCESS:
+ /* nothing to be done for IMAP */
+ break;
+ case CLIENT_AUTH_RESULT_REFERRAL_SUCCESS:
+ case CLIENT_AUTH_RESULT_REFERRAL_NOLOGIN:
+ /* MANAGESIEVE referral
+
+ [nologin] referral host=.. [port=..] [destuser=..]
+ [reason=..]
+
+ NO [REFERRAL sieve://user;AUTH=mech@host:port/] "Can't login."
+ OK [...] "Logged in, but you should use this server instead."
+ .. [REFERRAL ..] Reason from auth server
+ */
+ referral = t_str_new(128);
+ str_printfa(referral, "REFERRAL sieve://%s;AUTH=%s@%s",
+ reply->destuser, client->auth_mech_name, reply->host);
+ if ( reply->port != 4190 )
+ str_printfa(referral, ":%u", reply->port);
+
+ if ( result == CLIENT_AUTH_RESULT_REFERRAL_SUCCESS ) {
+ client_send_okresp(client, str_c(referral), text);;
+ } else {
+ client_send_noresp(client, str_c(referral), text);
+ }
+ break;
+ case CLIENT_AUTH_RESULT_ABORTED:
+ case CLIENT_AUTH_RESULT_AUTHFAILED_REASON:
+ case CLIENT_AUTH_RESULT_AUTHZFAILED:
+ client_send_no(client, text);
+ break;
+ case CLIENT_AUTH_RESULT_TEMPFAIL:
+ client_send_noresp(client, "TRYLATER", text);
+ break;
+ case CLIENT_AUTH_RESULT_SSL_REQUIRED:
+ client_send_noresp(client, "ENCRYPT-NEEDED", text);
+ break;
+ case CLIENT_AUTH_RESULT_AUTHFAILED:
+ default:
+ client_send_no(client, text);
+ break;
+ }
+
+ msieve_client->auth_response_input = NULL;
+ managesieve_parser_reset(msieve_client->parser);
+}
+
+void managesieve_client_auth_send_challenge
+(struct client *client, const char *data)
+{
+ struct managesieve_client *msieve_client =
+ (struct managesieve_client *) client;
+
+ T_BEGIN {
+ string_t *str = t_str_new(256);
+
+ managesieve_quote_append_string(str, data, TRUE);
+ str_append(str, "\r\n");
+
+ client_send_raw_data(client, str_c(str), str_len(str));
+ } T_END;
+
+ msieve_client->auth_response_input = NULL;
+ managesieve_parser_reset(msieve_client->parser);
+}
+
+static int managesieve_client_auth_read_response
+(struct managesieve_client *msieve_client, bool initial, const char **error_r)
+{
+ struct client *client = &msieve_client->common;
+ const struct managesieve_arg *args;
+ const char *error;
+ bool fatal;
+ const unsigned char *data;
+ size_t size;
+ uoff_t resp_size;
+ int ret;
+
+ *error_r = NULL;
+
+ if ( i_stream_read(client->input) == -1 ) {
+ /* disconnected */
+ client_destroy_iostream_error(client);
+ return -1;
+ }
+
+ if ( msieve_client->auth_response_input == NULL ) {
+
+ if ( msieve_client->skip_line ) {
+ if ( i_stream_next_line(client->input) == NULL )
+ return 0;
+
+ msieve_client->skip_line = FALSE;
+ }
+
+ switch ( managesieve_parser_read_args(msieve_client->parser, 0,
+ MANAGESIEVE_PARSE_FLAG_STRING_STREAM, &args) ) {
+ case -1:
+ error = managesieve_parser_get_error(msieve_client->parser, &fatal);
+ if (fatal) {
+ client_send_bye(client, error);
+ client_destroy(client, t_strconcat(
+ "parse error during auth: ", error, NULL));
+ } else {
+ *error_r = error;
+ }
+ msieve_client->skip_line = TRUE;
+ return -1;
+
+ case -2:
+ /* not enough data */
+ return 0;
+
+ default:
+ break;
+ }
+
+ if ( MANAGESIEVE_ARG_IS_EOL(&args[0]) ) {
+ if (!initial) {
+ *error_r = "Received empty AUTHENTICATE client response line.";
+ msieve_client->skip_line = TRUE;
+ return -1;
+ }
+ msieve_client->skip_line = TRUE;
+ return 1;
+ }
+
+ if ( !managesieve_arg_get_string_stream
+ (&args[0], &msieve_client->auth_response_input)
+ || !MANAGESIEVE_ARG_IS_EOL(&args[1]) ) {
+ if ( !initial )
+ *error_r = "Invalid AUTHENTICATE client response.";
+ else
+ *error_r = "Invalid AUTHENTICATE initial response.";
+ msieve_client->skip_line = TRUE;
+ return -1;
+ }
+
+ if ( i_stream_get_size
+ (msieve_client->auth_response_input, FALSE, &resp_size) <= 0 )
+ resp_size = 0;
+
+ if (client->auth_response == NULL)
+ client->auth_response = str_new(default_pool, I_MAX(resp_size+1, 256));
+ }
+
+ while ( (ret=i_stream_read_more
+ (msieve_client->auth_response_input, &data, &size) ) > 0 ) {
+
+ if (str_len(client->auth_response) + size > LOGIN_MAX_AUTH_BUF_SIZE) {
+ client_destroy(client, "Authentication response too large");
+ return -1;
+ }
+
+ str_append_data(client->auth_response, data, size);
+ i_stream_skip(msieve_client->auth_response_input, size);
+ }
+
+ if ( ret == 0 ) return 0;
+
+ if ( msieve_client->auth_response_input->stream_errno != 0 ) {
+ if ( !client->input->eof &&
+ msieve_client->auth_response_input->stream_errno == EINVAL ) {
+ msieve_client->skip_line = TRUE;
+ *error_r = t_strconcat
+ ("Error in AUTHENTICATE response string: ",
+ i_stream_get_error(msieve_client->auth_response_input), NULL);
+ return -1;
+ }
+
+ client_destroy_iostream_error(client);
+ return -1;
+ }
+
+ if ( i_stream_next_line(client->input) == NULL )
+ return 0;
+
+ return 1;
+}
+
+void managesieve_client_auth_parse_response(struct client *client)
+{
+ struct managesieve_client *msieve_client =
+ (struct managesieve_client *) client;
+ const char *error = NULL;
+ int ret;
+
+ if ( (ret=managesieve_client_auth_read_response(msieve_client, FALSE, &error))
+ < 0 ) {
+ if ( error != NULL )
+ client_auth_fail(client, error);
+ return;
+ }
+
+ if ( ret == 0 ) return;
+
+ if ( strcmp(str_c(client->auth_response), "*") == 0 ) {
+ client_auth_abort(client);
+ return;
+ }
+
+ client_auth_respond(client, str_c(client->auth_response));
+
+ memset(str_c_modifiable(client->auth_response), 0,
+ str_len(client->auth_response));
+}
+
+int cmd_authenticate
+(struct managesieve_client *msieve_client, const struct managesieve_arg *args)
+{
+ /* NOTE: This command's input is handled specially because the
+ SASL-IR can be large. */
+ struct client *client = &msieve_client->common;
+ const char *mech_name, *init_response;
+ const char *error;
+ int ret;
+
+ if (!msieve_client->auth_mech_name_parsed) {
+ i_assert(args != NULL);
+
+ /* one mandatory argument: authentication mechanism name */
+ if ( !managesieve_arg_get_string(&args[0], &mech_name) )
+ return -1;
+
+ if (*mech_name == '\0')
+ return -1;
+
+ i_free(client->auth_mech_name);
+ client->auth_mech_name = i_strdup(mech_name);
+ msieve_client->auth_mech_name_parsed = TRUE;
+
+ msieve_client->auth_response_input = NULL;
+ managesieve_parser_reset(msieve_client->parser);
+ }
+
+ msieve_client->skip_line = FALSE;
+ if ( (ret=managesieve_client_auth_read_response(msieve_client, TRUE, &error))
+ < 0 ) {
+ msieve_client->auth_mech_name_parsed = FALSE;
+ if ( error != NULL ) {
+ client_send_no(client, error);
+ }
+ return 1;
+ }
+
+ if ( ret == 0 ) return 0;
+
+ init_response = ( client->auth_response == NULL ? NULL :
+ t_strdup(str_c(client->auth_response)) );
+ msieve_client->auth_mech_name_parsed = FALSE;
+ if ( (ret=client_auth_begin
+ (client, t_strdup(client->auth_mech_name), init_response)) < 0 )
+ return ret;
+
+ msieve_client->cmd_finished = TRUE;
+ return 0;
+}
+
diff --git a/pigeonhole/src/managesieve-login/client-authenticate.h b/pigeonhole/src/managesieve-login/client-authenticate.h
new file mode 100644
index 0000000..1280ad5
--- /dev/null
+++ b/pigeonhole/src/managesieve-login/client-authenticate.h
@@ -0,0 +1,21 @@
+#ifndef CLIENT_AUTHENTICATE_H
+#define CLIENT_AUTHENTICATE_H
+
+struct managesieve_arg;
+
+const char *client_authenticate_get_capabilities
+ (struct client *client);
+
+void managesieve_client_auth_result
+ (struct client *client, enum client_auth_result result,
+ const struct client_auth_reply *reply, const char *text);
+
+void managesieve_client_auth_send_challenge
+ (struct client *client, const char *data);
+void managesieve_client_auth_parse_response
+ (struct client *client);
+
+int cmd_authenticate
+ (struct managesieve_client *client, const struct managesieve_arg *args);
+
+#endif
diff --git a/pigeonhole/src/managesieve-login/client.c b/pigeonhole/src/managesieve-login/client.c
new file mode 100644
index 0000000..fe8acff
--- /dev/null
+++ b/pigeonhole/src/managesieve-login/client.c
@@ -0,0 +1,574 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "login-common.h"
+#include "buffer.h"
+#include "ioloop.h"
+#include "istream.h"
+#include "ostream.h"
+#include "safe-memset.h"
+#include "str.h"
+#include "strescape.h"
+#include "base64.h"
+#include "master-service.h"
+#include "master-auth.h"
+#include "auth-client.h"
+
+#include "managesieve-parser.h"
+#include "managesieve-quote.h"
+
+#include "client.h"
+#include "client-authenticate.h"
+
+#include "managesieve-login-settings.h"
+#include "managesieve-proxy.h"
+
+/* Disconnect client when it sends too many bad commands */
+#define CLIENT_MAX_BAD_COMMANDS 3
+
+struct managesieve_command {
+ const char *name;
+ int (*func)(struct managesieve_client *client,
+ const struct managesieve_arg *args);
+ int preparsed_args;
+};
+
+/* Skip incoming data until newline is found,
+ returns TRUE if newline was found. */
+bool client_skip_line(struct managesieve_client *client)
+{
+ const unsigned char *data;
+ size_t i, data_size;
+
+ data = i_stream_get_data(client->common.input, &data_size);
+
+ for (i = 0; i < data_size; i++) {
+ if (data[i] == '\n') {
+ i_stream_skip(client->common.input, i+1);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void client_send_capabilities(struct client *client)
+{
+ struct managesieve_client *msieve_client =
+ (struct managesieve_client *)client;
+ const char *saslcap;
+
+ T_BEGIN {
+ saslcap = client_authenticate_get_capabilities(client);
+
+ /* Default capabilities */
+ client_send_raw(client, t_strconcat(
+ "\"IMPLEMENTATION\" \"",
+ msieve_client->set->managesieve_implementation_string,
+ "\"\r\n", NULL));
+ client_send_raw(client, t_strconcat(
+ "\"SIEVE\" \"",
+ msieve_client->set->managesieve_sieve_capability,
+ "\"\r\n", NULL));
+ if (msieve_client->set->managesieve_notify_capability != NULL) {
+ client_send_raw(client, t_strconcat(
+ "\"NOTIFY\" \"",
+ msieve_client->set->managesieve_notify_capability,
+ "\"\r\n", NULL));
+ }
+ client_send_raw(client, t_strconcat("\"SASL\" \"", saslcap,
+ "\"\r\n", NULL));
+
+ /* STARTTLS */
+ if (login_ssl_initialized && !client->tls)
+ client_send_raw(client, "\"STARTTLS\"\r\n");
+
+ /* Protocol version */
+ client_send_raw(client, "\"VERSION\" \"1.0\"\r\n");
+
+ /* XCLIENT */
+ if (client->trusted)
+ client_send_raw(client, "\"XCLIENT\"\r\n");
+ } T_END;
+}
+
+static int
+cmd_capability(struct managesieve_client *client,
+ const struct managesieve_arg *args ATTR_UNUSED)
+{
+ o_stream_cork(client->common.output);
+
+ client_send_capabilities(&client->common);
+ client_send_ok(&client->common, "Capability completed.");
+
+ o_stream_uncork(client->common.output);
+
+ return 1;
+}
+
+static int
+cmd_starttls(struct managesieve_client *client,
+ const struct managesieve_arg *args ATTR_UNUSED)
+{
+ client_cmd_starttls(&client->common);
+ return 1;
+}
+
+static void
+managesieve_client_notify_starttls(struct client *client, bool success,
+ const char *text)
+{
+ if (success)
+ client_send_ok(client, text);
+ else
+ client_send_no(client, text);
+}
+
+static int
+cmd_noop(struct managesieve_client *client, const struct managesieve_arg *args)
+{
+ const char *text;
+ string_t *resp_code;
+
+ if (MANAGESIEVE_ARG_IS_EOL(&args[0])) {
+ client_send_ok(&client->common, "NOOP Completed");
+ return 1;
+ }
+ if (!MANAGESIEVE_ARG_IS_EOL(&args[1]))
+ return -1;
+ if (!managesieve_arg_get_string(&args[0], &text)) {
+ client_send_no(&client->common, "Invalid echo tag.");
+ return 1;
+ }
+
+ resp_code = t_str_new(256);
+ str_append(resp_code, "TAG ");
+ managesieve_quote_append_string(resp_code, text, FALSE);
+
+ client_send_okresp(&client->common, str_c(resp_code), "Done");
+ return 1;
+}
+
+static int
+cmd_logout(struct managesieve_client *client,
+ const struct managesieve_arg *args ATTR_UNUSED)
+{
+ client_send_ok(&client->common, "Logout completed.");
+ client_destroy(&client->common, CLIENT_UNAUTHENTICATED_LOGOUT_MSG);
+ return 1;
+}
+
+static int
+cmd_xclient_parse_forward(struct managesieve_client *client, const char *value)
+{
+ size_t value_len = strlen(value);
+
+ if (client->common.forward_fields != NULL)
+ str_truncate(client->common.forward_fields, 0);
+ else {
+ client->common.forward_fields = str_new(
+ client->common.preproxy_pool,
+ MAX_BASE64_DECODED_SIZE(value_len));
+ }
+
+ if (base64_decode(value, value_len, NULL,
+ client->common.forward_fields) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+cmd_xclient(struct managesieve_client *client,
+ const struct managesieve_arg *args)
+{
+ const char *arg;
+ bool args_ok = TRUE;
+
+ if (!client->common.trusted) {
+ client_send_no(&client->common, "You are not from trusted IP");
+ return 1;
+ }
+ while (!MANAGESIEVE_ARG_IS_EOL(&args[0]) &&
+ managesieve_arg_get_atom(&args[0], &arg)) {
+ if (strncasecmp(arg, "ADDR=", 5) == 0) {
+ if (net_addr2ip(arg + 5, &client->common.ip) < 0)
+ args_ok = FALSE;
+ } else if (strncasecmp(arg, "FORWARD=", 8) == 0) {
+ if (cmd_xclient_parse_forward(client, arg + 8) < 0)
+ args_ok = FALSE;
+ } else if (strncasecmp(arg, "PORT=", 5) == 0) {
+ if (net_str2port(arg + 5,
+ &client->common.remote_port) < 0)
+ args_ok = FALSE;
+ } else if (strncasecmp(arg, "SESSION=", 8) == 0) {
+ const char *value = arg + 8;
+
+ if (strlen(value) <= LOGIN_MAX_SESSION_ID_LEN) {
+ client->common.session_id =
+ p_strdup(client->common.pool, value);
+ }
+ } else if (strncasecmp(arg, "TTL=", 4) == 0) {
+ if (str_to_uint(arg + 4, &client->common.proxy_ttl) < 0)
+ args_ok = FALSE;
+ }
+ args++;
+ }
+ if (!args_ok || !MANAGESIEVE_ARG_IS_EOL(&args[0]))
+ return -1;
+
+ client_send_ok(&client->common, "Updated");
+ return 1;
+}
+
+static struct managesieve_command commands[] = {
+ { "AUTHENTICATE", cmd_authenticate, 1 },
+ { "CAPABILITY", cmd_capability, -1 },
+ { "STARTTLS", cmd_starttls, -1 },
+ { "NOOP", cmd_noop, 0 },
+ { "LOGOUT", cmd_logout, -1 },
+ { "XCLIENT", cmd_xclient, 0 },
+ { NULL, NULL, 0 }
+};
+
+static bool client_handle_input(struct managesieve_client *client)
+{
+ i_assert(!client->common.authenticating);
+
+ if (client->cmd_finished) {
+ /* Clear the previous command from memory */
+ client->cmd_name = NULL;
+ client->cmd_parsed_args = FALSE;
+ client->cmd = NULL;
+ managesieve_parser_reset(client->parser);
+
+ /* Remove \r\n */
+ if (client->skip_line) {
+ if (!client_skip_line(client))
+ return FALSE;
+ client->skip_line = FALSE;
+ }
+
+ client->cmd_finished = FALSE;
+ }
+
+ if (client->cmd == NULL) {
+ struct managesieve_command *cmd;
+ const char *cmd_name;
+
+ client->cmd_name = managesieve_parser_read_word(client->parser);
+ if (client->cmd_name == NULL)
+ return FALSE; /* Need more data */
+
+ cmd_name = t_str_ucase(client->cmd_name);
+ cmd = commands;
+ while (cmd->name != NULL) {
+ if (strcmp(cmd->name, cmd_name) == 0)
+ break;
+ cmd++;
+ }
+
+ if (cmd->name != NULL)
+ client->cmd = cmd;
+ else
+ client->skip_line = TRUE;
+ }
+ return client->common.v.input_next_cmd(&client->common);
+}
+
+static bool managesieve_client_input_next_cmd(struct client *_client)
+{
+ struct managesieve_client *client =
+ (struct managesieve_client *)_client;
+ const struct managesieve_arg *args = NULL;
+ const char *msg;
+ int ret = 1;
+ bool fatal;
+
+ if (client->cmd == NULL) {
+ /* Unknown command */
+ ret = -1;
+ } else if (!client->cmd_parsed_args) {
+ unsigned int arg_count =
+ (client->cmd->preparsed_args > 0 ?
+ client->cmd->preparsed_args : 0);
+
+ switch (managesieve_parser_read_args(client->parser, arg_count,
+ 0, &args)) {
+ case -1:
+ /* Error */
+ msg = managesieve_parser_get_error(client->parser,
+ &fatal);
+ if (fatal) {
+ client_send_bye(&client->common, msg);
+ client_destroy(&client->common, msg);
+ return FALSE;
+ }
+ client_send_no(&client->common, msg);
+ client->cmd_finished = TRUE;
+ client->skip_line = TRUE;
+ return TRUE;
+ case -2:
+ /* Not enough data */
+ return FALSE;
+ }
+ i_assert(args != NULL);
+
+ if (arg_count == 0) {
+ /* We read the entire line - skip over the CRLF */
+ if (!client_skip_line(client))
+ i_unreached();
+ } else {
+ /* Get rid of it later */
+ client->skip_line = TRUE;
+ }
+
+ client->cmd_parsed_args = TRUE;
+
+ if (client->cmd->preparsed_args == -1) {
+ /* Check absence of arguments */
+ if (args[0].type != MANAGESIEVE_ARG_EOL)
+ ret = -1;
+ }
+ }
+ if (ret > 0) {
+ i_assert(client->cmd != NULL);
+ ret = client->cmd->func(client, args);
+ }
+
+ if (ret != 0)
+ client->cmd_finished = TRUE;
+ if (ret < 0) {
+ if (++client->common.bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
+ client_send_bye(&client->common,
+ "Too many invalid MANAGESIEVE commands.");
+ client_destroy(&client->common,
+ "Too many invalid commands.");
+ return FALSE;
+ }
+ client_send_no(&client->common,
+ "Error in MANAGESIEVE command received by server.");
+ }
+
+ return ret != 0 && !client->common.destroyed;
+}
+
+static void managesieve_client_input(struct client *client)
+{
+ struct managesieve_client *managesieve_client =
+ (struct managesieve_client *)client;
+
+ if (!client_read(client))
+ return;
+
+ client_ref(client);
+ o_stream_cork(managesieve_client->common.output);
+ for (;;) {
+ if (!auth_client_is_connected(auth_client)) {
+ /* We're not currently connected to auth process -
+ don't allow any commands */
+ /* FIXME: Can't do untagged responses with managesieve.
+ Any other ways?
+ client_send_ok(client, AUTH_SERVER_WAITING_MSG);
+ */
+ timeout_remove(&client->to_auth_waiting);
+
+ client->input_blocked = TRUE;
+ break;
+ } else {
+ if (!client_handle_input(managesieve_client))
+ break;
+ }
+ }
+ o_stream_uncork(managesieve_client->common.output);
+ client_unref(&client);
+}
+
+static struct client *managesieve_client_alloc(pool_t pool)
+{
+ struct managesieve_client *msieve_client;
+
+ msieve_client = p_new(pool, struct managesieve_client, 1);
+ return &msieve_client->common;
+}
+
+static void managesieve_client_create(struct client *client, void **other_sets)
+{
+ struct managesieve_client *msieve_client =
+ (struct managesieve_client *)client;
+
+ msieve_client->set = other_sets[0];
+ msieve_client->parser = managesieve_parser_create(
+ msieve_client->common.input, MAX_MANAGESIEVE_LINE);
+ client->io = io_add(client->fd, IO_READ, client_input, client);
+}
+
+static void managesieve_client_destroy(struct client *client)
+{
+ struct managesieve_client *managesieve_client =
+ (struct managesieve_client *)client;
+
+ managesieve_parser_destroy(&managesieve_client->parser);
+}
+
+static void managesieve_client_notify_auth_ready(struct client *client)
+{
+ /* Cork the stream to send the capability data as a single tcp frame
+ Some naive clients break if we don't.
+ */
+ o_stream_cork(client->output);
+
+ /* Send initial capabilities */
+ client_send_capabilities(client);
+ client_send_ok(client, client->set->login_greeting);
+
+ o_stream_uncork(client->output);
+
+ client->banner_sent = TRUE;
+}
+
+static void managesieve_client_starttls(struct client *client)
+{
+ struct managesieve_client *msieve_client =
+ (struct managesieve_client *)client;
+
+ managesieve_parser_destroy(&msieve_client->parser);
+ msieve_client->parser = managesieve_parser_create(
+ msieve_client->common.input, MAX_MANAGESIEVE_LINE);
+
+ /* CRLF is lost from buffer when streams are reopened. */
+ msieve_client->skip_line = FALSE;
+
+ /* Cork the stream to send the capability data as a single tcp frame
+ Some naive clients break if we don't.
+ */
+ o_stream_cork(client->output);
+
+ client_send_capabilities(client);
+ client_send_ok(client, "TLS negotiation successful.");
+
+ o_stream_uncork(client->output);
+}
+
+static void
+client_send_reply_raw(struct client *client, const char *prefix,
+ const char *resp_code, const char *text)
+{
+ T_BEGIN {
+ string_t *line = t_str_new(256);
+
+ str_append(line, prefix);
+
+ if (resp_code != NULL) {
+ str_append(line, " (");
+ str_append(line, resp_code);
+ str_append_c(line, ')');
+ }
+
+ if (text != NULL) {
+ str_append_c(line, ' ');
+ managesieve_quote_append_string(line, text, TRUE);
+ }
+
+ str_append(line, "\r\n");
+
+ client_send_raw_data(client, str_data(line), str_len(line));
+ } T_END;
+}
+
+void client_send_reply_code(struct client *client,
+ enum managesieve_cmd_reply reply,
+ const char *resp_code, const char *text)
+{
+ const char *prefix = "NO";
+
+ switch (reply) {
+ case MANAGESIEVE_CMD_REPLY_OK:
+ prefix = "OK";
+ break;
+ case MANAGESIEVE_CMD_REPLY_NO:
+ break;
+ case MANAGESIEVE_CMD_REPLY_BYE:
+ prefix = "BYE";
+ break;
+ }
+
+ client_send_reply_raw(client, prefix, resp_code, text);
+}
+
+void client_send_reply(struct client *client, enum managesieve_cmd_reply reply,
+ const char *text)
+{
+ client_send_reply_code(client, reply, NULL, text);
+}
+
+static void
+managesieve_client_notify_disconnect(struct client *client,
+ enum client_disconnect_reason reason,
+ const char *text)
+{
+ if (reason == CLIENT_DISCONNECT_SYSTEM_SHUTDOWN) {
+ client_send_reply_code(client, MANAGESIEVE_CMD_REPLY_BYE,
+ "TRYLATER", text);
+ } else {
+ client_send_reply_code(client, MANAGESIEVE_CMD_REPLY_BYE,
+ NULL, text);
+ }
+}
+
+static void managesieve_login_preinit(void)
+{
+ login_set_roots = managesieve_login_settings_set_roots;
+}
+
+static void managesieve_login_init(void)
+{
+}
+
+static void managesieve_login_deinit(void)
+{
+ clients_destroy_all();
+}
+
+static struct client_vfuncs managesieve_client_vfuncs = {
+ .alloc = managesieve_client_alloc,
+ .create = managesieve_client_create,
+ .destroy = managesieve_client_destroy,
+ .notify_auth_ready = managesieve_client_notify_auth_ready,
+ .notify_disconnect = managesieve_client_notify_disconnect,
+ .notify_starttls = managesieve_client_notify_starttls,
+ .starttls = managesieve_client_starttls,
+ .input = managesieve_client_input,
+ .auth_send_challenge = managesieve_client_auth_send_challenge,
+ .auth_parse_response = managesieve_client_auth_parse_response,
+ .auth_result = managesieve_client_auth_result,
+ .proxy_reset = managesieve_proxy_reset,
+ .proxy_parse_line = managesieve_proxy_parse_line,
+ .proxy_failed = managesieve_proxy_failed,
+ .proxy_get_state = managesieve_proxy_get_state,
+ .send_raw_data = client_common_send_raw_data,
+ .input_next_cmd = managesieve_client_input_next_cmd,
+ .free = client_common_default_free,
+};
+
+static struct login_binary managesieve_login_binary = {
+ .protocol = "sieve",
+ .process_name = "managesieve-login",
+ .default_port = 4190,
+
+ .event_category = {
+ .name = "managesieve",
+ },
+
+ .client_vfuncs = &managesieve_client_vfuncs,
+ .preinit = managesieve_login_preinit,
+ .init = managesieve_login_init,
+ .deinit = managesieve_login_deinit,
+
+ .anonymous_login_acceptable = FALSE,
+};
+
+int main(int argc, char *argv[])
+{
+ return login_binary_run(&managesieve_login_binary, argc, argv);
+}
diff --git a/pigeonhole/src/managesieve-login/client.h b/pigeonhole/src/managesieve-login/client.h
new file mode 100644
index 0000000..a04190d
--- /dev/null
+++ b/pigeonhole/src/managesieve-login/client.h
@@ -0,0 +1,76 @@
+#ifndef CLIENT_H
+#define CLIENT_H
+
+#include "net.h"
+#include "client-common.h"
+
+/* maximum length for managesieve command line. */
+#define MAX_MANAGESIEVE_LINE 8192
+
+enum managesieve_proxy_state {
+ MSIEVE_PROXY_STATE_NONE,
+ MSIEVE_PROXY_STATE_TLS_START,
+ MSIEVE_PROXY_STATE_TLS_READY,
+ MSIEVE_PROXY_STATE_XCLIENT,
+ MSIEVE_PROXY_STATE_AUTH,
+
+ MSIEVE_PROXY_STATE_COUNT
+};
+struct managesieve_command;
+
+struct managesieve_client {
+ struct client common;
+
+ const struct managesieve_login_settings *set;
+ struct managesieve_parser *parser;
+
+ enum managesieve_proxy_state proxy_state;
+
+ const char *cmd_name;
+ struct managesieve_command *cmd;
+
+ struct istream *auth_response_input;
+
+ bool cmd_finished:1;
+ bool cmd_parsed_args:1;
+ bool skip_line:1;
+ bool auth_mech_name_parsed:1;
+
+ bool proxy_starttls:1;
+ bool proxy_sasl:1;
+ bool proxy_xclient:1;
+};
+
+bool client_skip_line(struct managesieve_client *client);
+
+enum managesieve_cmd_reply {
+ MANAGESIEVE_CMD_REPLY_OK,
+ MANAGESIEVE_CMD_REPLY_NO,
+ MANAGESIEVE_CMD_REPLY_BYE
+};
+
+void client_send_reply(struct client *client, enum managesieve_cmd_reply reply,
+ const char *text);
+
+void client_send_reply_code(struct client *client,
+ enum managesieve_cmd_reply reply,
+ const char *resp_code, const char *text);
+
+#define client_send_ok(client, text) \
+ client_send_reply(client, MANAGESIEVE_CMD_REPLY_OK, text)
+#define client_send_no(client, text) \
+ client_send_reply(client, MANAGESIEVE_CMD_REPLY_NO, text)
+#define client_send_bye(client, text) \
+ client_send_reply(client, MANAGESIEVE_CMD_REPLY_BYE, text)
+
+#define client_send_okresp(client, resp_code, text) \
+ client_send_reply_code(client, MANAGESIEVE_CMD_REPLY_OK, \
+ resp_code, text)
+#define client_send_noresp(client, resp_code, text) \
+ client_send_reply_code(client, MANAGESIEVE_CMD_REPLY_NO, \
+ resp_code, text)
+#define client_send_byeresp(client, resp_code, text) \
+ client_send_reply_code(client, MANAGESIEVE_CMD_REPLY_BYE, \
+ resp_code, text)
+
+#endif
diff --git a/pigeonhole/src/managesieve-login/managesieve-login-settings-plugin.c b/pigeonhole/src/managesieve-login/managesieve-login-settings-plugin.c
new file mode 100644
index 0000000..12515cd
--- /dev/null
+++ b/pigeonhole/src/managesieve-login/managesieve-login-settings-plugin.c
@@ -0,0 +1,223 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "buffer.h"
+#include "env-util.h"
+#include "execv-const.h"
+#include "master-service.h"
+#include "settings-parser.h"
+#include "config-parser-private.h"
+#include "managesieve-login-settings-plugin.h"
+
+#include <stddef.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sysexits.h>
+
+typedef enum { CAP_SIEVE, CAP_NOTIFY } capability_type_t;
+
+bool capability_dumped = FALSE;
+static char *capability_sieve = NULL;
+static char *capability_notify = NULL;
+
+static void (*next_hook_config_parser_begin)(struct config_parser_context *ctx) = NULL;
+
+static void managesieve_login_config_parser_begin(struct config_parser_context *ctx);
+
+const char *managesieve_login_settings_version = DOVECOT_ABI_VERSION;
+
+void managesieve_login_settings_init(struct module *module ATTR_UNUSED)
+{
+ next_hook_config_parser_begin = hook_config_parser_begin;
+ hook_config_parser_begin = managesieve_login_config_parser_begin;
+}
+
+void managesieve_login_settings_deinit(void)
+{
+ hook_config_parser_begin = next_hook_config_parser_begin;
+
+ if ( capability_sieve != NULL )
+ i_free(capability_sieve);
+
+ if ( capability_notify != NULL )
+ i_free(capability_notify);
+}
+
+static void capability_store(capability_type_t cap_type, const char *value)
+{
+ switch ( cap_type ) {
+ case CAP_SIEVE:
+ capability_sieve = i_strdup(value);
+ break;
+ case CAP_NOTIFY:
+ capability_notify = i_strdup(value);
+ break;
+ }
+}
+
+static void capability_parse(const char *cap_string)
+{
+ capability_type_t cap_type = CAP_SIEVE;
+ const char *p = cap_string;
+ string_t *part = t_str_new(256);
+
+ if ( cap_string == NULL || *cap_string == '\0' ) {
+ i_warning("managesieve-login: capability string is empty.");
+ return;
+ }
+
+ while ( *p != '\0' ) {
+ if ( *p == '\\' ) {
+ p++;
+ if ( *p != '\0' ) {
+ str_append_c(part, *p);
+ p++;
+ } else break;
+ } else if ( *p == ':' ) {
+ if ( strcasecmp(str_c(part), "SIEVE") == 0 )
+ cap_type = CAP_SIEVE;
+ else if ( strcasecmp(str_c(part), "NOTIFY") == 0 )
+ cap_type = CAP_NOTIFY;
+ else
+ i_warning("managesieve-login: unknown capability '%s' listed in "
+ "capability string (ignored).", str_c(part));
+ str_truncate(part, 0);
+ } else if ( *p == ',' ) {
+ capability_store(cap_type, str_c(part));
+ str_truncate(part, 0);
+ } else {
+ /* Append character, but omit leading spaces */
+ if ( str_len(part) > 0 || *p != ' ' )
+ str_append_c(part, *p);
+ }
+ p++;
+ }
+
+ if ( str_len(part) > 0 ) {
+ capability_store(cap_type, str_c(part));
+ }
+}
+
+static bool capability_dump(void)
+{
+ char buf[4096];
+ int fd[2], status = 0;
+ ssize_t ret;
+ unsigned int pos;
+ pid_t pid;
+
+ if ( getenv("DUMP_CAPABILITY") != NULL )
+ return TRUE;
+
+ if ( pipe(fd) < 0 ) {
+ i_error("managesieve-login: dump-capability pipe() failed: %m");
+ return FALSE;
+ }
+ fd_close_on_exec(fd[0], TRUE);
+ fd_close_on_exec(fd[1], TRUE);
+
+ if ( (pid = fork()) == (pid_t)-1 ) {
+ (void)close(fd[0]); (void)close(fd[1]);
+ i_error("managesieve-login: dump-capability fork() failed: %m");
+ return FALSE;
+ }
+
+ if ( pid == 0 ) {
+ const char *argv[5];
+
+ /* Child */
+ (void)close(fd[0]);
+
+ if (dup2(fd[1], STDOUT_FILENO) < 0)
+ i_fatal("managesieve-login: dump-capability dup2() failed: %m");
+
+ env_put("DUMP_CAPABILITY", "1");
+
+ argv[0] = PKG_LIBEXECDIR"/managesieve";
+ argv[1] = "-k";
+ argv[2] = "-c";
+ argv[3] = master_service_get_config_path(master_service);
+ argv[4] = NULL;
+ execv_const(argv[0], argv);
+
+ i_fatal("managesieve-login: dump-capability execv(%s) failed: %m", argv[0]);
+ }
+
+ (void)close(fd[1]);
+
+ alarm(60);
+ if (wait(&status) == -1) {
+ i_error("managesieve-login: dump-capability failed: process %d got stuck",
+ (int)pid);
+ return FALSE;
+ }
+ alarm(0);
+
+ if (status != 0) {
+ (void)close(fd[0]);
+ if (WIFSIGNALED(status)) {
+ i_error("managesieve-login: dump-capability process "
+ "killed with signal %d", WTERMSIG(status));
+ } else {
+ i_error("managesieve-login: dump-capability process returned %d",
+ WIFEXITED(status) ? WEXITSTATUS(status) : status);
+ }
+ return FALSE;
+ }
+
+ pos = 0;
+ while ((ret = read(fd[0], buf + pos, sizeof(buf) - pos)) > 0)
+ pos += ret;
+
+ if (ret < 0) {
+ i_error("managesieve-login: read(dump-capability process) failed: %m");
+ (void)close(fd[0]);
+ return FALSE;
+ }
+ (void)close(fd[0]);
+
+ if (pos == 0 || buf[pos-1] != '\n') {
+ i_error("managesieve-login: dump-capability: Couldn't read capability "
+ "(got %u bytes)", pos);
+ return FALSE;
+ }
+ buf[pos-1] = '\0';
+
+ capability_parse(buf);
+
+ return TRUE;
+}
+
+static void managesieve_login_config_set
+(struct config_parser_context *ctx, const char *key, const char *value)
+{
+ config_apply_line(ctx, key, t_strdup_printf("%s=%s", key, value), NULL);
+}
+
+static void managesieve_login_config_parser_begin(struct config_parser_context *ctx)
+{
+ const char *const *module = ctx->modules;
+
+ if ( module != NULL && *module != NULL ) {
+ while ( *module != NULL ) {
+ if ( strcmp(*module, "managesieve-login") == 0 )
+ break;
+ module++;
+ }
+ if ( *module == NULL )
+ return;
+ }
+
+ if ( !capability_dumped ) {
+ (void)capability_dump();
+ capability_dumped = TRUE;
+ }
+
+ if ( capability_sieve != NULL )
+ managesieve_login_config_set(ctx, "managesieve_sieve_capability", capability_sieve);
+
+ if ( capability_notify != NULL )
+ managesieve_login_config_set(ctx, "managesieve_notify_capability", capability_notify);
+}
diff --git a/pigeonhole/src/managesieve-login/managesieve-login-settings-plugin.h b/pigeonhole/src/managesieve-login/managesieve-login-settings-plugin.h
new file mode 100644
index 0000000..ebefe1a
--- /dev/null
+++ b/pigeonhole/src/managesieve-login/managesieve-login-settings-plugin.h
@@ -0,0 +1,9 @@
+#ifndef MANAGESIEVE_LOGIN_SETTINGS_PLUGIN_H
+#define MANAGESIEVE_LOGIN_SETTINGS_PLUGIN_H
+
+#include "lib.h"
+
+void managesieve_login_settings_init(struct module *module);
+void managesieve_login_settings_deinit(void);
+
+#endif
diff --git a/pigeonhole/src/managesieve-login/managesieve-login-settings.c b/pigeonhole/src/managesieve-login/managesieve-login-settings.c
new file mode 100644
index 0000000..9146d03
--- /dev/null
+++ b/pigeonhole/src/managesieve-login/managesieve-login-settings.c
@@ -0,0 +1,104 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "buffer.h"
+#include "env-util.h"
+#include "execv-const.h"
+#include "settings-parser.h"
+#include "service-settings.h"
+#include "login-settings.h"
+
+#include "pigeonhole-config.h"
+
+#include "managesieve-login-settings.h"
+
+#include <stddef.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sysexits.h>
+
+/* <settings checks> */
+
+static struct inet_listener_settings managesieve_login_inet_listeners_array[] = {
+ { .name = "sieve", .address = "", .port = 4190 },
+};
+static struct inet_listener_settings *managesieve_login_inet_listeners[] = {
+ &managesieve_login_inet_listeners_array[0]
+};
+static buffer_t managesieve_login_inet_listeners_buf = {
+ { { managesieve_login_inet_listeners,
+ sizeof(managesieve_login_inet_listeners) } }
+};
+/* </settings checks> */
+
+struct service_settings managesieve_login_settings_service_settings = {
+ .name = "managesieve-login",
+ .protocol = "sieve",
+ .type = "login",
+ .executable = "managesieve-login",
+ .user = "$default_login_user",
+ .group = "",
+ .privileged_group = "",
+ .extra_groups = "",
+ .chroot = "login",
+
+ .drop_priv_before_exec = FALSE,
+
+ .process_min_avail = 0,
+ .process_limit = 0,
+ .client_limit = 0,
+ .service_count = 1,
+ .idle_kill = 0,
+ .vsz_limit = (uoff_t)-1,
+
+ .unix_listeners = ARRAY_INIT,
+ .fifo_listeners = ARRAY_INIT,
+ .inet_listeners = { { &managesieve_login_inet_listeners_buf,
+ sizeof(managesieve_login_inet_listeners[0]) } }
+};
+
+#undef DEF
+#define DEF(type, name) \
+ SETTING_DEFINE_STRUCT_##type(#name, name, struct managesieve_login_settings)
+
+static const struct setting_define managesieve_login_setting_defines[] = {
+ DEF(STR, managesieve_implementation_string),
+ DEF(STR, managesieve_sieve_capability),
+ DEF(STR, managesieve_notify_capability),
+
+ SETTING_DEFINE_LIST_END
+};
+
+static const struct managesieve_login_settings managesieve_login_default_settings = {
+ .managesieve_implementation_string = DOVECOT_NAME " " PIGEONHOLE_NAME,
+ .managesieve_sieve_capability = "",
+ .managesieve_notify_capability = NULL
+};
+
+static const struct setting_parser_info *managesieve_login_setting_dependencies[] = {
+ &login_setting_parser_info,
+ NULL
+};
+
+static const struct setting_parser_info managesieve_login_setting_parser_info = {
+ .module_name = "managesieve-login",
+ .defines = managesieve_login_setting_defines,
+ .defaults = &managesieve_login_default_settings,
+
+ .type_offset = (size_t)-1,
+ .struct_size = sizeof(struct managesieve_login_settings),
+
+ .parent_offset = (size_t)-1,
+ .parent = NULL,
+
+ .dependencies = managesieve_login_setting_dependencies
+};
+
+const struct setting_parser_info *managesieve_login_settings_set_roots[] = {
+ &login_setting_parser_info,
+ &managesieve_login_setting_parser_info,
+ NULL
+};
+
diff --git a/pigeonhole/src/managesieve-login/managesieve-login-settings.h b/pigeonhole/src/managesieve-login/managesieve-login-settings.h
new file mode 100644
index 0000000..c6f4826
--- /dev/null
+++ b/pigeonhole/src/managesieve-login/managesieve-login-settings.h
@@ -0,0 +1,17 @@
+#ifndef MANAGESIEVE_LOGIN_SETTINGS_H
+#define MANAGESIEVE_LOGIN_SETTINGS_H
+
+struct managesieve_login_settings {
+ const char *managesieve_implementation_string;
+ const char *managesieve_sieve_capability;
+ const char *managesieve_notify_capability;
+};
+
+extern const struct setting_parser_info *managesieve_login_settings_set_roots[];
+
+#ifdef _CONFIG_PLUGIN
+void managesieve_login_settings_init(void);
+void managesieve_login_settings_deinit(void);
+#endif
+
+#endif
diff --git a/pigeonhole/src/managesieve-login/managesieve-proxy.c b/pigeonhole/src/managesieve-login/managesieve-proxy.c
new file mode 100644
index 0000000..50e31ae
--- /dev/null
+++ b/pigeonhole/src/managesieve-login/managesieve-proxy.c
@@ -0,0 +1,686 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include <string.h>
+#include "login-common.h"
+#include "ioloop.h"
+#include "istream.h"
+#include "ostream.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "strescape.h"
+#include "safe-memset.h"
+#include "buffer.h"
+#include "base64.h"
+#include "dsasl-client.h"
+
+#include "client.h"
+#include "client-authenticate.h"
+
+#include "managesieve-quote.h"
+#include "managesieve-proxy.h"
+#include "managesieve-parser.h"
+
+typedef enum {
+ MANAGESIEVE_RESPONSE_NONE,
+ MANAGESIEVE_RESPONSE_OK,
+ MANAGESIEVE_RESPONSE_NO,
+ MANAGESIEVE_RESPONSE_BYE
+} managesieve_response_t;
+
+static const char *managesieve_proxy_state_names[MSIEVE_PROXY_STATE_COUNT] = {
+ "none", "tls-start", "tls-ready", "xclient", "auth"
+};
+
+static string_t *
+proxy_compose_xclient_forward(struct managesieve_client *client)
+{
+ const char *const *arg;
+ string_t *str;
+
+ if (*client->common.auth_passdb_args == NULL)
+ return NULL;
+
+ str = t_str_new(128);
+ for (arg = client->common.auth_passdb_args; *arg != NULL; arg++) {
+ if (strncasecmp(*arg, "forward_", 8) == 0) {
+ if (str_len(str) > 0)
+ str_append_c(str, '\t');
+ str_append_tabescaped(str, (*arg)+8);
+ }
+ }
+ if (str_len(str) == 0)
+ return NULL;
+
+ return str;
+}
+
+static void
+proxy_write_xclient(struct managesieve_client *client, string_t *str)
+{
+ string_t *fwd = proxy_compose_xclient_forward(client);
+
+ str_printfa(str, "XCLIENT ADDR=%s PORT=%u SESSION=%s TTL=%u",
+ net_ip2addr(&client->common.ip), client->common.remote_port,
+ client_get_session_id(&client->common),
+ client->common.proxy_ttl - 1);
+ if (fwd != NULL) {
+ str_append(str, " FORWARD=");
+ base64_encode(str_data(fwd), str_len(fwd), str);
+ }
+ str_append(str, "\r\n");
+}
+
+static void
+proxy_write_auth_data(const unsigned char *data, unsigned int data_len,
+ string_t *str)
+{
+ if (data_len == 0)
+ str_append(str, "\"\"");
+ else {
+ string_t *data_str = t_str_new(128);
+ base64_encode(data, data_len, data_str);
+ managesieve_quote_append_string(str, str_c(data_str), FALSE);
+ }
+}
+
+static int
+proxy_write_auth(struct managesieve_client *client, string_t *str)
+{
+ struct dsasl_client_settings sasl_set;
+ const unsigned char *output;
+ size_t len;
+ const char *mech_name, *error;
+
+ i_assert(client->common.proxy_ttl > 1);
+
+ if (!client->proxy_sasl) {
+ /* Prevent sending credentials to a server that has login
+ disabled; i.e., due to the lack of TLS */
+ login_proxy_failed(client->common.login_proxy,
+ login_proxy_get_event(client->common.login_proxy),
+ LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG,
+ "Server has disabled authentication (TLS required?)");
+ return -1;
+ }
+
+ if (client->common.proxy_mech == NULL)
+ client->common.proxy_mech = &dsasl_client_mech_plain;
+
+ i_assert(client->common.proxy_sasl_client == NULL);
+ i_zero(&sasl_set);
+ sasl_set.authid = (client->common.proxy_master_user != NULL ?
+ client->common.proxy_master_user :
+ client->common.proxy_user);
+ sasl_set.authzid = client->common.proxy_user;
+ sasl_set.password = client->common.proxy_password;
+ client->common.proxy_sasl_client =
+ dsasl_client_new(client->common.proxy_mech, &sasl_set);
+ mech_name = dsasl_client_mech_get_name(client->common.proxy_mech);
+
+ str_append(str, "AUTHENTICATE ");
+ managesieve_quote_append_string(str, mech_name, FALSE);
+ if (dsasl_client_output(client->common.proxy_sasl_client,
+ &output, &len, &error) < 0) {
+ const char *reason = t_strdup_printf(
+ "SASL mechanism %s init failed: %s",
+ mech_name, error);
+ login_proxy_failed(client->common.login_proxy,
+ login_proxy_get_event(client->common.login_proxy),
+ LOGIN_PROXY_FAILURE_TYPE_INTERNAL, reason);
+ return -1;
+ }
+ if (len > 0) {
+ str_append_c(str, ' ');
+ proxy_write_auth_data(output, len, str);
+ }
+ str_append(str, "\r\n");
+ return 0;
+}
+
+static int
+proxy_input_auth_challenge(struct managesieve_client *client, const char *line,
+ const char **challenge_r)
+{
+ struct istream *input;
+ struct managesieve_parser *parser;
+ const struct managesieve_arg *args;
+ const char *challenge;
+ bool fatal = FALSE;
+ int ret;
+
+ i_assert(client->common.proxy_sasl_client != NULL);
+ *challenge_r = NULL;
+
+ /* Build an input stream for the managesieve parser.
+ FIXME: Ugly, see proxy_input_capability().
+ */
+ line = t_strconcat(line, "\r\n", NULL);
+ input = i_stream_create_from_data(line, strlen(line));
+ parser = managesieve_parser_create(input, MAX_MANAGESIEVE_LINE);
+ managesieve_parser_reset(parser);
+
+ (void)i_stream_read(input);
+ ret = managesieve_parser_read_args(parser, 1, 0, &args);
+
+ if (ret >= 0) {
+ if (ret > 0 &&
+ managesieve_arg_get_string(&args[0], &challenge)) {
+ *challenge_r = t_strdup(challenge);
+ } else {
+ const char *reason = t_strdup_printf(
+ "Server sent invalid SASL challenge line: %s",
+ str_sanitize(line,160));
+ login_proxy_failed(client->common.login_proxy,
+ login_proxy_get_event(client->common.login_proxy),
+ LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason);
+ fatal = TRUE;
+ }
+
+ } else if (ret == -2) {
+ /* Parser needs more data (not possible on mem stream) */
+ i_unreached();
+
+ } else {
+ const char *error_str =
+ managesieve_parser_get_error(parser, &fatal);
+ error_str = (error_str != NULL ? error_str : "unknown (bug)");
+
+ /* Do not accept faulty server */
+ const char *reason = t_strdup_printf(
+ "Protocol parse error(%d) int SASL challenge line: %s "
+ "(line=`%s')", ret, error_str, line);
+ login_proxy_failed(client->common.login_proxy,
+ login_proxy_get_event(client->common.login_proxy),
+ LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason);
+ fatal = TRUE;
+ }
+
+
+ /* Cleanup parser */
+ managesieve_parser_destroy(&parser);
+ i_stream_destroy(&input);
+
+ /* Time to exit if greeting was not accepted */
+ if (fatal)
+ return -1;
+ return 0;
+}
+
+static int
+proxy_write_auth_response(struct managesieve_client *client,
+ const char *challenge, string_t *str)
+{
+ const unsigned char *data;
+ size_t data_len;
+ const char *error;
+ int ret;
+
+ if (base64_decode(challenge, strlen(challenge), NULL, str) < 0) {
+ login_proxy_failed(client->common.login_proxy,
+ login_proxy_get_event(client->common.login_proxy),
+ LOGIN_PROXY_FAILURE_TYPE_PROTOCOL,
+ "Server sent invalid base64 data in AUTHENTICATE response");
+ return -1;
+ }
+ ret = dsasl_client_input(client->common.proxy_sasl_client,
+ str_data(str), str_len(str), &error);
+ if (ret == 0) {
+ ret = dsasl_client_output(client->common.proxy_sasl_client,
+ &data, &data_len, &error);
+ }
+ if (ret < 0) {
+ const char *reason = t_strdup_printf(
+ "Server sent invalid authentication data: %s", error);
+ login_proxy_failed(client->common.login_proxy,
+ login_proxy_get_event(client->common.login_proxy),
+ LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason);
+ return -1;
+ }
+ i_assert(ret == 0);
+
+ str_truncate(str, 0);
+ proxy_write_auth_data(data, data_len, str);
+ str_append(str, "\r\n");
+ return 0;
+}
+
+static managesieve_response_t
+proxy_read_response(const struct managesieve_arg *args)
+{
+ const char *response;
+
+ if (managesieve_arg_get_atom(&args[0], &response)) {
+ if (strcasecmp(response, "OK") == 0) {
+ /* Received OK response; greeting is finished */
+ return MANAGESIEVE_RESPONSE_OK;
+
+ } else if (strcasecmp(response, "NO") == 0) {
+ /* Received OK response; greeting is finished */
+ return MANAGESIEVE_RESPONSE_NO;
+
+ } else if (strcasecmp(response, "BYE") == 0) {
+ /* Received OK response; greeting is finished */
+ return MANAGESIEVE_RESPONSE_BYE;
+ }
+ }
+ return MANAGESIEVE_RESPONSE_NONE;
+}
+
+static int
+proxy_input_capability(struct managesieve_client *client, const char *line,
+ managesieve_response_t *resp_r)
+{
+ struct istream *input;
+ struct managesieve_parser *parser;
+ const struct managesieve_arg *args;
+ const char *capability;
+ int ret;
+ bool fatal = FALSE;
+
+ *resp_r = MANAGESIEVE_RESPONSE_NONE;
+
+ /* Build an input stream for the managesieve parser
+
+ FIXME: It would be nice if the line-wise parsing could be substituded
+ by something similar to the command line interpreter. However,
+ the current login_proxy structure does not make streams known
+ until inside proxy_input handler.
+ */
+ line = t_strconcat(line, "\r\n", NULL);
+ input = i_stream_create_from_data(line, strlen(line));
+ parser = managesieve_parser_create(input, MAX_MANAGESIEVE_LINE);
+ managesieve_parser_reset(parser);
+
+ /* Parse input
+
+ FIXME: Theoretically the OK response could include a response code
+ which could be rejected by the parser.
+ */
+ (void)i_stream_read(input);
+ ret = managesieve_parser_read_args(parser, 2, 0, &args);
+
+ if (ret == 0) {
+ const char *reason = t_strdup_printf(
+ "Remote returned with invalid capability/greeting line: %s",
+ str_sanitize(line,160));
+ login_proxy_failed(client->common.login_proxy,
+ login_proxy_get_event(client->common.login_proxy),
+ LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason);
+ fatal = TRUE;
+ } else if (ret > 0) {
+ if (args[0].type == MANAGESIEVE_ARG_ATOM) {
+ *resp_r = proxy_read_response(args);
+
+ if (*resp_r == MANAGESIEVE_RESPONSE_NONE) {
+ const char *reason = t_strdup_printf(
+ "Remote sent invalid response: %s",
+ str_sanitize(line,160));
+ login_proxy_failed(client->common.login_proxy,
+ login_proxy_get_event(client->common.login_proxy),
+ LOGIN_PROXY_FAILURE_TYPE_PROTOCOL,
+ reason);
+
+ fatal = TRUE;
+ }
+ } else if (managesieve_arg_get_string(&args[0], &capability)) {
+ if (strcasecmp(capability, "SASL") == 0) {
+ const char *sasl_mechs;
+
+ /* Check whether the server supports the SASL mechanism
+ we are going to use (currently only PLAIN supported).
+ */
+ if (ret == 2 &&
+ managesieve_arg_get_string(&args[1], &sasl_mechs)) {
+ const char *const *mechs = t_strsplit(sasl_mechs, " ");
+
+ if (*mechs != NULL) {
+ /* At least one SASL mechanism is supported */
+ client->proxy_sasl = TRUE;
+ }
+
+ } else {
+ login_proxy_failed(client->common.login_proxy,
+ login_proxy_get_event(client->common.login_proxy),
+ LOGIN_PROXY_FAILURE_TYPE_PROTOCOL,
+ "Server returned erroneous SASL capability");
+ fatal = TRUE;
+ }
+
+ } else if (strcasecmp(capability, "STARTTLS") == 0) {
+ client->proxy_starttls = TRUE;
+ } else if (strcasecmp(capability, "XCLIENT") == 0) {
+ client->proxy_xclient = TRUE;
+ }
+
+ } else {
+ /* Do not accept faulty server */
+ const char *reason = t_strdup_printf(
+ "Remote returned with invalid capability/greeting line: %s",
+ str_sanitize(line,160));
+ login_proxy_failed(client->common.login_proxy,
+ login_proxy_get_event(client->common.login_proxy),
+ LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason);
+ fatal = TRUE;
+ }
+
+ } else if (ret == -2) {
+ /* Parser needs more data (not possible on mem stream) */
+ i_unreached();
+
+ } else {
+ const char *error_str =
+ managesieve_parser_get_error(parser, &fatal);
+ error_str = (error_str != NULL ? error_str : "unknown (bug)");
+
+ /* Do not accept faulty server */
+ const char *reason = t_strdup_printf(
+ "Protocol parse error(%d) in capability/greeting line: %s "
+ "(line=`%s')", ret, error_str, line);
+ login_proxy_failed(client->common.login_proxy,
+ login_proxy_get_event(client->common.login_proxy),
+ LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason);
+ fatal = TRUE;
+ }
+
+ /* Cleanup parser */
+ managesieve_parser_destroy(&parser);
+ i_stream_destroy(&input);
+
+ /* Time to exit if greeting was not accepted */
+ if (fatal)
+ return -1;
+
+ /* Wait until greeting is received completely */
+ if (*resp_r == MANAGESIEVE_RESPONSE_NONE)
+ return 1;
+
+ return 0;
+}
+
+static void
+managesieve_proxy_parse_auth_reply(const char *line,
+ const char **reason_r, bool *trylater_r)
+{
+ struct managesieve_parser *parser;
+ const struct managesieve_arg *args;
+ struct istream *input;
+ const char *reason;
+ int ret;
+
+ *trylater_r = FALSE;
+
+ if (strncasecmp(line, "NO ", 3) != 0) {
+ *reason_r = line;
+ return;
+ }
+ line += 3;
+ *reason_r = line;
+
+ if (line[0] == '(') {
+ /* Parse optional resp-code. FIXME: The current
+ managesieve-parser can't really handle this properly, so
+ we'll just assume that there aren't any strings with ')'
+ in them. */
+ if (strncasecmp(line, "(TRYLATER) ", 11) == 0) {
+ *trylater_r = TRUE;
+ line += 11;
+ } else {
+ line = strstr(line, ") ");
+ if (line == NULL)
+ return;
+ line += 2;
+ }
+ }
+
+ /* Parse the string */
+ input = i_stream_create_from_data(line, strlen(line));
+ parser = managesieve_parser_create(input, (size_t)-1);
+ (void)i_stream_read(input);
+ ret = managesieve_parser_finish_line(parser, 0, 0, &args);
+ if (ret == 1 && managesieve_arg_get_string(&args[0], &reason))
+ *reason_r = t_strdup(reason);
+ managesieve_parser_destroy(&parser);
+ i_stream_destroy(&input);
+}
+
+int managesieve_proxy_parse_line(struct client *client, const char *line)
+{
+ struct managesieve_client *msieve_client =
+ (struct managesieve_client *)client;
+ struct ostream *output;
+ enum login_proxy_ssl_flags ssl_flags;
+ managesieve_response_t response = MANAGESIEVE_RESPONSE_NONE;
+ string_t *command;
+ int ret = 0;
+
+ i_assert(!client->destroyed);
+
+ output = login_proxy_get_ostream(client->login_proxy);
+ switch (msieve_client->proxy_state) {
+ case MSIEVE_PROXY_STATE_NONE:
+ ret = proxy_input_capability(msieve_client, line, &response);
+ if (ret < 0)
+ return -1;
+ if (ret == 0) {
+ if (response != MANAGESIEVE_RESPONSE_OK) {
+ login_proxy_failed(client->login_proxy,
+ login_proxy_get_event(client->login_proxy),
+ LOGIN_PROXY_FAILURE_TYPE_PROTOCOL,
+ "Remote sent unexpected NO/BYE instead of capability response");
+ return -1;
+ }
+
+ command = t_str_new(128);
+
+ ssl_flags = login_proxy_get_ssl_flags(client->login_proxy);
+ if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) != 0) {
+ if (!msieve_client->proxy_starttls) {
+ login_proxy_failed(client->login_proxy,
+ login_proxy_get_event(client->login_proxy),
+ LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG,
+ "Remote doesn't support STARTTLS");
+ return -1;
+ }
+
+ str_append(command, "STARTTLS\r\n");
+ msieve_client->proxy_state = MSIEVE_PROXY_STATE_TLS_START;
+ } else if (msieve_client->proxy_xclient) {
+ proxy_write_xclient(msieve_client, command);
+ msieve_client->proxy_state = MSIEVE_PROXY_STATE_XCLIENT;
+ } else {
+ if (proxy_write_auth(msieve_client, command) < 0)
+ return -1;
+ msieve_client->proxy_state = MSIEVE_PROXY_STATE_AUTH;
+ }
+
+ o_stream_nsend(output, str_data(command), str_len(command));
+ }
+ return 0;
+ case MSIEVE_PROXY_STATE_TLS_START:
+ if (strncasecmp(line, "OK", 2) == 0 &&
+ (strlen(line) == 2 || line[2] == ' ')) {
+ /* STARTTLS successful, begin TLS negotiation. */
+ if (login_proxy_starttls(client->login_proxy) < 0)
+ return -1;
+
+ msieve_client->proxy_sasl = FALSE;
+ msieve_client->proxy_xclient = FALSE;
+ msieve_client->proxy_state = MSIEVE_PROXY_STATE_TLS_READY;
+ return 1;
+ }
+
+ login_proxy_failed(client->login_proxy,
+ login_proxy_get_event(client->login_proxy),
+ LOGIN_PROXY_FAILURE_TYPE_REMOTE,
+ "Remote refused STARTTLS command");
+ return -1;
+ case MSIEVE_PROXY_STATE_TLS_READY:
+ ret = proxy_input_capability(msieve_client, line, &response);
+ if (ret < 0)
+ return -1;
+ if (ret == 0) {
+ if (response != MANAGESIEVE_RESPONSE_OK) {
+ /* STARTTLS failed */
+ const char *reason = t_strdup_printf(
+ "Remote STARTTLS failed: %s",
+ str_sanitize(line, 160));
+ login_proxy_failed(client->login_proxy,
+ login_proxy_get_event(client->login_proxy),
+ LOGIN_PROXY_FAILURE_TYPE_REMOTE, reason);
+ return -1;
+ }
+
+ command = t_str_new(128);
+ if (msieve_client->proxy_xclient) {
+ proxy_write_xclient(msieve_client, command);
+ msieve_client->proxy_state = MSIEVE_PROXY_STATE_XCLIENT;
+ } else {
+ if (proxy_write_auth(msieve_client, command) < 0)
+ return -1;
+ msieve_client->proxy_state = MSIEVE_PROXY_STATE_AUTH;
+ }
+ o_stream_nsend(output, str_data(command), str_len(command));
+ }
+ return 0;
+ case MSIEVE_PROXY_STATE_XCLIENT:
+ if (strncasecmp(line, "OK", 2) == 0 &&
+ (strlen(line) == 2 || line[2] == ' ')) {
+ command = t_str_new(128);
+ if (proxy_write_auth(msieve_client, command) < 0)
+ return -1;
+ o_stream_nsend(output, str_data(command), str_len(command));
+ msieve_client->proxy_state = MSIEVE_PROXY_STATE_AUTH;
+ return 0;
+ }
+
+ const char *reason = t_strdup_printf(
+ "Remote XCLIENT failed: %s",
+ str_sanitize(line, 160));
+ login_proxy_failed(client->login_proxy,
+ login_proxy_get_event(client->login_proxy),
+ LOGIN_PROXY_FAILURE_TYPE_REMOTE, reason);
+ return -1;
+ case MSIEVE_PROXY_STATE_AUTH:
+ /* Challenge? */
+ if (*line == '"') {
+ const char *challenge;
+
+ if (proxy_input_auth_challenge(msieve_client, line,
+ &challenge) < 0)
+ return -1;
+ command = t_str_new(128);
+ if (proxy_write_auth_response(msieve_client, challenge,
+ command) < 0)
+ return -1;
+ o_stream_nsend(output, str_data(command),
+ str_len(command));
+ return 0;
+ }
+
+ /* Check login status */
+ if (strncasecmp(line, "OK", 2) == 0 &&
+ (strlen(line) == 2 || line[2] == ' ')) {
+ string_t *str = t_str_new(128);
+
+ /* Login successful */
+
+ /* FIXME: Some SASL mechanisms cause a capability
+ response to be sent.
+ */
+
+ /* Send this line to client. */
+ str_append(str, line);
+ str_append(str, "\r\n");
+ o_stream_nsend(client->output, str_data(str),
+ str_len(str));
+
+ client_proxy_finish_destroy_client(client);
+ return 1;
+ }
+
+ /* Authentication failed */
+ bool try_later;
+ (void)managesieve_proxy_parse_auth_reply(line, &reason,
+ &try_later);
+
+ /* Login failed. Send our own failure reply so client can't
+ figure out if user exists or not just by looking at the reply
+ string.
+ */
+ enum login_proxy_failure_type failure_type;
+ if (try_later)
+ failure_type = LOGIN_PROXY_FAILURE_TYPE_AUTH_TEMPFAIL;
+ else {
+ failure_type = LOGIN_PROXY_FAILURE_TYPE_AUTH;
+ client_send_no(client, AUTH_FAILED_MSG);
+ }
+
+ login_proxy_failed(client->login_proxy,
+ login_proxy_get_event(client->login_proxy),
+ failure_type, reason);
+ return -1;
+ default:
+ /* Not supposed to happen */
+ break;
+ }
+
+ i_unreached();
+ return -1;
+}
+
+void managesieve_proxy_reset(struct client *client)
+{
+ struct managesieve_client *msieve_client =
+ (struct managesieve_client *)client;
+
+ msieve_client->proxy_starttls = FALSE;
+ msieve_client->proxy_sasl = FALSE;
+ msieve_client->proxy_xclient = FALSE;
+ msieve_client->proxy_state = MSIEVE_PROXY_STATE_NONE;
+}
+
+static void
+managesieve_proxy_send_failure_reply(struct client *client,
+ enum login_proxy_failure_type type,
+ const char *reason)
+{
+ switch (type) {
+ case LOGIN_PROXY_FAILURE_TYPE_CONNECT:
+ case LOGIN_PROXY_FAILURE_TYPE_INTERNAL:
+ case LOGIN_PROXY_FAILURE_TYPE_REMOTE:
+ case LOGIN_PROXY_FAILURE_TYPE_PROTOCOL:
+ client_send_reply_code(client, MANAGESIEVE_CMD_REPLY_NO,
+ "TRYLATER", LOGIN_PROXY_FAILURE_MSG);
+ break;
+ case LOGIN_PROXY_FAILURE_TYPE_INTERNAL_CONFIG:
+ case LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG:
+ client_send_reply_code(client, MANAGESIEVE_CMD_REPLY_NO,
+ NULL, LOGIN_PROXY_FAILURE_MSG);
+ break;
+ case LOGIN_PROXY_FAILURE_TYPE_AUTH_TEMPFAIL:
+ client_send_reply_code(client, MANAGESIEVE_CMD_REPLY_NO,
+ "TRYLATER", reason);
+ break;
+ case LOGIN_PROXY_FAILURE_TYPE_AUTH:
+ /* reply was already sent */
+ break;
+ }
+}
+
+void managesieve_proxy_failed(struct client *client,
+ enum login_proxy_failure_type type,
+ const char *reason, bool reconnecting)
+{
+ if (!reconnecting)
+ managesieve_proxy_send_failure_reply(client, type, reason);
+ client_common_proxy_failed(client, type, reason, reconnecting);
+}
+
+const char *managesieve_proxy_get_state(struct client *client)
+{
+ struct managesieve_client *msieve_client =
+ (struct managesieve_client *)client;
+
+ return managesieve_proxy_state_names[msieve_client->proxy_state];
+}
diff --git a/pigeonhole/src/managesieve-login/managesieve-proxy.h b/pigeonhole/src/managesieve-login/managesieve-proxy.h
new file mode 100644
index 0000000..946f074
--- /dev/null
+++ b/pigeonhole/src/managesieve-login/managesieve-proxy.h
@@ -0,0 +1,12 @@
+#ifndef MANAGESIEVE_PROXY_H
+#define MANAGESIEVE_PROXY_H
+
+void managesieve_proxy_reset(struct client *client);
+int managesieve_proxy_parse_line(struct client *client, const char *line);
+
+void managesieve_proxy_failed(struct client *client,
+ enum login_proxy_failure_type type,
+ const char *reason, bool reconnecting);
+const char *managesieve_proxy_get_state(struct client *client);
+
+#endif
diff --git a/pigeonhole/src/managesieve/Makefile.am b/pigeonhole/src/managesieve/Makefile.am
new file mode 100644
index 0000000..17b5790
--- /dev/null
+++ b/pigeonhole/src/managesieve/Makefile.am
@@ -0,0 +1,59 @@
+settingsdir = $(dovecot_moduledir)/settings
+
+dovecot_pkglibexec_PROGRAMS = managesieve
+
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_SERVICE_INCLUDE) \
+ -DMODULEDIR=\""$(dovecot_moduledir)"\" \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src/lib-sieve \
+ -I$(top_srcdir)/src/lib-managesieve
+
+libmanagesieve_settings_la_LDFLAGS = -module -avoid-version
+
+settings_LTLIBRARIES = \
+ libmanagesieve_settings.la
+
+libmanagesieve_settings_la_SOURCES = \
+ managesieve-settings.c
+
+libs = \
+ managesieve-settings.lo \
+ $(top_builddir)/src/lib-managesieve/libmanagesieve.la \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la
+
+managesieve_CPPFLAGS = $(AM_CPPFLAGS) $(BINARY_CFLAGS)
+managesieve_LDFLAGS = -export-dynamic $(BINARY_LDFLAGS)
+
+managesieve_LDADD = $(libs) $(LIBDOVECOT_STORAGE) $(LIBDOVECOT_LDA) $(LIBDOVECOT)
+
+managesieve_DEPENDENCIES = $(libs) $(LIBDOVECOT_STORAGE_DEPS) $(LIBDOVECOT_LDA_DEPS) $(LIBDOVECOT_DEPS)
+
+cmds = \
+ cmd-capability.c \
+ cmd-logout.c \
+ cmd-putscript.c \
+ cmd-getscript.c \
+ cmd-setactive.c \
+ cmd-deletescript.c \
+ cmd-listscripts.c \
+ cmd-havespace.c \
+ cmd-renamescript.c \
+ cmd-noop.c
+
+managesieve_SOURCES = \
+ $(cmds) \
+ managesieve-quota.c \
+ managesieve-client.c \
+ managesieve-commands.c \
+ managesieve-capabilities.c \
+ main.c
+
+noinst_HEADERS = \
+ managesieve-quota.h \
+ managesieve-client.h \
+ managesieve-commands.h \
+ managesieve-capabilities.h \
+ managesieve-settings.h \
+ managesieve-common.h
diff --git a/pigeonhole/src/managesieve/Makefile.in b/pigeonhole/src/managesieve/Makefile.in
new file mode 100644
index 0000000..d8f9faa
--- /dev/null
+++ b/pigeonhole/src/managesieve/Makefile.in
@@ -0,0 +1,1134 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+dovecot_pkglibexec_PROGRAMS = managesieve$(EXEEXT)
+subdir = src/managesieve
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(dovecot_pkglibexecdir)" \
+ "$(DESTDIR)$(settingsdir)"
+PROGRAMS = $(dovecot_pkglibexec_PROGRAMS)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+LTLIBRARIES = $(settings_LTLIBRARIES)
+libmanagesieve_settings_la_LIBADD =
+am_libmanagesieve_settings_la_OBJECTS = managesieve-settings.lo
+libmanagesieve_settings_la_OBJECTS = \
+ $(am_libmanagesieve_settings_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libmanagesieve_settings_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libmanagesieve_settings_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am__objects_1 = managesieve-cmd-capability.$(OBJEXT) \
+ managesieve-cmd-logout.$(OBJEXT) \
+ managesieve-cmd-putscript.$(OBJEXT) \
+ managesieve-cmd-getscript.$(OBJEXT) \
+ managesieve-cmd-setactive.$(OBJEXT) \
+ managesieve-cmd-deletescript.$(OBJEXT) \
+ managesieve-cmd-listscripts.$(OBJEXT) \
+ managesieve-cmd-havespace.$(OBJEXT) \
+ managesieve-cmd-renamescript.$(OBJEXT) \
+ managesieve-cmd-noop.$(OBJEXT)
+am_managesieve_OBJECTS = $(am__objects_1) \
+ managesieve-managesieve-quota.$(OBJEXT) \
+ managesieve-managesieve-client.$(OBJEXT) \
+ managesieve-managesieve-commands.$(OBJEXT) \
+ managesieve-managesieve-capabilities.$(OBJEXT) \
+ managesieve-main.$(OBJEXT)
+managesieve_OBJECTS = $(am_managesieve_OBJECTS)
+am__DEPENDENCIES_1 =
+managesieve_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(managesieve_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/managesieve-cmd-capability.Po \
+ ./$(DEPDIR)/managesieve-cmd-deletescript.Po \
+ ./$(DEPDIR)/managesieve-cmd-getscript.Po \
+ ./$(DEPDIR)/managesieve-cmd-havespace.Po \
+ ./$(DEPDIR)/managesieve-cmd-listscripts.Po \
+ ./$(DEPDIR)/managesieve-cmd-logout.Po \
+ ./$(DEPDIR)/managesieve-cmd-noop.Po \
+ ./$(DEPDIR)/managesieve-cmd-putscript.Po \
+ ./$(DEPDIR)/managesieve-cmd-renamescript.Po \
+ ./$(DEPDIR)/managesieve-cmd-setactive.Po \
+ ./$(DEPDIR)/managesieve-main.Po \
+ ./$(DEPDIR)/managesieve-managesieve-capabilities.Po \
+ ./$(DEPDIR)/managesieve-managesieve-client.Po \
+ ./$(DEPDIR)/managesieve-managesieve-commands.Po \
+ ./$(DEPDIR)/managesieve-managesieve-quota.Po \
+ ./$(DEPDIR)/managesieve-settings.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libmanagesieve_settings_la_SOURCES) $(managesieve_SOURCES)
+DIST_SOURCES = $(libmanagesieve_settings_la_SOURCES) \
+ $(managesieve_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+settingsdir = $(dovecot_moduledir)/settings
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_SERVICE_INCLUDE) \
+ -DMODULEDIR=\""$(dovecot_moduledir)"\" \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src/lib-sieve \
+ -I$(top_srcdir)/src/lib-managesieve
+
+libmanagesieve_settings_la_LDFLAGS = -module -avoid-version
+settings_LTLIBRARIES = \
+ libmanagesieve_settings.la
+
+libmanagesieve_settings_la_SOURCES = \
+ managesieve-settings.c
+
+libs = \
+ managesieve-settings.lo \
+ $(top_builddir)/src/lib-managesieve/libmanagesieve.la \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la
+
+managesieve_CPPFLAGS = $(AM_CPPFLAGS) $(BINARY_CFLAGS)
+managesieve_LDFLAGS = -export-dynamic $(BINARY_LDFLAGS)
+managesieve_LDADD = $(libs) $(LIBDOVECOT_STORAGE) $(LIBDOVECOT_LDA) $(LIBDOVECOT)
+managesieve_DEPENDENCIES = $(libs) $(LIBDOVECOT_STORAGE_DEPS) $(LIBDOVECOT_LDA_DEPS) $(LIBDOVECOT_DEPS)
+cmds = \
+ cmd-capability.c \
+ cmd-logout.c \
+ cmd-putscript.c \
+ cmd-getscript.c \
+ cmd-setactive.c \
+ cmd-deletescript.c \
+ cmd-listscripts.c \
+ cmd-havespace.c \
+ cmd-renamescript.c \
+ cmd-noop.c
+
+managesieve_SOURCES = \
+ $(cmds) \
+ managesieve-quota.c \
+ managesieve-client.c \
+ managesieve-commands.c \
+ managesieve-capabilities.c \
+ main.c
+
+noinst_HEADERS = \
+ managesieve-quota.h \
+ managesieve-client.h \
+ managesieve-commands.h \
+ managesieve-capabilities.h \
+ managesieve-settings.h \
+ managesieve-common.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/managesieve/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/managesieve/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-dovecot_pkglibexecPROGRAMS: $(dovecot_pkglibexec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(dovecot_pkglibexec_PROGRAMS)'; test -n "$(dovecot_pkglibexecdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(dovecot_pkglibexecdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(dovecot_pkglibexecdir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(dovecot_pkglibexecdir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(dovecot_pkglibexecdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-dovecot_pkglibexecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dovecot_pkglibexec_PROGRAMS)'; test -n "$(dovecot_pkglibexecdir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(dovecot_pkglibexecdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(dovecot_pkglibexecdir)" && rm -f $$files
+
+clean-dovecot_pkglibexecPROGRAMS:
+ @list='$(dovecot_pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+install-settingsLTLIBRARIES: $(settings_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(settings_LTLIBRARIES)'; test -n "$(settingsdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(settingsdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(settingsdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(settingsdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(settingsdir)"; \
+ }
+
+uninstall-settingsLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(settings_LTLIBRARIES)'; test -n "$(settingsdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(settingsdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(settingsdir)/$$f"; \
+ done
+
+clean-settingsLTLIBRARIES:
+ -test -z "$(settings_LTLIBRARIES)" || rm -f $(settings_LTLIBRARIES)
+ @list='$(settings_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libmanagesieve_settings.la: $(libmanagesieve_settings_la_OBJECTS) $(libmanagesieve_settings_la_DEPENDENCIES) $(EXTRA_libmanagesieve_settings_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libmanagesieve_settings_la_LINK) -rpath $(settingsdir) $(libmanagesieve_settings_la_OBJECTS) $(libmanagesieve_settings_la_LIBADD) $(LIBS)
+
+managesieve$(EXEEXT): $(managesieve_OBJECTS) $(managesieve_DEPENDENCIES) $(EXTRA_managesieve_DEPENDENCIES)
+ @rm -f managesieve$(EXEEXT)
+ $(AM_V_CCLD)$(managesieve_LINK) $(managesieve_OBJECTS) $(managesieve_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-cmd-capability.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-cmd-deletescript.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-cmd-getscript.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-cmd-havespace.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-cmd-listscripts.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-cmd-logout.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-cmd-noop.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-cmd-putscript.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-cmd-renamescript.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-cmd-setactive.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-managesieve-capabilities.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-managesieve-client.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-managesieve-commands.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-managesieve-quota.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/managesieve-settings.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+managesieve-cmd-capability.o: cmd-capability.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-capability.o -MD -MP -MF $(DEPDIR)/managesieve-cmd-capability.Tpo -c -o managesieve-cmd-capability.o `test -f 'cmd-capability.c' || echo '$(srcdir)/'`cmd-capability.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-capability.Tpo $(DEPDIR)/managesieve-cmd-capability.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-capability.c' object='managesieve-cmd-capability.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-capability.o `test -f 'cmd-capability.c' || echo '$(srcdir)/'`cmd-capability.c
+
+managesieve-cmd-capability.obj: cmd-capability.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-capability.obj -MD -MP -MF $(DEPDIR)/managesieve-cmd-capability.Tpo -c -o managesieve-cmd-capability.obj `if test -f 'cmd-capability.c'; then $(CYGPATH_W) 'cmd-capability.c'; else $(CYGPATH_W) '$(srcdir)/cmd-capability.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-capability.Tpo $(DEPDIR)/managesieve-cmd-capability.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-capability.c' object='managesieve-cmd-capability.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-capability.obj `if test -f 'cmd-capability.c'; then $(CYGPATH_W) 'cmd-capability.c'; else $(CYGPATH_W) '$(srcdir)/cmd-capability.c'; fi`
+
+managesieve-cmd-logout.o: cmd-logout.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-logout.o -MD -MP -MF $(DEPDIR)/managesieve-cmd-logout.Tpo -c -o managesieve-cmd-logout.o `test -f 'cmd-logout.c' || echo '$(srcdir)/'`cmd-logout.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-logout.Tpo $(DEPDIR)/managesieve-cmd-logout.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-logout.c' object='managesieve-cmd-logout.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-logout.o `test -f 'cmd-logout.c' || echo '$(srcdir)/'`cmd-logout.c
+
+managesieve-cmd-logout.obj: cmd-logout.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-logout.obj -MD -MP -MF $(DEPDIR)/managesieve-cmd-logout.Tpo -c -o managesieve-cmd-logout.obj `if test -f 'cmd-logout.c'; then $(CYGPATH_W) 'cmd-logout.c'; else $(CYGPATH_W) '$(srcdir)/cmd-logout.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-logout.Tpo $(DEPDIR)/managesieve-cmd-logout.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-logout.c' object='managesieve-cmd-logout.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-logout.obj `if test -f 'cmd-logout.c'; then $(CYGPATH_W) 'cmd-logout.c'; else $(CYGPATH_W) '$(srcdir)/cmd-logout.c'; fi`
+
+managesieve-cmd-putscript.o: cmd-putscript.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-putscript.o -MD -MP -MF $(DEPDIR)/managesieve-cmd-putscript.Tpo -c -o managesieve-cmd-putscript.o `test -f 'cmd-putscript.c' || echo '$(srcdir)/'`cmd-putscript.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-putscript.Tpo $(DEPDIR)/managesieve-cmd-putscript.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-putscript.c' object='managesieve-cmd-putscript.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-putscript.o `test -f 'cmd-putscript.c' || echo '$(srcdir)/'`cmd-putscript.c
+
+managesieve-cmd-putscript.obj: cmd-putscript.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-putscript.obj -MD -MP -MF $(DEPDIR)/managesieve-cmd-putscript.Tpo -c -o managesieve-cmd-putscript.obj `if test -f 'cmd-putscript.c'; then $(CYGPATH_W) 'cmd-putscript.c'; else $(CYGPATH_W) '$(srcdir)/cmd-putscript.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-putscript.Tpo $(DEPDIR)/managesieve-cmd-putscript.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-putscript.c' object='managesieve-cmd-putscript.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-putscript.obj `if test -f 'cmd-putscript.c'; then $(CYGPATH_W) 'cmd-putscript.c'; else $(CYGPATH_W) '$(srcdir)/cmd-putscript.c'; fi`
+
+managesieve-cmd-getscript.o: cmd-getscript.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-getscript.o -MD -MP -MF $(DEPDIR)/managesieve-cmd-getscript.Tpo -c -o managesieve-cmd-getscript.o `test -f 'cmd-getscript.c' || echo '$(srcdir)/'`cmd-getscript.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-getscript.Tpo $(DEPDIR)/managesieve-cmd-getscript.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-getscript.c' object='managesieve-cmd-getscript.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-getscript.o `test -f 'cmd-getscript.c' || echo '$(srcdir)/'`cmd-getscript.c
+
+managesieve-cmd-getscript.obj: cmd-getscript.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-getscript.obj -MD -MP -MF $(DEPDIR)/managesieve-cmd-getscript.Tpo -c -o managesieve-cmd-getscript.obj `if test -f 'cmd-getscript.c'; then $(CYGPATH_W) 'cmd-getscript.c'; else $(CYGPATH_W) '$(srcdir)/cmd-getscript.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-getscript.Tpo $(DEPDIR)/managesieve-cmd-getscript.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-getscript.c' object='managesieve-cmd-getscript.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-getscript.obj `if test -f 'cmd-getscript.c'; then $(CYGPATH_W) 'cmd-getscript.c'; else $(CYGPATH_W) '$(srcdir)/cmd-getscript.c'; fi`
+
+managesieve-cmd-setactive.o: cmd-setactive.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-setactive.o -MD -MP -MF $(DEPDIR)/managesieve-cmd-setactive.Tpo -c -o managesieve-cmd-setactive.o `test -f 'cmd-setactive.c' || echo '$(srcdir)/'`cmd-setactive.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-setactive.Tpo $(DEPDIR)/managesieve-cmd-setactive.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-setactive.c' object='managesieve-cmd-setactive.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-setactive.o `test -f 'cmd-setactive.c' || echo '$(srcdir)/'`cmd-setactive.c
+
+managesieve-cmd-setactive.obj: cmd-setactive.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-setactive.obj -MD -MP -MF $(DEPDIR)/managesieve-cmd-setactive.Tpo -c -o managesieve-cmd-setactive.obj `if test -f 'cmd-setactive.c'; then $(CYGPATH_W) 'cmd-setactive.c'; else $(CYGPATH_W) '$(srcdir)/cmd-setactive.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-setactive.Tpo $(DEPDIR)/managesieve-cmd-setactive.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-setactive.c' object='managesieve-cmd-setactive.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-setactive.obj `if test -f 'cmd-setactive.c'; then $(CYGPATH_W) 'cmd-setactive.c'; else $(CYGPATH_W) '$(srcdir)/cmd-setactive.c'; fi`
+
+managesieve-cmd-deletescript.o: cmd-deletescript.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-deletescript.o -MD -MP -MF $(DEPDIR)/managesieve-cmd-deletescript.Tpo -c -o managesieve-cmd-deletescript.o `test -f 'cmd-deletescript.c' || echo '$(srcdir)/'`cmd-deletescript.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-deletescript.Tpo $(DEPDIR)/managesieve-cmd-deletescript.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-deletescript.c' object='managesieve-cmd-deletescript.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-deletescript.o `test -f 'cmd-deletescript.c' || echo '$(srcdir)/'`cmd-deletescript.c
+
+managesieve-cmd-deletescript.obj: cmd-deletescript.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-deletescript.obj -MD -MP -MF $(DEPDIR)/managesieve-cmd-deletescript.Tpo -c -o managesieve-cmd-deletescript.obj `if test -f 'cmd-deletescript.c'; then $(CYGPATH_W) 'cmd-deletescript.c'; else $(CYGPATH_W) '$(srcdir)/cmd-deletescript.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-deletescript.Tpo $(DEPDIR)/managesieve-cmd-deletescript.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-deletescript.c' object='managesieve-cmd-deletescript.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-deletescript.obj `if test -f 'cmd-deletescript.c'; then $(CYGPATH_W) 'cmd-deletescript.c'; else $(CYGPATH_W) '$(srcdir)/cmd-deletescript.c'; fi`
+
+managesieve-cmd-listscripts.o: cmd-listscripts.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-listscripts.o -MD -MP -MF $(DEPDIR)/managesieve-cmd-listscripts.Tpo -c -o managesieve-cmd-listscripts.o `test -f 'cmd-listscripts.c' || echo '$(srcdir)/'`cmd-listscripts.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-listscripts.Tpo $(DEPDIR)/managesieve-cmd-listscripts.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-listscripts.c' object='managesieve-cmd-listscripts.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-listscripts.o `test -f 'cmd-listscripts.c' || echo '$(srcdir)/'`cmd-listscripts.c
+
+managesieve-cmd-listscripts.obj: cmd-listscripts.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-listscripts.obj -MD -MP -MF $(DEPDIR)/managesieve-cmd-listscripts.Tpo -c -o managesieve-cmd-listscripts.obj `if test -f 'cmd-listscripts.c'; then $(CYGPATH_W) 'cmd-listscripts.c'; else $(CYGPATH_W) '$(srcdir)/cmd-listscripts.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-listscripts.Tpo $(DEPDIR)/managesieve-cmd-listscripts.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-listscripts.c' object='managesieve-cmd-listscripts.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-listscripts.obj `if test -f 'cmd-listscripts.c'; then $(CYGPATH_W) 'cmd-listscripts.c'; else $(CYGPATH_W) '$(srcdir)/cmd-listscripts.c'; fi`
+
+managesieve-cmd-havespace.o: cmd-havespace.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-havespace.o -MD -MP -MF $(DEPDIR)/managesieve-cmd-havespace.Tpo -c -o managesieve-cmd-havespace.o `test -f 'cmd-havespace.c' || echo '$(srcdir)/'`cmd-havespace.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-havespace.Tpo $(DEPDIR)/managesieve-cmd-havespace.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-havespace.c' object='managesieve-cmd-havespace.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-havespace.o `test -f 'cmd-havespace.c' || echo '$(srcdir)/'`cmd-havespace.c
+
+managesieve-cmd-havespace.obj: cmd-havespace.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-havespace.obj -MD -MP -MF $(DEPDIR)/managesieve-cmd-havespace.Tpo -c -o managesieve-cmd-havespace.obj `if test -f 'cmd-havespace.c'; then $(CYGPATH_W) 'cmd-havespace.c'; else $(CYGPATH_W) '$(srcdir)/cmd-havespace.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-havespace.Tpo $(DEPDIR)/managesieve-cmd-havespace.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-havespace.c' object='managesieve-cmd-havespace.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-havespace.obj `if test -f 'cmd-havespace.c'; then $(CYGPATH_W) 'cmd-havespace.c'; else $(CYGPATH_W) '$(srcdir)/cmd-havespace.c'; fi`
+
+managesieve-cmd-renamescript.o: cmd-renamescript.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-renamescript.o -MD -MP -MF $(DEPDIR)/managesieve-cmd-renamescript.Tpo -c -o managesieve-cmd-renamescript.o `test -f 'cmd-renamescript.c' || echo '$(srcdir)/'`cmd-renamescript.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-renamescript.Tpo $(DEPDIR)/managesieve-cmd-renamescript.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-renamescript.c' object='managesieve-cmd-renamescript.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-renamescript.o `test -f 'cmd-renamescript.c' || echo '$(srcdir)/'`cmd-renamescript.c
+
+managesieve-cmd-renamescript.obj: cmd-renamescript.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-renamescript.obj -MD -MP -MF $(DEPDIR)/managesieve-cmd-renamescript.Tpo -c -o managesieve-cmd-renamescript.obj `if test -f 'cmd-renamescript.c'; then $(CYGPATH_W) 'cmd-renamescript.c'; else $(CYGPATH_W) '$(srcdir)/cmd-renamescript.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-renamescript.Tpo $(DEPDIR)/managesieve-cmd-renamescript.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-renamescript.c' object='managesieve-cmd-renamescript.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-renamescript.obj `if test -f 'cmd-renamescript.c'; then $(CYGPATH_W) 'cmd-renamescript.c'; else $(CYGPATH_W) '$(srcdir)/cmd-renamescript.c'; fi`
+
+managesieve-cmd-noop.o: cmd-noop.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-noop.o -MD -MP -MF $(DEPDIR)/managesieve-cmd-noop.Tpo -c -o managesieve-cmd-noop.o `test -f 'cmd-noop.c' || echo '$(srcdir)/'`cmd-noop.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-noop.Tpo $(DEPDIR)/managesieve-cmd-noop.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-noop.c' object='managesieve-cmd-noop.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-noop.o `test -f 'cmd-noop.c' || echo '$(srcdir)/'`cmd-noop.c
+
+managesieve-cmd-noop.obj: cmd-noop.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-cmd-noop.obj -MD -MP -MF $(DEPDIR)/managesieve-cmd-noop.Tpo -c -o managesieve-cmd-noop.obj `if test -f 'cmd-noop.c'; then $(CYGPATH_W) 'cmd-noop.c'; else $(CYGPATH_W) '$(srcdir)/cmd-noop.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-cmd-noop.Tpo $(DEPDIR)/managesieve-cmd-noop.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd-noop.c' object='managesieve-cmd-noop.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-cmd-noop.obj `if test -f 'cmd-noop.c'; then $(CYGPATH_W) 'cmd-noop.c'; else $(CYGPATH_W) '$(srcdir)/cmd-noop.c'; fi`
+
+managesieve-managesieve-quota.o: managesieve-quota.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-managesieve-quota.o -MD -MP -MF $(DEPDIR)/managesieve-managesieve-quota.Tpo -c -o managesieve-managesieve-quota.o `test -f 'managesieve-quota.c' || echo '$(srcdir)/'`managesieve-quota.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-managesieve-quota.Tpo $(DEPDIR)/managesieve-managesieve-quota.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managesieve-quota.c' object='managesieve-managesieve-quota.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-managesieve-quota.o `test -f 'managesieve-quota.c' || echo '$(srcdir)/'`managesieve-quota.c
+
+managesieve-managesieve-quota.obj: managesieve-quota.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-managesieve-quota.obj -MD -MP -MF $(DEPDIR)/managesieve-managesieve-quota.Tpo -c -o managesieve-managesieve-quota.obj `if test -f 'managesieve-quota.c'; then $(CYGPATH_W) 'managesieve-quota.c'; else $(CYGPATH_W) '$(srcdir)/managesieve-quota.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-managesieve-quota.Tpo $(DEPDIR)/managesieve-managesieve-quota.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managesieve-quota.c' object='managesieve-managesieve-quota.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-managesieve-quota.obj `if test -f 'managesieve-quota.c'; then $(CYGPATH_W) 'managesieve-quota.c'; else $(CYGPATH_W) '$(srcdir)/managesieve-quota.c'; fi`
+
+managesieve-managesieve-client.o: managesieve-client.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-managesieve-client.o -MD -MP -MF $(DEPDIR)/managesieve-managesieve-client.Tpo -c -o managesieve-managesieve-client.o `test -f 'managesieve-client.c' || echo '$(srcdir)/'`managesieve-client.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-managesieve-client.Tpo $(DEPDIR)/managesieve-managesieve-client.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managesieve-client.c' object='managesieve-managesieve-client.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-managesieve-client.o `test -f 'managesieve-client.c' || echo '$(srcdir)/'`managesieve-client.c
+
+managesieve-managesieve-client.obj: managesieve-client.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-managesieve-client.obj -MD -MP -MF $(DEPDIR)/managesieve-managesieve-client.Tpo -c -o managesieve-managesieve-client.obj `if test -f 'managesieve-client.c'; then $(CYGPATH_W) 'managesieve-client.c'; else $(CYGPATH_W) '$(srcdir)/managesieve-client.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-managesieve-client.Tpo $(DEPDIR)/managesieve-managesieve-client.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managesieve-client.c' object='managesieve-managesieve-client.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-managesieve-client.obj `if test -f 'managesieve-client.c'; then $(CYGPATH_W) 'managesieve-client.c'; else $(CYGPATH_W) '$(srcdir)/managesieve-client.c'; fi`
+
+managesieve-managesieve-commands.o: managesieve-commands.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-managesieve-commands.o -MD -MP -MF $(DEPDIR)/managesieve-managesieve-commands.Tpo -c -o managesieve-managesieve-commands.o `test -f 'managesieve-commands.c' || echo '$(srcdir)/'`managesieve-commands.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-managesieve-commands.Tpo $(DEPDIR)/managesieve-managesieve-commands.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managesieve-commands.c' object='managesieve-managesieve-commands.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-managesieve-commands.o `test -f 'managesieve-commands.c' || echo '$(srcdir)/'`managesieve-commands.c
+
+managesieve-managesieve-commands.obj: managesieve-commands.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-managesieve-commands.obj -MD -MP -MF $(DEPDIR)/managesieve-managesieve-commands.Tpo -c -o managesieve-managesieve-commands.obj `if test -f 'managesieve-commands.c'; then $(CYGPATH_W) 'managesieve-commands.c'; else $(CYGPATH_W) '$(srcdir)/managesieve-commands.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-managesieve-commands.Tpo $(DEPDIR)/managesieve-managesieve-commands.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managesieve-commands.c' object='managesieve-managesieve-commands.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-managesieve-commands.obj `if test -f 'managesieve-commands.c'; then $(CYGPATH_W) 'managesieve-commands.c'; else $(CYGPATH_W) '$(srcdir)/managesieve-commands.c'; fi`
+
+managesieve-managesieve-capabilities.o: managesieve-capabilities.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-managesieve-capabilities.o -MD -MP -MF $(DEPDIR)/managesieve-managesieve-capabilities.Tpo -c -o managesieve-managesieve-capabilities.o `test -f 'managesieve-capabilities.c' || echo '$(srcdir)/'`managesieve-capabilities.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-managesieve-capabilities.Tpo $(DEPDIR)/managesieve-managesieve-capabilities.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managesieve-capabilities.c' object='managesieve-managesieve-capabilities.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-managesieve-capabilities.o `test -f 'managesieve-capabilities.c' || echo '$(srcdir)/'`managesieve-capabilities.c
+
+managesieve-managesieve-capabilities.obj: managesieve-capabilities.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-managesieve-capabilities.obj -MD -MP -MF $(DEPDIR)/managesieve-managesieve-capabilities.Tpo -c -o managesieve-managesieve-capabilities.obj `if test -f 'managesieve-capabilities.c'; then $(CYGPATH_W) 'managesieve-capabilities.c'; else $(CYGPATH_W) '$(srcdir)/managesieve-capabilities.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-managesieve-capabilities.Tpo $(DEPDIR)/managesieve-managesieve-capabilities.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managesieve-capabilities.c' object='managesieve-managesieve-capabilities.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-managesieve-capabilities.obj `if test -f 'managesieve-capabilities.c'; then $(CYGPATH_W) 'managesieve-capabilities.c'; else $(CYGPATH_W) '$(srcdir)/managesieve-capabilities.c'; fi`
+
+managesieve-main.o: main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-main.o -MD -MP -MF $(DEPDIR)/managesieve-main.Tpo -c -o managesieve-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-main.Tpo $(DEPDIR)/managesieve-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='managesieve-main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c
+
+managesieve-main.obj: main.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT managesieve-main.obj -MD -MP -MF $(DEPDIR)/managesieve-main.Tpo -c -o managesieve-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/managesieve-main.Tpo $(DEPDIR)/managesieve-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='managesieve-main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(managesieve_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o managesieve-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(dovecot_pkglibexecdir)" "$(DESTDIR)$(settingsdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-dovecot_pkglibexecPROGRAMS clean-generic clean-libtool \
+ clean-settingsLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/managesieve-cmd-capability.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-deletescript.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-getscript.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-havespace.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-listscripts.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-logout.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-noop.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-putscript.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-renamescript.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-setactive.Po
+ -rm -f ./$(DEPDIR)/managesieve-main.Po
+ -rm -f ./$(DEPDIR)/managesieve-managesieve-capabilities.Po
+ -rm -f ./$(DEPDIR)/managesieve-managesieve-client.Po
+ -rm -f ./$(DEPDIR)/managesieve-managesieve-commands.Po
+ -rm -f ./$(DEPDIR)/managesieve-managesieve-quota.Po
+ -rm -f ./$(DEPDIR)/managesieve-settings.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-settingsLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-dovecot_pkglibexecPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/managesieve-cmd-capability.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-deletescript.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-getscript.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-havespace.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-listscripts.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-logout.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-noop.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-putscript.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-renamescript.Po
+ -rm -f ./$(DEPDIR)/managesieve-cmd-setactive.Po
+ -rm -f ./$(DEPDIR)/managesieve-main.Po
+ -rm -f ./$(DEPDIR)/managesieve-managesieve-capabilities.Po
+ -rm -f ./$(DEPDIR)/managesieve-managesieve-client.Po
+ -rm -f ./$(DEPDIR)/managesieve-managesieve-commands.Po
+ -rm -f ./$(DEPDIR)/managesieve-managesieve-quota.Po
+ -rm -f ./$(DEPDIR)/managesieve-settings.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dovecot_pkglibexecPROGRAMS \
+ uninstall-settingsLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-dovecot_pkglibexecPROGRAMS clean-generic clean-libtool \
+ clean-settingsLTLIBRARIES cscopelist-am ctags ctags-am \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dovecot_pkglibexecPROGRAMS install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-settingsLTLIBRARIES install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am \
+ uninstall-dovecot_pkglibexecPROGRAMS \
+ uninstall-settingsLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/managesieve/cmd-capability.c b/pigeonhole/src/managesieve/cmd-capability.c
new file mode 100644
index 0000000..1d26eb5
--- /dev/null
+++ b/pigeonhole/src/managesieve/cmd-capability.c
@@ -0,0 +1,76 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "strfuncs.h"
+#include "ostream.h"
+
+#include "sieve.h"
+
+#include "managesieve-common.h"
+#include "managesieve-commands.h"
+
+static void send_capability(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ const char *sievecap, *notifycap;
+ unsigned int max_redirects;
+
+ /* Get capabilities */
+ sievecap = sieve_get_capabilities(client->svinst, NULL);
+ notifycap = sieve_get_capabilities(client->svinst, "notify");
+ max_redirects = sieve_max_redirects(client->svinst);
+
+ /* Default capabilities */
+ client_send_line(client,
+ t_strconcat(
+ "\"IMPLEMENTATION\" \"",
+ client->set->managesieve_implementation_string,
+ "\"", NULL));
+ client_send_line(client,
+ t_strconcat(
+ "\"SIEVE\" \"",
+ (sievecap == NULL ? "" : sievecap),
+ "\"", NULL));
+
+ /* Maximum number of redirects (if limited) */
+ if (max_redirects > 0) {
+ client_send_line(client,
+ t_strdup_printf("\"MAXREDIRECTS\" \"%u\"",
+ max_redirects));
+ }
+
+ /* Notify methods */
+ if (notifycap != NULL) {
+ client_send_line(client,
+ t_strconcat("\"NOTIFY\" \"", notifycap, "\"",
+ NULL));
+ }
+
+ /* Protocol version */
+ client_send_line(client, "\"VERSION\" \"1.0\"");
+}
+
+bool cmd_capability(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+
+ /* no arguments */
+ if (!client_read_no_args(cmd))
+ return FALSE;
+
+ o_stream_cork(client->output);
+
+ T_BEGIN {
+ send_capability(cmd);
+ } T_END;
+
+ client_send_line(client, "OK \"Capability completed.\"");
+
+ o_stream_uncork(client->output);
+
+ return TRUE;
+
+}
+
diff --git a/pigeonhole/src/managesieve/cmd-deletescript.c b/pigeonhole/src/managesieve/cmd-deletescript.c
new file mode 100644
index 0000000..a8be5c9
--- /dev/null
+++ b/pigeonhole/src/managesieve/cmd-deletescript.c
@@ -0,0 +1,43 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+
+#include "managesieve-common.h"
+#include "managesieve-commands.h"
+
+bool cmd_deletescript(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ struct sieve_storage *storage = client->storage;
+ const char *scriptname;
+ struct sieve_script *script;
+
+ /* <script name>*/
+ if (!client_read_string_args(cmd, TRUE, 1, &scriptname))
+ return FALSE;
+
+ event_add_str(cmd->event, "script_name", scriptname);
+
+ script = sieve_storage_open_script(storage, scriptname, NULL);
+ if (script == NULL || sieve_script_delete(script, FALSE) < 0) {
+ client_command_storage_error(
+ cmd, "Failed to delete script `%s'", scriptname);
+ sieve_script_unref(&script);
+ return TRUE;
+ }
+
+ struct event_passthrough *e =
+ client_command_create_finish_event(cmd);
+ e_debug(e->event(), "Deleted script `%s'", scriptname);
+
+ client->deleted_count++;
+ client_send_ok(client, "Deletescript completed.");
+
+ sieve_script_unref(&script);
+ return TRUE;
+}
diff --git a/pigeonhole/src/managesieve/cmd-getscript.c b/pigeonhole/src/managesieve/cmd-getscript.c
new file mode 100644
index 0000000..2f0a5f9
--- /dev/null
+++ b/pigeonhole/src/managesieve/cmd-getscript.c
@@ -0,0 +1,157 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "ostream.h"
+#include "istream.h"
+#include "iostream.h"
+
+#include "sieve-script.h"
+#include "sieve-storage.h"
+
+#include "managesieve-common.h"
+#include "managesieve-commands.h"
+
+struct cmd_getscript_context {
+ struct client *client;
+ struct client_command_context *cmd;
+ struct sieve_storage *storage;
+ uoff_t script_size;
+
+ const char *scriptname;
+ struct sieve_script *script;
+ struct istream *script_stream;
+
+ bool failed:1;
+};
+
+static bool cmd_getscript_finish(struct cmd_getscript_context *ctx)
+{
+ struct client_command_context *cmd = ctx->cmd;
+ struct client *client = ctx->client;
+
+ if (ctx->script != NULL)
+ sieve_script_unref(&ctx->script);
+
+ if (ctx->failed) {
+ if (client->output->closed) {
+ client_disconnect(client, NULL);
+ return TRUE;
+ }
+
+ client_command_storage_error(
+ cmd, "Failed to retrieve script `%s'", ctx->scriptname);
+ return TRUE;
+ }
+
+ client->get_count++;
+ client->get_bytes += ctx->script_size;
+
+ struct event_passthrough *e =
+ client_command_create_finish_event(cmd);
+ e_debug(e->event(), "Retrieved script `%s'", ctx->scriptname);
+
+ client_send_line(client, "");
+ client_send_ok(client, "Getscript completed.");
+ return TRUE;
+}
+
+static bool cmd_getscript_continue(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ struct cmd_getscript_context *ctx = cmd->context;
+
+ switch (o_stream_send_istream(client->output, ctx->script_stream)) {
+ case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
+ if (ctx->script_stream->v_offset != ctx->script_size &&
+ !ctx->failed) {
+ /* Input stream gave less data than expected */
+ sieve_storage_set_critical(
+ ctx->storage, "GETSCRIPT for script `%s' "
+ "from %s got too little data: "
+ "%"PRIuUOFF_T" vs %"PRIuUOFF_T,
+ sieve_script_name(ctx->script),
+ sieve_script_location(ctx->script),
+ ctx->script_stream->v_offset, ctx->script_size);
+ client_disconnect(ctx->client, "GETSCRIPT failed");
+ ctx->failed = TRUE;
+ }
+ break;
+ case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
+ i_unreached();
+ case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
+ return FALSE;
+ case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
+ sieve_storage_set_critical(ctx->storage,
+ "o_stream_send_istream() failed for script `%s' "
+ "from %s: %s",
+ sieve_script_name(ctx->script),
+ sieve_script_location(ctx->script),
+ i_stream_get_error(ctx->script_stream));
+ ctx->failed = TRUE;
+ break;
+ case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
+ client_disconnect(ctx->client, NULL);
+ ctx->failed = TRUE;
+ break;
+ }
+ return cmd_getscript_finish(ctx);
+}
+
+bool cmd_getscript(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ struct cmd_getscript_context *ctx;
+ const char *scriptname;
+ enum sieve_error error;
+
+ /* <scriptname> */
+ if (!client_read_string_args(cmd, TRUE, 1, &scriptname))
+ return FALSE;
+
+ event_add_str(cmd->event, "script_name", scriptname);
+
+ ctx = p_new(cmd->pool, struct cmd_getscript_context, 1);
+ ctx->cmd = cmd;
+ ctx->client = client;
+ ctx->scriptname = p_strdup(cmd->pool, scriptname);
+ ctx->storage = client->storage;
+ ctx->failed = FALSE;
+
+ ctx->script = sieve_storage_open_script(client->storage, scriptname,
+ NULL);
+ if (ctx->script == NULL) {
+ ctx->failed = TRUE;
+ return cmd_getscript_finish(ctx);
+ }
+
+ if (sieve_script_get_stream(ctx->script, &ctx->script_stream,
+ &error) < 0 ) {
+ if (error == SIEVE_ERROR_NOT_FOUND) {
+ sieve_storage_set_error(client->storage, error,
+ "Script does not exist.");
+ }
+ ctx->failed = TRUE;
+ return cmd_getscript_finish(ctx);
+ }
+
+ if (sieve_script_get_size(ctx->script, &ctx->script_size) <= 0) {
+ sieve_storage_set_critical(ctx->storage,
+ "failed to obtain script size for script `%s' from %s",
+ sieve_script_name(ctx->script),
+ sieve_script_location(ctx->script));
+ ctx->failed = TRUE;
+ return cmd_getscript_finish(ctx);
+ }
+
+ i_assert(ctx->script_stream->v_offset == 0);
+
+ client_send_line(client, t_strdup_printf("{%"PRIuUOFF_T"}",
+ ctx->script_size));
+
+ client->command_pending = TRUE;
+ cmd->func = cmd_getscript_continue;
+ cmd->context = ctx;
+
+ return cmd_getscript_continue(cmd);
+}
diff --git a/pigeonhole/src/managesieve/cmd-havespace.c b/pigeonhole/src/managesieve/cmd-havespace.c
new file mode 100644
index 0000000..5af2bb1
--- /dev/null
+++ b/pigeonhole/src/managesieve/cmd-havespace.c
@@ -0,0 +1,60 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "managesieve-common.h"
+#include "managesieve-commands.h"
+
+#include "sieve.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+
+#include "managesieve-client.h"
+#include "managesieve-quota.h"
+
+bool cmd_havespace(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ const struct managesieve_arg *args;
+ const char *scriptname;
+ uoff_t size;
+
+ /* <scriptname> <size> */
+ if (!client_read_args(cmd, 2, 0, TRUE, &args))
+ return FALSE;
+
+ if (!managesieve_arg_get_string(&args[0], &scriptname)) {
+ client_send_no(client, "Invalid string for scriptname.");
+ return TRUE;
+ }
+
+ if (!managesieve_arg_get_number(&args[1], &size)) {
+ client_send_no(client, "Invalid scriptsize argument.");
+ return TRUE;
+ }
+
+ if (!sieve_script_name_is_valid(scriptname)) {
+ client_send_no(client, "Invalid script name.");
+ return TRUE;
+ }
+
+ if (size == 0) {
+ client_send_no(client, "Cannot upload empty script.");
+ return TRUE;
+ }
+
+ event_add_str(cmd->event, "script_name", scriptname);
+ event_add_int(cmd->event, "script_size", size);
+
+ if (!managesieve_quota_check_all(cmd, scriptname, size))
+ return TRUE;
+
+ struct event_passthrough *e =
+ client_command_create_finish_event(cmd);
+ e_debug(e->event(), "Quota is within limits for script `%s' "
+ "with size %"PRIuUOFF_T, scriptname, size);
+
+ client_send_ok(client, "Putscript would succeed.");
+ return TRUE;
+}
diff --git a/pigeonhole/src/managesieve/cmd-listscripts.c b/pigeonhole/src/managesieve/cmd-listscripts.c
new file mode 100644
index 0000000..9e6abd2
--- /dev/null
+++ b/pigeonhole/src/managesieve/cmd-listscripts.c
@@ -0,0 +1,65 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve.h"
+#include "sieve-storage.h"
+
+#include "managesieve-quote.h"
+
+#include "managesieve-common.h"
+#include "managesieve-commands.h"
+
+bool cmd_listscripts(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ struct sieve_storage_list_context *ctx;
+ const char *scriptname;
+ unsigned int script_count = 0;
+ bool active;
+ string_t *str;
+
+ /* no arguments */
+ if (!client_read_no_args(cmd))
+ return FALSE;
+
+ if ((ctx = sieve_storage_list_init(client->storage)) == NULL) {
+ client_command_storage_error(
+ cmd, "Failed to list scripts");
+ return TRUE;
+ }
+
+ /* FIXME: This will be quite slow for large script lists. Implement
+ * some buffering to fix this. Wont truely be an issue with managesieve
+ * though.
+ */
+ while ((scriptname = sieve_storage_list_next(ctx, &active)) != NULL) {
+ T_BEGIN {
+ str = t_str_new(128);
+
+ managesieve_quote_append_string(str, scriptname, FALSE);
+
+ if (active)
+ str_append(str, " ACTIVE");
+
+ client_send_line(client, str_c(str));
+ } T_END;
+
+ script_count++;
+ }
+
+ if (sieve_storage_list_deinit(&ctx) < 0) {
+ client_command_storage_error(
+ cmd, "Failed to list scripts");
+ return TRUE;
+ }
+
+ struct event_passthrough *e =
+ client_command_create_finish_event(cmd);
+ e_debug(e->event(), "Listed %u scripts", script_count);
+
+ client_send_ok(client, "Listscripts completed.");
+ return TRUE;
+}
diff --git a/pigeonhole/src/managesieve/cmd-logout.c b/pigeonhole/src/managesieve/cmd-logout.c
new file mode 100644
index 0000000..9e0847d
--- /dev/null
+++ b/pigeonhole/src/managesieve/cmd-logout.c
@@ -0,0 +1,21 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "ostream.h"
+
+#include "managesieve-common.h"
+#include "managesieve-commands.h"
+
+bool cmd_logout(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+
+ /* no arguments */
+ if (!client_read_no_args(cmd))
+ return FALSE;
+
+ client_send_line(client, "OK \"Logout completed.\"");
+ client_disconnect(client, "Logged out");
+ return TRUE;
+}
diff --git a/pigeonhole/src/managesieve/cmd-noop.c b/pigeonhole/src/managesieve/cmd-noop.c
new file mode 100644
index 0000000..76d96c3
--- /dev/null
+++ b/pigeonhole/src/managesieve/cmd-noop.c
@@ -0,0 +1,46 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+
+#include "managesieve-quote.h"
+
+#include "managesieve-common.h"
+#include "managesieve-commands.h"
+
+
+bool cmd_noop(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ const struct managesieve_arg *args;
+ const char *text;
+ string_t *resp_code;
+
+ /* [<echo string>] */
+ if (!client_read_args(cmd, 0, 0, FALSE, &args))
+ return FALSE;
+
+ if (MANAGESIEVE_ARG_IS_EOL(&args[0])) {
+ client_send_ok(client, "NOOP Completed");
+ return TRUE;
+ }
+
+ if (!managesieve_arg_get_string(&args[0], &text)) {
+ client_send_no(client, "Invalid echo tag.");
+ return TRUE;
+ }
+
+ if (!MANAGESIEVE_ARG_IS_EOL(&args[1])) {
+ client_send_command_error(cmd, "Too many arguments.");
+ return TRUE;
+ }
+
+ resp_code = t_str_new(256);
+ str_append(resp_code, "TAG ");
+ managesieve_quote_append_string(resp_code, text, FALSE);
+
+ client_send_okresp(client, str_c(resp_code), "Done");
+ return TRUE;
+}
+
diff --git a/pigeonhole/src/managesieve/cmd-putscript.c b/pigeonhole/src/managesieve/cmd-putscript.c
new file mode 100644
index 0000000..1998cd9
--- /dev/null
+++ b/pigeonhole/src/managesieve/cmd-putscript.c
@@ -0,0 +1,578 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* NOTE: this file also contains the checkscript command due to its obvious
+ * similarities.
+ */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "istream.h"
+#include "ostream.h"
+#include "iostream.h"
+#include "str.h"
+
+#include "sieve.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+
+#include "managesieve-parser.h"
+
+#include "managesieve-common.h"
+#include "managesieve-client.h"
+#include "managesieve-commands.h"
+#include "managesieve-quota.h"
+
+#include <sys/time.h>
+
+struct cmd_putscript_context {
+ struct client *client;
+ struct client_command_context *cmd;
+ struct sieve_storage *storage;
+
+ struct istream *input;
+
+ const char *scriptname;
+ uoff_t script_size, max_script_size;
+
+ struct managesieve_parser *save_parser;
+ struct sieve_storage_save_context *save_ctx;
+
+ bool script_size_valid:1;
+};
+
+static void cmd_putscript_finish(struct cmd_putscript_context *ctx);
+static bool cmd_putscript_continue_script(struct client_command_context *cmd);
+
+static void client_input_putscript(struct client *client)
+{
+ struct client_command_context *cmd = &client->cmd;
+
+ i_assert(!client->destroyed);
+
+ client->last_input = ioloop_time;
+ timeout_reset(client->to_idle);
+
+ switch (i_stream_read(client->input)) {
+ case -1:
+ /* disconnected */
+ cmd_putscript_finish(cmd->context);
+ /* Reset command so that client_destroy() doesn't try to call
+ cmd_putscript_continue_script() anymore. */
+ _client_reset_command(client);
+ client_destroy(client, "Disconnected in PUTSCRIPT/CHECKSCRIPT");
+ return;
+ case -2:
+ cmd_putscript_finish(cmd->context);
+ if (client->command_pending) {
+ /* uploaded script data, this is handled internally by
+ mailbox_save_continue() */
+ break;
+ }
+
+ /* parameter word is longer than max. input buffer size.
+ this is most likely an error, so skip the new data
+ until newline is found. */
+ client->input_skip_line = TRUE;
+
+ client_send_command_error(cmd, "Too long argument.");
+ cmd->param_error = TRUE;
+ _client_reset_command(client);
+ return;
+ }
+
+ if (cmd->func(cmd)) {
+ /* command execution was finished. Note that if cmd_sync()
+ didn't finish, we didn't get here but the input handler
+ has already been moved. So don't do anything important
+ here..
+
+ reset command once again to reset cmd_sync()'s changes. */
+ _client_reset_command(client);
+
+ if (client->input_pending)
+ client_input(client);
+ }
+}
+
+static void cmd_putscript_finish(struct cmd_putscript_context *ctx)
+{
+ managesieve_parser_destroy(&ctx->save_parser);
+
+ io_remove(&ctx->client->io);
+ o_stream_set_flush_callback(ctx->client->output,
+ client_output, ctx->client);
+
+ if (ctx->save_ctx != NULL) {
+ ctx->client->input_skip_line = TRUE;
+ sieve_storage_save_cancel(&ctx->save_ctx);
+ }
+}
+
+static bool cmd_putscript_continue_cancel(struct client_command_context *cmd)
+{
+ struct cmd_putscript_context *ctx = cmd->context;
+ size_t size;
+
+ (void)i_stream_read(ctx->input);
+ (void)i_stream_get_data(ctx->input, &size);
+ i_stream_skip(ctx->input, size);
+
+ if (cmd->client->input->closed || ctx->input->eof ||
+ ctx->input->v_offset == ctx->script_size) {
+ cmd_putscript_finish(ctx);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static bool cmd_putscript_cancel(struct cmd_putscript_context *ctx, bool skip)
+{
+ ctx->client->input_skip_line = TRUE;
+
+ if (!skip) {
+ cmd_putscript_finish(ctx);
+ return TRUE;
+ }
+
+ /* we have to read the nonsynced literal so we don't treat the uploaded
+ script as commands. */
+ ctx->client->command_pending = TRUE;
+ ctx->cmd->func = cmd_putscript_continue_cancel;
+ ctx->cmd->context = ctx;
+ return cmd_putscript_continue_cancel(ctx->cmd);
+}
+
+static void cmd_putscript_storage_error(struct cmd_putscript_context *ctx)
+{
+ struct client_command_context *cmd = ctx->cmd;
+
+ if (ctx->scriptname == NULL) {
+ client_command_storage_error(cmd, "Failed to check script");
+ } else {
+ client_command_storage_error(cmd, "Failed to store script `%s'",
+ ctx->scriptname);
+ }
+}
+
+static bool cmd_putscript_save(struct cmd_putscript_context *ctx)
+{
+ /* Commit to save only when this is a putscript command */
+ if (ctx->scriptname == NULL)
+ return TRUE;
+
+ /* Check commit */
+ if (sieve_storage_save_commit(&ctx->save_ctx) < 0) {
+ cmd_putscript_storage_error(ctx);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+cmd_putscript_finish_script(struct cmd_putscript_context *ctx,
+ struct sieve_script *script)
+{
+ struct client *client = ctx->client;
+ struct client_command_context *cmd = ctx->cmd;
+ struct sieve_error_handler *ehandler;
+ enum sieve_compile_flags cpflags =
+ SIEVE_COMPILE_FLAG_NOGLOBAL | SIEVE_COMPILE_FLAG_UPLOADED;
+ struct sieve_binary *sbin;
+ bool success = TRUE;
+ enum sieve_error error;
+ string_t *errors;
+
+ /* Mark this as an activation when we are replacing the
+ active script */
+ if (sieve_storage_save_will_activate(ctx->save_ctx))
+ cpflags |= SIEVE_COMPILE_FLAG_ACTIVATED;
+
+ /* Prepare error handler */
+ errors = str_new(default_pool, 1024);
+ ehandler = sieve_strbuf_ehandler_create(
+ client->svinst, errors, TRUE,
+ client->set->managesieve_max_compile_errors);
+
+ /* Compile */
+ sbin = sieve_compile_script(script, ehandler, cpflags, &error);
+ if (sbin == NULL) {
+ const char *errormsg = NULL, *action;
+
+ if (error != SIEVE_ERROR_NOT_VALID) {
+ errormsg = sieve_script_get_last_error(script, &error);
+ if (error == SIEVE_ERROR_NONE)
+ errormsg = NULL;
+ }
+
+ action = (ctx->scriptname != NULL ?
+ t_strdup_printf("store script `%s'",
+ ctx->scriptname) :
+ "check script");
+
+ if (errormsg == NULL) {
+ struct event_passthrough *e =
+ client_command_create_finish_event(cmd)->
+ add_str("error", "Compilation failed")->
+ add_int("compile_errors",
+ sieve_get_errors(ehandler))->
+ add_int("compile_warnings",
+ sieve_get_warnings(ehandler));
+ e_debug(e->event(), "Failed to %s: "
+ "Compilation failed (%u errors, %u warnings)",
+ action, sieve_get_errors(ehandler),
+ sieve_get_warnings(ehandler));
+
+ client_send_no(client, str_c(errors));
+ } else {
+ struct event_passthrough *e =
+ client_command_create_finish_event(cmd)->
+ add_str("error", errormsg);
+ e_debug(e->event(), "Failed to %s: %s",
+ action, errormsg);
+
+ client_send_no(client, errormsg);
+ }
+
+ success = FALSE;
+ } else {
+ sieve_close(&sbin);
+
+ if (!cmd_putscript_save(ctx))
+ success = FALSE;
+ }
+
+ /* Finish up */
+ cmd_putscript_finish(ctx);
+
+ /* Report result to user */
+ if (success) {
+ if (ctx->scriptname != NULL) {
+ client->put_count++;
+ client->put_bytes += ctx->script_size;
+ } else {
+ client->check_count++;
+ client->check_bytes += ctx->script_size;
+ }
+
+ struct event_passthrough *e =
+ client_command_create_finish_event(cmd)->
+ add_int("compile_warnings",
+ sieve_get_warnings(ehandler));
+ if (ctx->scriptname != NULL) {
+ e_debug(e->event(), "Stored script `%s' successfully "
+ "(%u warnings)", ctx->scriptname,
+ sieve_get_warnings(ehandler));
+ } else {
+ e_debug(e->event(), "Checked script successfully "
+ "(%u warnings)", sieve_get_warnings(ehandler));
+ }
+
+ if (sieve_get_warnings(ehandler) > 0)
+ client_send_okresp(client, "WARNINGS", str_c(errors));
+ else if (ctx->scriptname != NULL)
+ client_send_ok(client, "PUTSCRIPT completed.");
+ else
+ client_send_ok(client, "Script checked successfully.");
+ }
+
+ sieve_error_handler_unref(&ehandler);
+ str_free(&errors);
+}
+
+static void cmd_putscript_handle_script(struct cmd_putscript_context *ctx)
+{
+ struct client_command_context *cmd = ctx->cmd;
+ struct sieve_script *script;
+
+ /* Obtain script object for uploaded script */
+ script = sieve_storage_save_get_tempscript(ctx->save_ctx);
+
+ /* Check result */
+ if (script == NULL) {
+ cmd_putscript_storage_error(ctx);
+ cmd_putscript_finish(ctx);
+ return;
+ }
+
+ /* If quoted string, the size was not known until now */
+ if (!ctx->script_size_valid) {
+ if (sieve_script_get_size(script, &ctx->script_size) < 0) {
+ cmd_putscript_storage_error(ctx);
+ cmd_putscript_finish(ctx);
+ return;
+ }
+ ctx->script_size_valid = TRUE;
+
+ /* Check quota; max size is already checked */
+ if (ctx->scriptname != NULL &&
+ !managesieve_quota_check_all(cmd, ctx->scriptname,
+ ctx->script_size)) {
+ cmd_putscript_finish(ctx);
+ return;
+ }
+ }
+
+ /* Try to compile and store the script */
+ T_BEGIN {
+ cmd_putscript_finish_script(ctx, script);
+ } T_END;
+}
+
+static bool cmd_putscript_finish_parsing(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ struct cmd_putscript_context *ctx = cmd->context;
+ const struct managesieve_arg *args;
+ int ret;
+
+ /* if error occurs, the CRLF is already read. */
+ client->input_skip_line = FALSE;
+
+ /* <script literal> */
+ ret = managesieve_parser_read_args(ctx->save_parser, 0, 0, &args);
+ if (ret == -1 || client->output->closed) {
+ if (ctx->storage != NULL) {
+ const char *msg;
+ bool fatal ATTR_UNUSED;
+
+ msg = managesieve_parser_get_error(
+ ctx->save_parser, &fatal);
+ client_send_command_error(cmd, msg);
+ }
+ cmd_putscript_finish(ctx);
+ return TRUE;
+ }
+ if (ret < 0) {
+ /* need more data */
+ return FALSE;
+ }
+
+ if (MANAGESIEVE_ARG_IS_EOL(&args[0])) {
+ /* Eat away the trailing CRLF */
+ client->input_skip_line = TRUE;
+
+ cmd_putscript_handle_script(ctx);
+ return TRUE;
+ }
+
+ client_send_command_error(cmd, "Too many command arguments.");
+ cmd_putscript_finish(ctx);
+ return TRUE;
+}
+
+static bool cmd_putscript_continue_parsing(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ struct cmd_putscript_context *ctx = cmd->context;
+ const struct managesieve_arg *args;
+ int ret;
+
+ /* if error occurs, the CRLF is already read. */
+ client->input_skip_line = FALSE;
+
+ /* <script literal> */
+ ret = managesieve_parser_read_args(
+ ctx->save_parser, 0, MANAGESIEVE_PARSE_FLAG_STRING_STREAM,
+ &args);
+ if (ret == -1 || client->output->closed) {
+ cmd_putscript_finish(ctx);
+ client_send_command_error(cmd, "Invalid arguments.");
+ client->input_skip_line = TRUE;
+ return TRUE;
+ }
+ if (ret < 0) {
+ /* need more data */
+ return FALSE;
+ }
+
+ /* Validate the script argument */
+ if (!managesieve_arg_get_string_stream(args,&ctx->input)) {
+ client_send_command_error(cmd, "Invalid arguments.");
+ return cmd_putscript_cancel(ctx, FALSE);
+ }
+
+ if (i_stream_get_size(ctx->input, FALSE, &ctx->script_size) > 0) {
+ ctx->script_size_valid = TRUE;
+
+ /* Check quota */
+ if (ctx->scriptname == NULL) {
+ if (!managesieve_quota_check_validsize(
+ cmd, ctx->script_size))
+ return cmd_putscript_cancel(ctx, TRUE);
+ } else {
+ if (!managesieve_quota_check_all(
+ cmd, ctx->scriptname, ctx->script_size))
+ return cmd_putscript_cancel(ctx, TRUE);
+ }
+
+ } else {
+ ctx->max_script_size =
+ managesieve_quota_max_script_size(client);
+ }
+
+ /* save the script */
+ ctx->save_ctx = sieve_storage_save_init(ctx->storage, ctx->scriptname,
+ ctx->input);
+
+ if (ctx->save_ctx == NULL) {
+ /* save initialization failed */
+ cmd_putscript_storage_error(ctx);
+ return cmd_putscript_cancel(ctx, TRUE);
+ }
+
+ /* after literal comes CRLF, if we fail make sure we eat it away */
+ client->input_skip_line = TRUE;
+
+ client->command_pending = TRUE;
+ cmd->func = cmd_putscript_continue_script;
+ return cmd_putscript_continue_script(cmd);
+}
+
+static bool cmd_putscript_continue_script(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ struct cmd_putscript_context *ctx = cmd->context;
+ size_t size;
+ int ret;
+
+ if (ctx->save_ctx != NULL) {
+ for (;;) {
+ i_assert(!ctx->script_size_valid ||
+ ctx->input->v_offset <= ctx->script_size);
+ if (ctx->max_script_size > 0 &&
+ ctx->input->v_offset > ctx->max_script_size) {
+ (void)managesieve_quota_check_validsize(
+ cmd, ctx->input->v_offset);
+ cmd_putscript_finish(ctx);
+ return TRUE;
+ }
+
+ ret = i_stream_read(ctx->input);
+ if ((ret != -1 || ctx->input->stream_errno != EINVAL ||
+ client->input->eof) &&
+ sieve_storage_save_continue(ctx->save_ctx) < 0) {
+ /* we still have to finish reading the script
+ from client */
+ sieve_storage_save_cancel(&ctx->save_ctx);
+ break;
+ }
+ if (ret == -1 || ret == 0)
+ break;
+ }
+ }
+
+ if (ctx->save_ctx == NULL) {
+ (void)i_stream_read(ctx->input);
+ (void)i_stream_get_data(ctx->input, &size);
+ i_stream_skip(ctx->input, size);
+ }
+
+ if (ctx->input->eof || client->input->closed) {
+ bool failed = FALSE;
+ bool all_written = FALSE;
+
+ if (!ctx->script_size_valid) {
+ if (!client->input->eof &&
+ ctx->input->stream_errno == EINVAL) {
+ client_send_command_error(
+ cmd, t_strdup_printf(
+ "Invalid input: %s",
+ i_stream_get_error(ctx->input)));
+ client->input_skip_line = TRUE;
+ failed = TRUE;
+ }
+ all_written = (ctx->input->eof &&
+ ctx->input->stream_errno == 0);
+
+ } else {
+ all_written = (ctx->input->v_offset == ctx->script_size);
+ }
+
+ /* finished */
+ ctx->input = NULL;
+
+ if (!failed) {
+ if (ctx->save_ctx == NULL) {
+ /* failed above */
+ cmd_putscript_storage_error(ctx);
+ failed = TRUE;
+ } else if (!all_written) {
+ /* client disconnected before it finished sending the
+ whole script. */
+ failed = TRUE;
+ sieve_storage_save_cancel(&ctx->save_ctx);
+ const char *reason = t_strdup_printf(
+ "%s (While appending in PUTSCRIPT/CHECKSCRIPT)",
+ io_stream_get_disconnect_reason(client->input,
+ client->output));
+ client_disconnect(client, reason);
+ } else if (sieve_storage_save_finish(ctx->save_ctx) < 0) {
+ failed = TRUE;
+ cmd_putscript_storage_error(ctx);
+ } else {
+ failed = client->input->closed;
+ }
+ }
+
+ if (failed) {
+ cmd_putscript_finish(ctx);
+ return TRUE;
+ }
+
+ /* finish */
+ client->command_pending = FALSE;
+ managesieve_parser_reset(ctx->save_parser);
+ cmd->func = cmd_putscript_finish_parsing;
+ return cmd_putscript_finish_parsing(cmd);
+ }
+
+ return FALSE;
+}
+
+static bool
+cmd_putscript_start(struct client_command_context *cmd, const char *scriptname)
+{
+ struct cmd_putscript_context *ctx;
+ struct client *client = cmd->client;
+
+ ctx = p_new(cmd->pool, struct cmd_putscript_context, 1);
+ ctx->cmd = cmd;
+ ctx->client = client;
+ ctx->storage = client->storage;
+ ctx->scriptname = scriptname;
+
+ io_remove(&client->io);
+ client->io = io_add(i_stream_get_fd(client->input), IO_READ,
+ client_input_putscript, client);
+ /* putscript is special because we're only waiting on client input, not
+ client output, so disable the standard output handler until we're
+ finished */
+ o_stream_unset_flush_callback(client->output);
+
+ ctx->save_parser = managesieve_parser_create(
+ client->input, client->set->managesieve_max_line_length);
+
+ cmd->func = cmd_putscript_continue_parsing;
+ cmd->context = ctx;
+ return cmd_putscript_continue_parsing(cmd);
+
+}
+
+bool cmd_putscript(struct client_command_context *cmd)
+{
+ const char *scriptname;
+
+ /* <scriptname> */
+ if (!client_read_string_args(cmd, FALSE, 1, &scriptname))
+ return FALSE;
+
+ event_add_str(cmd->event, "script_name", scriptname);
+
+ return cmd_putscript_start(cmd, scriptname);
+}
+
+bool cmd_checkscript(struct client_command_context *cmd)
+{
+ return cmd_putscript_start(cmd, NULL);
+}
diff --git a/pigeonhole/src/managesieve/cmd-renamescript.c b/pigeonhole/src/managesieve/cmd-renamescript.c
new file mode 100644
index 0000000..bc7a99d
--- /dev/null
+++ b/pigeonhole/src/managesieve/cmd-renamescript.c
@@ -0,0 +1,54 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+
+#include "managesieve-common.h"
+#include "managesieve-commands.h"
+
+bool cmd_renamescript(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ struct sieve_storage *storage = client->storage;
+ const char *scriptname, *newname;
+ struct sieve_script *script;
+
+ /* <oldname> <newname> */
+ if (!client_read_string_args(cmd, TRUE, 2, &scriptname, &newname))
+ return FALSE;
+
+ event_add_str(cmd->event, "old_script_name", scriptname);
+ event_add_str(cmd->event, "new_script_name", newname);
+
+ script = sieve_storage_open_script(storage, scriptname, NULL);
+ if (script == NULL) {
+ client_command_storage_error(
+ cmd, "Failed to open script `%s' for rename to `%s'",
+ scriptname, newname);
+ return TRUE;
+ }
+
+ if (sieve_script_rename(script, newname) < 0) {
+ client_command_storage_error(
+ cmd, "Failed to rename script `%s' to `%s'",
+ scriptname, newname);
+ } else {
+ client->renamed_count++;
+
+ struct event_passthrough *e =
+ client_command_create_finish_event(cmd);
+ e_debug(e->event(), "Renamed script `%s' to `%s'",
+ scriptname, newname);
+
+ client_send_ok(client, "Renamescript completed.");
+ }
+
+ sieve_script_unref(&script);
+ return TRUE;
+}
+
diff --git a/pigeonhole/src/managesieve/cmd-setactive.c b/pigeonhole/src/managesieve/cmd-setactive.c
new file mode 100644
index 0000000..07844c5
--- /dev/null
+++ b/pigeonhole/src/managesieve/cmd-setactive.c
@@ -0,0 +1,165 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+
+#include "sieve.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+
+#include "managesieve-common.h"
+#include "managesieve-commands.h"
+
+static void
+cmd_setactive_activate(struct client_command_context *cmd,
+ const char *scriptname)
+{
+ struct client *client = cmd->client;
+ struct sieve_storage *storage = client->storage;
+ struct sieve_script *script;
+ string_t *errors = NULL;
+ const char *errormsg = NULL;
+ unsigned int warning_count = 0, error_count = 0;
+ bool success = TRUE;
+ int ret;
+
+ event_add_str(cmd->event, "script_name", scriptname);
+
+ script = sieve_storage_open_script(storage, scriptname, NULL);
+ if (script == NULL) {
+ client_command_storage_error(
+ cmd, "Failed to open script `%s' for activation",
+ scriptname);
+ return;
+ }
+
+ if (sieve_script_is_active(script) <= 0) T_BEGIN {
+ /* Script is first being activated; compile it again without the
+ UPLOAD flag. */
+ struct sieve_error_handler *ehandler;
+ enum sieve_compile_flags cpflags =
+ SIEVE_COMPILE_FLAG_NOGLOBAL |
+ SIEVE_COMPILE_FLAG_ACTIVATED;
+ struct sieve_binary *sbin;
+ enum sieve_error error;
+
+ /* Prepare error handler */
+ errors = str_new(default_pool, 1024);
+ ehandler = sieve_strbuf_ehandler_create(
+ client->svinst, errors, TRUE,
+ client->set->managesieve_max_compile_errors);
+
+ /* Compile */
+ sbin = sieve_compile_script(script, ehandler, cpflags, &error);
+ if (sbin == NULL) {
+ if (error != SIEVE_ERROR_NOT_VALID) {
+ errormsg = sieve_script_get_last_error(
+ script, &error);
+ if (error == SIEVE_ERROR_NONE)
+ errormsg = NULL;
+ }
+ success = FALSE;
+ } else {
+ sieve_close(&sbin);
+ }
+
+ warning_count = sieve_get_warnings(ehandler);
+ error_count = sieve_get_errors(ehandler);
+ sieve_error_handler_unref(&ehandler);
+ } T_END;
+
+ /* Activate only when script is valid (or already active) */
+ if (success) {
+ /* Refresh activation no matter what; this can also
+ resolve some erroneous situations. */
+ ret = sieve_script_activate(script, (time_t)-1);
+ if (ret < 0) {
+ client_command_storage_error(
+ cmd, "Failed to activate script `%s'",
+ scriptname);
+ } else {
+ struct event_passthrough *e =
+ client_command_create_finish_event(cmd)->
+ add_int("compile_warnings", warning_count);
+ e_debug(e->event(), "Activated script `%s' "
+ " (%u warnings%s)",
+ scriptname, warning_count,
+ (ret == 0 ? ", redundant" : ""));
+
+ if (warning_count > 0) {
+ client_send_okresp(
+ client, "WARNINGS",
+ str_c(errors));
+ } else {
+ client_send_ok(client,
+ (ret > 0 ?
+ "Setactive completed." :
+ "Script is already active."));
+ }
+ }
+ } else if (errormsg == NULL) {
+ struct event_passthrough *e =
+ client_command_create_finish_event(cmd)->
+ add_str("error", "Compilation failed")->
+ add_int("compile_errors", error_count)->
+ add_int("compile_warnings", warning_count);
+ e_debug(e->event(), "Failed to activate script `%s': "
+ "Compilation failed (%u errors, %u warnings)",
+ scriptname, error_count, warning_count);
+
+ client_send_no(client, str_c(errors));
+ } else {
+ struct event_passthrough *e =
+ client_command_create_finish_event(cmd)->
+ add_str("error", errormsg);
+ e_debug(e->event(), "Failed to activate script `%s': %s",
+ scriptname, errormsg);
+
+ client_send_no(client, errormsg);
+ }
+
+ if (errors != NULL)
+ str_free(&errors);
+ sieve_script_unref(&script);
+}
+
+static void
+cmd_setactive_deactivate(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ struct sieve_storage *storage = client->storage;
+ int ret;
+
+ ret = sieve_storage_deactivate(storage, (time_t)-1);
+ if (ret < 0) {
+ client_command_storage_error(
+ cmd, "Failed to deactivate script");
+ return;
+ }
+
+ struct event_passthrough *e =
+ client_command_create_finish_event(cmd);
+ e_debug(e->event(), "Deactivated script");
+
+ client_send_ok(client, (ret > 0 ?
+ "Active script is now deactivated." :
+ "No scripts currently active."));
+}
+
+bool cmd_setactive(struct client_command_context *cmd)
+{
+ const char *scriptname;
+
+ /* <scriptname> */
+ if (!client_read_string_args(cmd, TRUE, 1, &scriptname))
+ return FALSE;
+
+ /* Activate, or deactivate */
+ if (*scriptname != '\0')
+ cmd_setactive_activate(cmd, scriptname);
+ else
+ cmd_setactive_deactivate(cmd);
+
+ return TRUE;
+}
diff --git a/pigeonhole/src/managesieve/main.c b/pigeonhole/src/managesieve/main.c
new file mode 100644
index 0000000..321ebe3
--- /dev/null
+++ b/pigeonhole/src/managesieve/main.c
@@ -0,0 +1,401 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "buffer.h"
+#include "ioloop.h"
+#include "istream.h"
+#include "istream-concat.h"
+#include "ostream.h"
+#include "path-util.h"
+#include "str.h"
+#include "base64.h"
+#include "process-title.h"
+#include "restrict-access.h"
+#include "settings-parser.h"
+#include "master-interface.h"
+#include "master-service.h"
+#include "master-login.h"
+#include "mail-user.h"
+#include "mail-storage-service.h"
+
+#include "managesieve-common.h"
+#include "managesieve-commands.h"
+#include "managesieve-capabilities.h"
+
+#include <stdio.h>
+#include <unistd.h>
+
+#define IS_STANDALONE() \
+ (getenv(MASTER_IS_PARENT_ENV) == NULL)
+
+#define MANAGESIEVE_DIE_IDLE_SECS 10
+
+static bool verbose_proctitle = FALSE;
+static struct mail_storage_service_ctx *storage_service;
+static struct master_login *master_login = NULL;
+
+void (*hook_client_created)(struct client **client) = NULL;
+
+struct event_category event_category_managesieve = {
+ .name = "managesieve",
+};
+
+void managesieve_refresh_proctitle(void)
+{
+#define MANAGESIEVE_PROCTITLE_PREFERRED_LEN 80
+ struct client *client;
+ string_t *title = t_str_new(128);
+
+ if (!verbose_proctitle)
+ return;
+
+ str_append_c(title, '[');
+ switch (managesieve_client_count) {
+ case 0:
+ str_append(title, "idling");
+ break;
+ case 1:
+ client = managesieve_clients;
+ str_append(title, client->user->username);
+ if (client->user->conn.remote_ip != NULL) {
+ str_append_c(title, ' ');
+ str_append(title,
+ net_ip2addr(client->user->conn.remote_ip));
+ }
+
+ if (client->cmd.name != NULL &&
+ str_len(title) <= MANAGESIEVE_PROCTITLE_PREFERRED_LEN) {
+ str_append_c(title, ' ');
+ str_append(title, client->cmd.name);
+ }
+ break;
+ default:
+ str_printfa(title, "%u connections", managesieve_client_count);
+ break;
+ }
+ str_append_c(title, ']');
+ process_title_set(str_c(title));
+}
+
+static void client_kill_idle(struct client *client)
+{
+ mail_storage_service_io_activate_user(client->service_user);
+ client_send_bye(client, "Server shutting down.");
+ client_destroy(client, "Server shutting down.");
+}
+
+static void managesieve_die(void)
+{
+ struct client *client, *next;
+ time_t last_io, now = time(NULL);
+ time_t stop_timestamp = now - MANAGESIEVE_DIE_IDLE_SECS;
+ unsigned int stop_msecs;
+
+ for (client = managesieve_clients; client != NULL; client = next) {
+ next = client->next;
+
+ last_io = I_MAX(client->last_input, client->last_output);
+ if (last_io <= stop_timestamp)
+ client_kill_idle(client);
+ else {
+ timeout_remove(&client->to_idle);
+ stop_msecs = (last_io - stop_timestamp) * 1000;
+ client->to_idle = timeout_add(stop_msecs,
+ client_kill_idle, client);
+ }
+ }
+}
+
+static void client_add_istream_prefix(struct client *client,
+ const buffer_t *input)
+{
+ struct istream *inputs[] = {
+ i_stream_create_copy_from_data(input->data, input->used),
+ client->input,
+ NULL
+ };
+ client->input = i_stream_create_concat(inputs);
+ i_stream_copy_fd(client->input, inputs[1]);
+ i_stream_unref(&inputs[0]);
+ i_stream_unref(&inputs[1]);
+
+ i_stream_set_input_pending(client->input, TRUE);
+}
+
+static void client_logged_in(struct client *client)
+{
+ struct ostream *output;
+
+ output = client->output;
+ o_stream_ref(output);
+ o_stream_cork(output);
+ if (!IS_STANDALONE())
+ client_send_ok(client, "Logged in.");
+ (void)client_input(client);
+ o_stream_uncork(output);
+ o_stream_unref(&output);
+}
+
+static int
+client_create_from_input(const struct mail_storage_service_input *input,
+ int fd_in, int fd_out, const buffer_t *input_buf,
+ const char **error_r)
+{
+ struct mail_storage_service_input service_input;
+ struct mail_storage_service_user *user;
+ struct mail_user *mail_user;
+ struct client *client;
+ struct managesieve_settings *set;
+ struct event *event;
+ const char *error;
+
+ event = event_create(NULL);
+ event_add_category(event, &event_category_managesieve);
+ event_add_fields(event, (const struct event_add_field []){
+ { .key = "user", .value = input->username },
+ { .key = "session", .value = input->session_id },
+ { .key = NULL }
+ });
+
+ service_input = *input;
+ service_input.event_parent = event;
+ if (mail_storage_service_lookup_next(storage_service, &service_input,
+ &user, &mail_user, error_r) <= 0) {
+ event_unref(&event);
+ return -1;
+ }
+ restrict_access_allow_coredumps(TRUE);
+
+ set = mail_storage_service_user_get_set(user)[1];
+ if (set->verbose_proctitle)
+ verbose_proctitle = TRUE;
+
+ if (settings_var_expand(&managesieve_setting_parser_info, set,
+ mail_user->pool,
+ mail_user_var_expand_table(mail_user),
+ &error) <= 0) {
+ i_error("Failed to expand settings: %s", error);
+ mail_storage_service_user_unref(&user);
+ mail_user_unref(&mail_user);
+ event_unref(&event);
+ return -1;
+ }
+
+ client = client_create(fd_in, fd_out, input->session_id,
+ event, mail_user, user, set);
+ if (input_buf != NULL && input_buf->used > 0)
+ client_add_istream_prefix(client, input_buf);
+ client_create_finish(client);
+ T_BEGIN {
+ client_logged_in(client);
+ } T_END;
+ event_unref(&event);
+ return 0;
+}
+
+static void main_stdio_run(const char *username)
+{
+ struct mail_storage_service_input input;
+ const char *value, *error, *input_base64;
+ buffer_t *input_buf;
+
+ i_zero(&input);
+ input.module = "managesieve";
+ input.service = "sieve";
+ input.username = username != NULL ? username : getenv("USER");
+ if (input.username == NULL && IS_STANDALONE())
+ input.username = getlogin();
+ if (input.username == NULL)
+ i_fatal("USER environment missing");
+ if ((value = getenv("IP")) != NULL)
+ net_addr2ip(value, &input.remote_ip);
+ if ((value = getenv("LOCAL_IP")) != NULL)
+ net_addr2ip(value, &input.local_ip);
+
+ input_base64 = getenv("CLIENT_INPUT");
+ input_buf = (input_base64 == NULL ?
+ NULL : t_base64_decode_str(input_base64));
+
+ if (client_create_from_input(&input, STDIN_FILENO, STDOUT_FILENO,
+ input_buf, &error) < 0)
+ i_fatal("%s", error);
+}
+
+static void
+login_client_connected(const struct master_login_client *client,
+ const char *username, const char *const *extra_fields)
+{
+#define MSG_BYE_INTERNAL_ERROR "BYE \""CRITICAL_MSG"\"\r\n"
+ struct mail_storage_service_input input;
+ enum mail_auth_request_flags flags = client->auth_req.flags;
+ const char *error;
+ buffer_t input_buf;
+
+ i_zero(&input);
+ input.module = "managesieve";
+ input.service = "sieve";
+ input.local_ip = client->auth_req.local_ip;
+ input.remote_ip = client->auth_req.remote_ip;
+ input.local_port = client->auth_req.local_port;
+ input.remote_port = client->auth_req.remote_port;
+ input.username = username;
+ input.userdb_fields = extra_fields;
+ input.session_id = client->session_id;
+ if ((flags & MAIL_AUTH_REQUEST_FLAG_CONN_SECURED) != 0)
+ input.conn_secured = TRUE;
+ if ((flags & MAIL_AUTH_REQUEST_FLAG_CONN_SSL_SECURED) != 0)
+ input.conn_ssl_secured = TRUE;
+
+ buffer_create_from_const_data(&input_buf, client->data,
+ client->auth_req.data_size);
+ if (client_create_from_input(&input, client->fd, client->fd,
+ &input_buf, &error) < 0) {
+ int fd = client->fd;
+
+ if (write(fd, MSG_BYE_INTERNAL_ERROR,
+ strlen(MSG_BYE_INTERNAL_ERROR)) < 0) {
+ if (errno != EAGAIN && errno != EPIPE)
+ i_error("write(client) failed: %m");
+ }
+ i_error("%s", error);
+ i_close_fd(&fd);
+ master_service_client_connection_destroyed(master_service);
+ }
+}
+
+static void
+login_client_failed(const struct master_login_client *client,
+ const char *errormsg)
+{
+ const char *msg;
+
+ msg = t_strdup_printf("NO \"%s\"\r\n", errormsg);
+ if (write(client->fd, msg, strlen(msg)) < 0) {
+ /* ignored */
+ }
+}
+
+static void client_connected(struct master_service_connection *conn)
+{
+ /* when running standalone, we shouldn't even get here */
+ i_assert(master_login != NULL);
+
+ master_service_client_connection_accept(conn);
+ master_login_add(master_login, conn->fd);
+}
+
+int main(int argc, char *argv[])
+{
+ static const struct setting_parser_info *set_roots[] = {
+ &managesieve_setting_parser_info,
+ NULL
+ };
+ struct master_login_settings login_set;
+ enum master_service_flags service_flags = 0;
+ enum mail_storage_service_flags storage_service_flags = 0;
+ const char *username = NULL, *error = NULL;
+ int c;
+
+ i_zero(&login_set);
+ login_set.postlogin_timeout_secs = MASTER_POSTLOGIN_TIMEOUT_DEFAULT;
+
+ if (IS_STANDALONE() && getuid() == 0 &&
+ net_getpeername(1, NULL, NULL) == 0) {
+ printf("NO \"managesieve binary must not be started from "
+ "inetd, use managesieve-login instead.\"\n");
+ return 1;
+ }
+
+ if (IS_STANDALONE() || getenv("DUMP_CAPABILITY") != NULL) {
+ service_flags |= MASTER_SERVICE_FLAG_STANDALONE |
+ MASTER_SERVICE_FLAG_STD_CLIENT;
+ } else {
+ service_flags |= MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN;
+ }
+ if (getenv("DUMP_CAPABILITY") != NULL) {
+ service_flags |= MASTER_SERVICE_FLAG_DONT_SEND_STATS |
+ MASTER_SERVICE_FLAG_DISABLE_SSL_SET;
+ }
+
+ master_service = master_service_init("managesieve", service_flags,
+ &argc, &argv, "t:u:");
+ while ((c = master_getopt(master_service)) > 0) {
+ switch (c) {
+ case 't':
+ if (str_to_uint(optarg,
+ &login_set.postlogin_timeout_secs) < 0 ||
+ login_set.postlogin_timeout_secs == 0)
+ i_fatal("Invalid -t parameter: %s", optarg);
+ break;
+ case 'u':
+ storage_service_flags |=
+ MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
+ username = optarg;
+ break;
+ default:
+ return FATAL_DEFAULT;
+ }
+ }
+
+ master_service_set_die_callback(master_service, managesieve_die);
+
+ /* plugins may want to add commands, so this needs to be called early */
+ commands_init();
+
+ /* Dump capabilities if requested */
+ if (getenv("DUMP_CAPABILITY") != NULL) {
+ i_set_debug_file("/dev/null");
+ managesieve_capabilities_dump();
+ commands_deinit();
+ master_service_deinit(&master_service);
+ exit(0);
+ }
+
+ if (t_abspath("auth-master", &login_set.auth_socket_path, &error) < 0)
+ i_fatal("t_abspath(%s) failed: %s", "auth-master", error);
+
+ if (argv[optind] != NULL &&
+ t_abspath(argv[optind], &login_set.postlogin_socket_path,
+ &error) < 0) {
+ i_fatal("t_abspath(%s) failed: %s", argv[optind], error);
+ }
+
+ login_set.callback = login_client_connected;
+ login_set.failure_callback = login_client_failed;
+
+ if (!IS_STANDALONE())
+ master_login = master_login_init(master_service, &login_set);
+
+ storage_service =
+ mail_storage_service_init(master_service,
+ set_roots, storage_service_flags);
+ master_service_init_finish(master_service);
+ /* NOTE: login_set.*_socket_path are now invalid due to data stack
+ having been freed */
+
+ /* fake that we're running, so we know if client was destroyed
+ while handling its initial input */
+ io_loop_set_running(current_ioloop);
+
+ if (IS_STANDALONE()) {
+ T_BEGIN {
+ main_stdio_run(username);
+ } T_END;
+ } else {
+ io_loop_set_running(current_ioloop);
+ }
+
+ if (io_loop_is_running(current_ioloop))
+ master_service_run(master_service, client_connected);
+ clients_destroy_all();
+
+ if (master_login != NULL)
+ master_login_deinit(&master_login);
+ mail_storage_service_deinit(&storage_service);
+
+ commands_deinit();
+
+ master_service_deinit(&master_service);
+ return 0;
+}
diff --git a/pigeonhole/src/managesieve/managesieve-capabilities.c b/pigeonhole/src/managesieve/managesieve-capabilities.c
new file mode 100644
index 0000000..c72558f
--- /dev/null
+++ b/pigeonhole/src/managesieve/managesieve-capabilities.c
@@ -0,0 +1,136 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "hostpid.h"
+#include "var-expand.h"
+#include "settings-parser.h"
+#include "master-service.h"
+#include "master-service-settings.h"
+#include "master-service-settings-cache.h"
+
+#include "sieve.h"
+
+#include "managesieve-capabilities.h"
+
+#include <stddef.h>
+#include <unistd.h>
+
+/*
+ * Global plugin settings
+ */
+
+struct plugin_settings {
+ ARRAY(const char *) plugin_envs;
+};
+
+static const struct setting_parser_info **plugin_set_roots;
+
+static const struct setting_define plugin_setting_defines[] = {
+ { .type = SET_STRLIST, .key = "plugin",
+ .offset = offsetof(struct plugin_settings, plugin_envs) },
+
+ SETTING_DEFINE_LIST_END
+};
+
+static const struct setting_parser_info plugin_setting_parser_info = {
+ .module_name = "managesieve",
+ .defines = plugin_setting_defines,
+
+ .type_offset = (size_t)-1,
+ .struct_size = sizeof(struct plugin_settings),
+
+ .parent_offset = (size_t)-1,
+};
+
+static const struct setting_parser_info *default_plugin_set_roots[] = {
+ &plugin_setting_parser_info,
+ NULL
+};
+
+static const struct setting_parser_info **plugin_set_roots =
+ default_plugin_set_roots;
+
+static struct plugin_settings *plugin_settings_read(void)
+{
+ const char *error;
+
+ if (master_service_settings_read_simple(
+ master_service, plugin_set_roots, &error) < 0)
+ i_fatal("Error reading configuration: %s", error);
+
+ return (struct plugin_settings *)
+ master_service_settings_get_others(master_service)[0];
+}
+
+static const char *
+plugin_settings_get(const struct plugin_settings *set, const char *identifier)
+{
+ const char *const *envs;
+ unsigned int i, count;
+
+ if ( !array_is_created(&set->plugin_envs) )
+ return NULL;
+
+ envs = array_get(&set->plugin_envs, &count);
+ for ( i = 0; i < count; i += 2 ) {
+ if ( strcmp(envs[i], identifier) == 0 )
+ return envs[i+1];
+ }
+ return NULL;
+}
+
+/*
+ * Sieve environment
+ */
+
+static const char *sieve_get_setting(void *context, const char *identifier)
+{
+ const struct plugin_settings *set = context;
+
+ return plugin_settings_get(set, identifier);
+}
+
+static const struct sieve_callbacks sieve_callbacks = {
+ NULL,
+ sieve_get_setting
+};
+
+/*
+ * Capability dumping
+ */
+
+void managesieve_capabilities_dump(void)
+{
+ const struct plugin_settings *global_plugin_settings;
+ struct sieve_environment svenv;
+ struct sieve_instance *svinst;
+ const char *notify_cap;
+
+ /* Read plugin settings */
+
+ global_plugin_settings = plugin_settings_read();
+
+ /* Initialize Sieve engine */
+
+ memset((void*)&svenv, 0, sizeof(svenv));
+ svenv.home_dir = "/tmp";
+
+ svinst = sieve_init(&svenv, &sieve_callbacks,
+ (void *) global_plugin_settings, FALSE);
+
+ /* Dump capabilities */
+
+ notify_cap = sieve_get_capabilities(svinst, "notify");
+
+ if (notify_cap == NULL)
+ printf("SIEVE: %s\n", sieve_get_capabilities(svinst, NULL));
+ else {
+ printf("SIEVE: %s, NOTIFY: %s\n",
+ sieve_get_capabilities(svinst, NULL),
+ sieve_get_capabilities(svinst, "notify"));
+ }
+
+ sieve_deinit(&svinst);
+}
diff --git a/pigeonhole/src/managesieve/managesieve-capabilities.h b/pigeonhole/src/managesieve/managesieve-capabilities.h
new file mode 100644
index 0000000..b7503a9
--- /dev/null
+++ b/pigeonhole/src/managesieve/managesieve-capabilities.h
@@ -0,0 +1,6 @@
+#ifndef MANAGESIEVE_CAPABILITIES_H
+#define MANAGESIEVE_CAPABILITIES_H
+
+void managesieve_capabilities_dump(void);
+
+#endif
diff --git a/pigeonhole/src/managesieve/managesieve-client.c b/pigeonhole/src/managesieve/managesieve-client.c
new file mode 100644
index 0000000..bacf460
--- /dev/null
+++ b/pigeonhole/src/managesieve/managesieve-client.c
@@ -0,0 +1,792 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "llist.h"
+#include "str.h"
+#include "hostpid.h"
+#include "net.h"
+#include "istream.h"
+#include "ostream.h"
+#include "iostream.h"
+#include "iostream-rawlog.h"
+#include "var-expand.h"
+#include "time-util.h"
+#include "master-service.h"
+#include "mail-storage-service.h"
+#include "mail-namespace.h"
+
+#include "sieve.h"
+#include "sieve-storage.h"
+
+#include "managesieve-quote.h"
+#include "managesieve-common.h"
+#include "managesieve-commands.h"
+#include "managesieve-client.h"
+
+#include <unistd.h>
+
+extern struct mail_storage_callbacks mail_storage_callbacks;
+struct managesieve_module_register managesieve_module_register = { 0 };
+
+struct client *managesieve_clients = NULL;
+unsigned int managesieve_client_count = 0;
+
+static const char *
+managesieve_sieve_get_setting(void *context, const char *identifier)
+{
+ struct mail_user *mail_user = (struct mail_user *) context;
+
+ if (mail_user == NULL)
+ return NULL;
+
+ return mail_user_plugin_getenv(mail_user, identifier);
+}
+
+static const struct sieve_callbacks managesieve_sieve_callbacks = {
+ NULL,
+ managesieve_sieve_get_setting
+};
+
+static void client_idle_timeout(struct client *client)
+{
+ if (client->cmd.func != NULL) {
+ client_destroy(client,
+ "Disconnected for inactivity in reading our output");
+ } else {
+ client_send_bye(client, "Disconnected for inactivity");
+ client_destroy(client, "Disconnected for inactivity");
+ }
+}
+
+static struct sieve_storage *
+client_get_storage(struct sieve_instance *svinst, struct mail_user *user,
+ int fd_out)
+{
+ struct sieve_storage *storage;
+ enum sieve_error error;
+ const char *errormsg, *byemsg;
+
+ /* Open personal script storage */
+
+ storage = sieve_storage_create_main(svinst, user,
+ SIEVE_STORAGE_FLAG_READWRITE,
+ &error);
+ if (storage == NULL) {
+ switch (error) {
+ case SIEVE_ERROR_NOT_POSSIBLE:
+ byemsg = "BYE \"Sieve processing is disabled for this user.\"\r\n";
+ errormsg = "Failed to open Sieve storage: "
+ "Sieve is disabled for this user";
+ break;
+ case SIEVE_ERROR_NOT_FOUND:
+ byemsg = "BYE \"This user cannot manage personal Sieve scripts.\"\r\n";
+ errormsg = "Failed to open Sieve storage: "
+ "Personal script storage disabled or not found.";
+ break;
+ default:
+ byemsg = t_strflocaltime(
+ "BYE \""CRITICAL_MSG_STAMP"\"\r\n", ioloop_time);
+ errormsg = "Failed to open Sieve storage.";
+ }
+
+ if (write(fd_out, byemsg, strlen(byemsg)) < 0) {
+ if (errno != EAGAIN && errno != EPIPE)
+ i_error("write(client) failed: %m");
+ }
+ i_fatal("%s", errormsg);
+ }
+
+ return storage;
+}
+
+struct client *
+client_create(int fd_in, int fd_out, const char *session_id,
+ struct event *event, struct mail_user *user,
+ struct mail_storage_service_user *service_user,
+ const struct managesieve_settings *set)
+{
+ struct client *client;
+ const char *ident;
+ struct sieve_environment svenv;
+ struct sieve_instance *svinst;
+ struct sieve_storage *storage;
+ pool_t pool;
+
+ /* Initialize Sieve */
+
+ memset((void*)&svenv, 0, sizeof(svenv));
+ svenv.username = user->username;
+ (void)mail_user_get_home(user, &svenv.home_dir);
+ svenv.base_dir = user->set->base_dir;
+ svenv.event_parent = event;
+ svenv.flags = SIEVE_FLAG_HOME_RELATIVE;
+
+ svinst = sieve_init(&svenv, &managesieve_sieve_callbacks,
+ (void *) user, set->mail_debug);
+
+ /* Get Sieve storage */
+
+ storage = client_get_storage(svinst, user, fd_out);
+
+ /* always use nonblocking I/O */
+ net_set_nonblock(fd_in, TRUE);
+ net_set_nonblock(fd_out, TRUE);
+
+ pool = pool_alloconly_create("managesieve client", 1024);
+ client = p_new(pool, struct client, 1);
+ client->pool = pool;
+ client->event = event;
+ event_ref(client->event);
+ client->set = set;
+ client->service_user = service_user;
+ client->session_id = p_strdup(pool, session_id);
+ client->fd_in = fd_in;
+ client->fd_out = fd_out;
+ client->input = i_stream_create_fd(
+ fd_in, set->managesieve_max_line_length);
+ client->output = o_stream_create_fd(fd_out, (size_t)-1);
+
+ o_stream_set_no_error_handling(client->output, TRUE);
+ i_stream_set_name(client->input, "<managesieve client>");
+ o_stream_set_name(client->output, "<managesieve client>");
+
+ o_stream_set_flush_callback(client->output, client_output, client);
+
+ client->last_input = ioloop_time;
+ client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
+ client_idle_timeout, client);
+
+ client->cmd.pool = pool_alloconly_create(
+ MEMPOOL_GROWING"client command", 1024*12);
+ client->cmd.client = client;
+ client->cmd.event = event_create(client->event);
+ client->user = user;
+
+ client->svinst = svinst;
+ client->storage = storage;
+
+ ident = mail_user_get_anvil_userip_ident(client->user);
+ if (ident != NULL) {
+ master_service_anvil_send(
+ master_service, t_strconcat("CONNECT\t", my_pid,
+ "\tsieve/", ident,
+ "\n", NULL));
+ client->anvil_sent = TRUE;
+ }
+
+ managesieve_client_count++;
+ DLLIST_PREPEND(&managesieve_clients, client);
+ if (hook_client_created != NULL)
+ hook_client_created(&client);
+
+ managesieve_refresh_proctitle();
+ return client;
+}
+
+void client_create_finish(struct client *client)
+{
+ if (client->set->rawlog_dir[0] != '\0') {
+ (void)iostream_rawlog_create(client->set->rawlog_dir,
+ &client->input, &client->output);
+ }
+ client->parser = managesieve_parser_create(
+ client->input, client->set->managesieve_max_line_length);
+ client->io = io_add_istream(client->input, client_input, client);
+}
+
+static const char *client_stats(struct client *client)
+{
+ const struct var_expand_table logout_tab[] = {
+ { 'i', dec2str(i_stream_get_absolute_offset(client->input)),
+ "input" },
+ { 'o', dec2str(client->output->offset), "output" },
+ { '\0', dec2str(client->put_bytes), "put_bytes" },
+ { '\0', dec2str(client->put_count), "put_count" },
+ { '\0', dec2str(client->get_bytes), "get_bytes" },
+ { '\0', dec2str(client->get_count), "get_count" },
+ { '\0', dec2str(client->check_bytes), "check_bytes" },
+ { '\0', dec2str(client->check_count), "check_count" },
+ { '\0', dec2str(client->deleted_count), "deleted_count" },
+ { '\0', dec2str(client->renamed_count), "renamed_count" },
+ { '\0', client->session_id, "session" },
+ { '\0', NULL, NULL }
+ };
+ const struct var_expand_table *user_tab =
+ mail_user_var_expand_table(client->user);
+ const struct var_expand_table *tab =
+ t_var_expand_merge_tables(logout_tab, user_tab);
+ string_t *str;
+ const char *error;
+
+ str = t_str_new(128);
+ if (var_expand_with_funcs(str, client->set->managesieve_logout_format,
+ tab, mail_user_var_expand_func_table,
+ client->user, &error) < 0) {
+ i_error("Failed to expand managesieve_logout_format=%s: %s",
+ client->set->managesieve_logout_format, error);
+ }
+ return str_c(str);
+}
+
+void client_destroy(struct client *client, const char *reason)
+{
+ bool ret;
+
+ i_assert(!client->handling_input);
+ i_assert(!client->destroyed);
+ client->destroyed = TRUE;
+
+ client_disconnect(client, reason);
+
+ if (client->command_pending) {
+ /* try to deinitialize the command */
+ i_assert(client->cmd.func != NULL);
+
+ i_stream_close(client->input);
+ o_stream_close(client->output);
+
+ client->input_pending = FALSE;
+
+ ret = client->cmd.func(&client->cmd);
+ i_assert(ret);
+ }
+
+ if (client->anvil_sent) {
+ master_service_anvil_send(
+ master_service, t_strconcat(
+ "DISCONNECT\t", my_pid, "\tsieve/",
+ mail_user_get_anvil_userip_ident(client->user),
+ "\n", NULL));
+ }
+
+ managesieve_parser_destroy(&client->parser);
+ io_remove(&client->io);
+ timeout_remove(&client->to_idle_output);
+ timeout_remove(&client->to_idle);
+
+ /* i/ostreams are already closed at this stage, so fd can be closed */
+ net_disconnect(client->fd_in);
+ if (client->fd_in != client->fd_out)
+ net_disconnect(client->fd_out);
+
+ /* Free the user after client is already disconnected. It may start
+ some background work like autoexpunging. */
+ mail_user_unref(&client->user);
+
+ /* free the i/ostreams after mail_user_unref(), which could trigger
+ mail_storage_callbacks notifications that write to the ostream. */
+ i_stream_destroy(&client->input);
+ o_stream_destroy(&client->output);
+
+ sieve_storage_unref(&client->storage);
+ sieve_deinit(&client->svinst);
+
+ event_unref(&client->cmd.event);
+ pool_unref(&client->cmd.pool);
+ mail_storage_service_user_unref(&client->service_user);
+
+ managesieve_client_count--;
+ DLLIST_REMOVE(&managesieve_clients, client);
+ event_unref(&client->event);
+ pool_unref(&client->pool);
+
+ master_service_client_connection_destroyed(master_service);
+ managesieve_refresh_proctitle();
+}
+
+static void client_destroy_timeout(struct client *client)
+{
+ client_destroy(client, NULL);
+}
+
+void client_disconnect(struct client *client, const char *reason)
+{
+ if (client->disconnected)
+ return;
+
+ if (reason == NULL) {
+ reason = io_stream_get_disconnect_reason(client->input,
+ client->output);
+ i_info("%s %s", reason, client_stats(client));
+ } else {
+ i_info("Disconnected: %s %s", reason, client_stats(client));
+ }
+ client->disconnected = TRUE;
+ o_stream_flush(client->output);
+ o_stream_uncork(client->output);
+
+ i_stream_close(client->input);
+ o_stream_close(client->output);
+
+ timeout_remove(&client->to_idle);
+ if (!client->destroyed)
+ client->to_idle = timeout_add(0, client_destroy_timeout, client);
+}
+
+void client_disconnect_with_error(struct client *client, const char *msg)
+{
+ client_send_bye(client, msg);
+ client_disconnect(client, msg);
+}
+
+int client_send_line(struct client *client, const char *data)
+{
+ struct const_iovec iov[2];
+
+ if (client->output->closed)
+ return -1;
+
+ iov[0].iov_base = data;
+ iov[0].iov_len = strlen(data);
+ iov[1].iov_base = "\r\n";
+ iov[1].iov_len = 2;
+
+ if (o_stream_sendv(client->output, iov, 2) < 0)
+ return -1;
+ client->last_output = ioloop_time;
+
+ if (o_stream_get_buffer_used_size(client->output) >=
+ CLIENT_OUTPUT_OPTIMAL_SIZE) {
+ /* buffer full, try flushing */
+ return o_stream_flush(client->output);
+ }
+ return 1;
+}
+
+void client_send_response(struct client *client, const char *oknobye,
+ const char *resp_code, const char *msg)
+{
+ string_t *str;
+
+ str = t_str_new(128);
+ str_append(str, oknobye);
+
+ if (resp_code != NULL) {
+ str_append(str, " (");
+ str_append(str, resp_code);
+ str_append_c(str, ')');
+ }
+
+ if (msg != NULL) {
+ str_append_c(str, ' ');
+ managesieve_quote_append_string(str, msg, TRUE);
+ }
+
+ client_send_line(client, str_c(str));
+}
+
+struct event_passthrough *
+client_command_create_finish_event(struct client_command_context *cmd)
+{
+ struct event_passthrough *e =
+ event_create_passthrough(cmd->event)->
+ set_name("managesieve_command_finished");
+ return e;
+}
+
+void client_send_command_error(struct client_command_context *cmd,
+ const char *msg)
+{
+ struct client *client = cmd->client;
+ const char *error, *cmd_name;
+ bool fatal;
+
+ if (msg == NULL) {
+ msg = managesieve_parser_get_error(client->parser, &fatal);
+ if (fatal) {
+ client_disconnect_with_error(client, msg);
+ return;
+ }
+ }
+
+ if (cmd->name == NULL) {
+ error = t_strconcat("Error in MANAGESIEVE command: ",
+ msg, NULL);
+ } else {
+ cmd_name = t_str_ucase(cmd->name);
+ error = t_strconcat("Error in MANAGESIEVE command ",
+ cmd_name, ": ", msg, NULL);
+ }
+
+ client_send_no(client, error);
+
+ if (++client->bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
+ client_disconnect_with_error(
+ client, "Too many invalid MANAGESIEVE commands.");
+ }
+
+ /* client_read_args() failures rely on this being set, so that the
+ command processing is stopped even while command function returns
+ FALSE. */
+ cmd->param_error = TRUE;
+}
+
+#undef client_command_storage_error
+void client_command_storage_error(struct client_command_context *cmd,
+ const char *source_filename,
+ unsigned int source_linenum,
+ const char *log_prefix, ...)
+{
+ struct event_log_params params = {
+ .log_type = LOG_TYPE_INFO,
+ .source_filename = source_filename,
+ .source_linenum = source_linenum,
+ };
+ struct client *client = cmd->client;
+ struct sieve_storage *storage = client->storage;
+ enum sieve_error error_code;
+ const char *error;
+ va_list args;
+
+ error = sieve_storage_get_last_error(storage, &error_code);
+
+ switch (error_code) {
+ case SIEVE_ERROR_TEMP_FAILURE:
+ client_send_noresp(client, "TRYLATER", error);
+ break;
+ case SIEVE_ERROR_NO_QUOTA:
+ client_send_noresp(client, "QUOTA", error);
+ break;
+ case SIEVE_ERROR_NOT_FOUND:
+ client_send_noresp(client, "NONEXISTENT", error);
+ break;
+ case SIEVE_ERROR_ACTIVE:
+ client_send_noresp(client, "ACTIVE", error);
+ break;
+ case SIEVE_ERROR_EXISTS:
+ client_send_noresp(client, "ALREADYEXISTS", error);
+ break;
+ case SIEVE_ERROR_NOT_POSSIBLE:
+ default:
+ client_send_no(client, error);
+ break;
+ }
+
+ struct event_passthrough *e =
+ client_command_create_finish_event(cmd)->
+ add_str("error", error);
+
+ va_start(args, log_prefix);
+ event_log(e->event(), &params, "%s: %s",
+ t_strdup_vprintf(log_prefix, args), error);
+ va_end(args);
+}
+
+bool client_read_args(struct client_command_context *cmd, unsigned int count,
+ unsigned int flags, bool no_more,
+ const struct managesieve_arg **args_r)
+{
+ const struct managesieve_arg *dummy_args_r = NULL;
+ string_t *str;
+ int ret;
+
+ if (args_r == NULL)
+ args_r = &dummy_args_r;
+
+ i_assert(count <= INT_MAX);
+
+ ret = managesieve_parser_read_args(cmd->client->parser,
+ (no_more ? 0 : count),
+ flags, args_r);
+ if (ret >= 0) {
+ if (count > 0 || no_more) {
+ if (ret < (int)count) {
+ client_send_command_error(
+ cmd, "Missing arguments.");
+ return FALSE;
+ } else if (no_more && ret > (int)count) {
+ client_send_command_error(
+ cmd, "Too many arguments.");
+ return FALSE;
+ }
+ }
+
+ str = t_str_new(256);
+ managesieve_write_args(str, *args_r);
+ cmd->args = p_strdup(cmd->pool, str_c(str));
+
+ event_add_str(cmd->event, "cmd_args", cmd->args);
+
+ /* all parameters read successfully */
+ return TRUE;
+ } else if (ret == -2) {
+ /* need more data */
+ if (cmd->client->input->closed) {
+ /* disconnected */
+ cmd->param_error = TRUE;
+ }
+ return FALSE;
+ } else {
+ /* error */
+ client_send_command_error(cmd, NULL);
+ return FALSE;
+ }
+}
+
+bool client_read_string_args(struct client_command_context *cmd,
+ bool no_more, unsigned int count, ...)
+{
+ const struct managesieve_arg *msieve_args;
+ va_list va;
+ const char *str;
+ unsigned int i;
+ bool result = TRUE;
+
+ if (!client_read_args(cmd, count, 0, no_more, &msieve_args))
+ return FALSE;
+
+ va_start(va, count);
+ for (i = 0; i < count; i++) {
+ const char **ret = va_arg(va, const char **);
+
+ if (MANAGESIEVE_ARG_IS_EOL(&msieve_args[i])) {
+ client_send_command_error(cmd, "Missing arguments.");
+ result = FALSE;
+ break;
+ }
+
+ if (!managesieve_arg_get_string(&msieve_args[i], &str)) {
+ client_send_command_error(cmd, "Invalid arguments.");
+ result = FALSE;
+ break;
+ }
+
+ if (ret != NULL)
+ *ret = str;
+ }
+ va_end(va);
+
+ return result;
+}
+
+void _client_reset_command(struct client *client)
+{
+ pool_t pool;
+ size_t size;
+
+ /* reset input idle time because command output might have taken a long
+ time and we don't want to disconnect client immediately then */
+ client->last_input = ioloop_time;
+ timeout_reset(client->to_idle);
+
+ client->command_pending = FALSE;
+ if (client->io == NULL && !client->disconnected) {
+ i_assert(i_stream_get_fd(client->input) >= 0);
+ client->io = io_add(i_stream_get_fd(client->input),
+ IO_READ, client_input, client);
+ }
+ o_stream_set_flush_callback(client->output, client_output, client);
+
+ event_unref(&client->cmd.event);
+
+ pool = client->cmd.pool;
+ i_zero(&client->cmd);
+
+ p_clear(pool);
+ client->cmd.pool = pool;
+ client->cmd.client = client;
+
+ client->cmd.event = event_create(client->event);
+
+ managesieve_parser_reset(client->parser);
+
+ /* if there's unread data in buffer, remember that there's input pending
+ and we should get around to calling client_input() soon. This is
+ mostly for APPEND/IDLE. */
+ (void)i_stream_get_data(client->input, &size);
+ if (size > 0 && !client->destroyed)
+ client->input_pending = TRUE;
+}
+
+/* Skip incoming data until newline is found,
+ returns TRUE if newline was found. */
+static bool client_skip_line(struct client *client)
+{
+ const unsigned char *data;
+ size_t i, data_size;
+
+ data = i_stream_get_data(client->input, &data_size);
+
+ for (i = 0; i < data_size; i++) {
+ if (data[i] == '\n') {
+ client->input_skip_line = FALSE;
+ i++;
+ break;
+ }
+ }
+
+ i_stream_skip(client->input, i);
+ return !client->input_skip_line;
+}
+
+static bool client_handle_input(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+
+ if (cmd->func != NULL) {
+ bool finished;
+
+ event_push_global(cmd->event);
+ finished = cmd->func(cmd);
+ event_pop_global(cmd->event);
+
+ /* command is being executed - continue it */
+ if (finished || cmd->param_error) {
+ /* command execution was finished */
+ if (!cmd->param_error)
+ client->bad_counter = 0;
+ _client_reset_command(client);
+ return TRUE;
+ }
+
+ /* unfinished */
+ if (client->command_pending)
+ o_stream_set_flush_pending(client->output, TRUE);
+ return FALSE;
+ }
+
+ if (client->input_skip_line) {
+ /* we're just waiting for new line.. */
+ if (!client_skip_line(client))
+ return FALSE;
+
+ /* got the newline */
+ _client_reset_command(client);
+
+ /* pass through to parse next command */
+ }
+
+ if (cmd->name == NULL) {
+ cmd->name = managesieve_parser_read_word(client->parser);
+ if (cmd->name == NULL)
+ return FALSE; /* need more data */
+ cmd->name = p_strdup(cmd->pool, cmd->name);
+ managesieve_refresh_proctitle();
+ }
+
+ if (cmd->name[0] == '\0') {
+ /* command not given - cmd_func is already NULL. */
+ } else {
+ /* find the command function */
+ struct command *command = command_find(cmd->name);
+
+ if (command != NULL)
+ cmd->func = command->func;
+ }
+
+ client->input_skip_line = TRUE;
+ if (cmd->func == NULL) {
+ /* unknown command */
+ client_send_command_error(cmd, "Unknown command.");
+ _client_reset_command(client);
+ } else {
+ i_assert(!client->disconnected);
+
+ event_add_str(cmd->event, "cmd_name", t_str_ucase(cmd->name));
+ client_handle_input(cmd);
+ }
+
+ return TRUE;
+}
+
+void client_input(struct client *client)
+{
+ struct client_command_context *cmd = &client->cmd;
+ bool ret;
+
+ if (client->command_pending) {
+ /* already processing one command. wait. */
+ io_remove(&client->io);
+ return;
+ }
+
+ client->input_pending = FALSE;
+ client->last_input = ioloop_time;
+ timeout_reset(client->to_idle);
+
+ switch (i_stream_read(client->input)) {
+ case -1:
+ /* disconnected */
+ client_destroy(client, NULL);
+ return;
+ case -2:
+ /* parameter word is longer than max. input buffer size.
+ this is most likely an error, so skip the new data
+ until newline is found. */
+ client->input_skip_line = TRUE;
+
+ client_send_command_error(cmd, "Too long argument.");
+ _client_reset_command(client);
+ break;
+ }
+
+ client->handling_input = TRUE;
+ o_stream_cork(client->output);
+ do {
+ T_BEGIN {
+ ret = client_handle_input(cmd);
+ } T_END;
+ } while (ret && !client->disconnected);
+ o_stream_uncork(client->output);
+ client->handling_input = FALSE;
+
+ if (client->command_pending)
+ client->input_pending = TRUE;
+
+ if (client->output->closed)
+ client_destroy(client, NULL);
+}
+
+int client_output(struct client *client)
+{
+ struct client_command_context *cmd = &client->cmd;
+ int ret;
+ bool finished;
+
+ client->last_output = ioloop_time;
+ timeout_reset(client->to_idle);
+ if (client->to_idle_output != NULL)
+ timeout_reset(client->to_idle_output);
+
+ if ((ret = o_stream_flush(client->output)) < 0) {
+ client_destroy(client, NULL);
+ return 1;
+ }
+
+ if (!client->command_pending)
+ return 1;
+
+ /* continue processing command */
+ o_stream_cork(client->output);
+ client->output_pending = TRUE;
+ finished = cmd->func(cmd) || cmd->param_error;
+
+ /* a bit kludgy check. normally we would want to get back to this
+ output handler, but IDLE is a special case which has command
+ pending but without necessarily anything to write. */
+ if (!finished && client->output_pending)
+ o_stream_set_flush_pending(client->output, TRUE);
+
+ o_stream_uncork(client->output);
+
+ if (finished) {
+ /* command execution was finished */
+ client->bad_counter = 0;
+ _client_reset_command(client);
+
+ if (client->input_pending)
+ client_input(client);
+ }
+ return ret;
+}
+
+void clients_destroy_all(void)
+{
+ while (managesieve_clients != NULL) {
+ mail_storage_service_io_activate_user(managesieve_clients->service_user);
+ client_send_bye(managesieve_clients, "Server shutting down.");
+ client_destroy(managesieve_clients, "Server shutting down.");
+ }
+}
diff --git a/pigeonhole/src/managesieve/managesieve-client.h b/pigeonhole/src/managesieve/managesieve-client.h
new file mode 100644
index 0000000..6053eb6
--- /dev/null
+++ b/pigeonhole/src/managesieve/managesieve-client.h
@@ -0,0 +1,162 @@
+#ifndef MANAGESIEVE_CLIENT_H
+#define MANAGESIEVE_CLIENT_H
+
+#include "managesieve-commands.h"
+
+struct client;
+struct sieve_storage;
+struct managesieve_parser;
+struct managesieve_arg;
+
+struct client_command_context {
+ struct client *client;
+ struct event *event;
+
+ pool_t pool;
+ /* Name of this command */
+ const char *name;
+ /* Parameters for this command. These are generated from parsed
+ ManageSieve arguments, so they may not be exactly the same as how
+ client sent them. */
+ const char *args;
+
+ command_func_t *func;
+ void *context;
+
+ bool param_error:1;
+};
+
+struct managesieve_module_register {
+ unsigned int id;
+};
+
+union managesieve_module_context {
+ struct managesieve_module_register *reg;
+};
+extern struct managesieve_module_register managesieve_module_register;
+
+struct client {
+ struct client *prev, *next;
+
+ struct event *event;
+ const char *session_id;
+ int fd_in, fd_out;
+ struct io *io;
+ struct istream *input;
+ struct ostream *output;
+ struct timeout *to_idle, *to_idle_output;
+
+ pool_t pool;
+ struct mail_storage_service_user *service_user;
+ const struct managesieve_settings *set;
+
+ struct mail_user *user;
+
+ struct sieve_instance *svinst;
+ struct sieve_storage *storage;
+
+ time_t last_input, last_output;
+ unsigned int bad_counter;
+
+ struct managesieve_parser *parser;
+ struct client_command_context cmd;
+
+ uoff_t put_bytes;
+ uoff_t get_bytes;
+ uoff_t check_bytes;
+ unsigned int put_count;
+ unsigned int get_count;
+ unsigned int check_count;
+ unsigned int deleted_count;
+ unsigned int renamed_count;
+
+ bool disconnected:1;
+ bool destroyed:1;
+ bool command_pending:1;
+ bool input_pending:1;
+ bool output_pending:1;
+ bool handling_input:1;
+ bool anvil_sent:1;
+ bool input_skip_line:1; /* skip all the data until we've found a new
+ line */
+};
+
+extern struct client *managesieve_clients;
+extern unsigned int managesieve_client_count;
+
+/* Create new client with specified input/output handles. socket specifies
+ if the handle is a socket. */
+struct client *
+client_create(int fd_in, int fd_out, const char *session_id,
+ struct event *event, struct mail_user *user,
+ struct mail_storage_service_user *service_user,
+ const struct managesieve_settings *set);
+void client_create_finish(struct client *client);
+void client_destroy(struct client *client, const char *reason);
+
+void client_dump_capability(struct client *client);
+
+/* Disconnect client connection */
+void client_disconnect(struct client *client, const char *reason);
+void client_disconnect_with_error(struct client *client, const char *msg);
+
+/* Send a line of data to client. Returns 1 if ok, 0 if buffer is getting full,
+ -1 if error */
+int client_send_line(struct client *client, const char *data);
+
+void client_send_response(struct client *client, const char *oknobye,
+ const char *resp_code, const char *msg);
+
+#define client_send_ok(client, msg) \
+ client_send_response(client, "OK", NULL, msg)
+#define client_send_no(client, msg) \
+ client_send_response(client, "NO", NULL, msg)
+#define client_send_bye(client, msg) \
+ client_send_response(client, "BYE", NULL, msg)
+
+#define client_send_okresp(client, resp_code, msg) \
+ client_send_response(client, "OK", resp_code, msg)
+#define client_send_noresp(client, resp_code, msg) \
+ client_send_response(client, "NO", resp_code, msg)
+#define client_send_byeresp(cmd, resp_code, msg) \
+ client_send_response(client, "BYE", resp_code, msg)
+
+struct event_passthrough *
+client_command_create_finish_event(struct client_command_context *cmd);
+
+/* Send BAD command error to client. msg can be NULL. */
+void client_send_command_error(struct client_command_context *cmd,
+ const char *msg);
+
+/* Send storage or sieve-related errors to the client. Returns command finish
+ event with the "error" field set accordingly. */
+void client_command_storage_error(struct client_command_context *cmd,
+ const char *source_filename,
+ unsigned int source_linenum,
+ const char *log_prefix, ...)
+ ATTR_FORMAT(4, 5);
+#define client_command_storage_error(cmd, ...) \
+ client_command_storage_error(cmd, __FILE__, __LINE__, __VA_ARGS__)
+
+/* Read a number of arguments. Returns TRUE if everything was read or
+ FALSE if either needs more data or error occurred. */
+bool client_read_args(struct client_command_context *cmd, unsigned int count,
+ unsigned int flags, bool no_more,
+ const struct managesieve_arg **args_r);
+/* Reads a number of string arguments. ... is a list of pointers where to
+ store the arguments. */
+bool client_read_string_args(struct client_command_context *cmd, bool no_more,
+ unsigned int count, ...);
+
+static inline bool client_read_no_args(struct client_command_context *cmd)
+{
+ return client_read_args(cmd, 0, 0, TRUE, NULL);
+}
+
+void _client_reset_command(struct client *client);
+void client_input(struct client *client);
+int client_output(struct client *client);
+
+void clients_destroy_all(void);
+
+#endif
diff --git a/pigeonhole/src/managesieve/managesieve-commands.c b/pigeonhole/src/managesieve/managesieve-commands.c
new file mode 100644
index 0000000..87e2048
--- /dev/null
+++ b/pigeonhole/src/managesieve/managesieve-commands.c
@@ -0,0 +1,110 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+
+#include "managesieve-common.h"
+#include "managesieve-commands.h"
+
+
+/* May want to combine this somewhere in a commands-common.c to avoid duplicate
+ code
+ */
+
+static const struct command managesieve_base_commands[] = {
+ { "CAPABILITY", cmd_capability },
+ { "LOGOUT", cmd_logout },
+ { "PUTSCRIPT", cmd_putscript },
+ { "CHECKSCRIPT", cmd_checkscript },
+ { "GETSCRIPT", cmd_getscript },
+ { "SETACTIVE", cmd_setactive },
+ { "DELETESCRIPT", cmd_deletescript },
+ { "LISTSCRIPTS", cmd_listscripts },
+ { "HAVESPACE", cmd_havespace },
+ { "RENAMESCRIPT", cmd_renamescript },
+ { "NOOP", cmd_noop }
+};
+
+#define MANAGESIEVE_COMMANDS_COUNT N_ELEMENTS(managesieve_base_commands)
+
+static ARRAY(struct command) managesieve_commands;
+static bool commands_unsorted;
+
+void command_register(const char *name, command_func_t *func)
+{
+ struct command cmd;
+
+ i_zero(&cmd);
+ cmd.name = name;
+ cmd.func = func;
+ array_append(&managesieve_commands, &cmd, 1);
+
+ commands_unsorted = TRUE;
+}
+
+void command_unregister(const char *name)
+{
+ const struct command *cmd;
+ unsigned int i, count;
+
+ cmd = array_get(&managesieve_commands, &count);
+ for (i = 0; i < count; i++) {
+ if (strcasecmp(cmd[i].name, name) == 0) {
+ array_delete(&managesieve_commands, i, 1);
+ return;
+ }
+ }
+
+ i_error("Trying to unregister unknown command '%s'", name);
+}
+
+void command_register_array(const struct command *cmdarr, unsigned int count)
+{
+ commands_unsorted = TRUE;
+ array_append(&managesieve_commands, cmdarr, count);
+}
+
+void command_unregister_array(const struct command *cmdarr, unsigned int count)
+{
+ while (count > 0) {
+ command_unregister(cmdarr->name);
+ count--; cmdarr++;
+ }
+}
+
+static int command_cmp(const struct command *c1, const struct command *c2)
+{
+ return strcasecmp(c1->name, c2->name);
+}
+
+static int command_bsearch(const char *name, const struct command *cmd)
+{
+ return strcasecmp(name, cmd->name);
+}
+
+struct command *command_find(const char *name)
+{
+ if (commands_unsorted) {
+ array_sort(&managesieve_commands, command_cmp);
+ commands_unsorted = FALSE;
+ }
+
+ return array_bsearch(&managesieve_commands, name, command_bsearch);
+}
+
+void commands_init(void)
+{
+ i_array_init(&managesieve_commands, 16);
+ commands_unsorted = FALSE;
+
+ command_register_array(managesieve_base_commands,
+ MANAGESIEVE_COMMANDS_COUNT);
+}
+
+void commands_deinit(void)
+{
+ command_unregister_array(managesieve_base_commands,
+ MANAGESIEVE_COMMANDS_COUNT);
+ array_free(&managesieve_commands);
+}
diff --git a/pigeonhole/src/managesieve/managesieve-commands.h b/pigeonhole/src/managesieve/managesieve-commands.h
new file mode 100644
index 0000000..d922b74
--- /dev/null
+++ b/pigeonhole/src/managesieve/managesieve-commands.h
@@ -0,0 +1,46 @@
+#ifndef MANAGESIEVE_COMMANDS_H
+#define MANAGESIEVE_COMMANDS_H
+
+struct client_command_context;
+
+#include "managesieve-parser.h"
+
+typedef bool command_func_t(struct client_command_context *cmd);
+
+struct command {
+ const char *name;
+ command_func_t *func;
+};
+
+/* Register command. Given name parameter must be permanently stored until
+ command is unregistered. */
+void command_register(const char *name, command_func_t *func);
+void command_unregister(const char *name);
+
+/* Register array of commands. */
+void command_register_array(const struct command *cmdarr, unsigned int count);
+void command_unregister_array(const struct command *cmdarr, unsigned int count);
+
+struct command *command_find(const char *name);
+
+void commands_init(void);
+void commands_deinit(void);
+
+/* MANAGESIEVE commands: */
+
+/* Non-Authenticated State */
+extern bool cmd_logout(struct client_command_context *cmd);
+extern bool cmd_capability(struct client_command_context *cmd);
+extern bool cmd_noop(struct client_command_context *cmd);
+
+/* Authenticated State */
+extern bool cmd_putscript(struct client_command_context *cmd);
+extern bool cmd_checkscript(struct client_command_context *cmd);
+extern bool cmd_getscript(struct client_command_context *cmd);
+extern bool cmd_setactive(struct client_command_context *cmd);
+extern bool cmd_deletescript(struct client_command_context *cmd);
+extern bool cmd_listscripts(struct client_command_context *cmd);
+extern bool cmd_havespace(struct client_command_context *cmd);
+extern bool cmd_renamescript(struct client_command_context *cmd);
+
+#endif
diff --git a/pigeonhole/src/managesieve/managesieve-common.h b/pigeonhole/src/managesieve/managesieve-common.h
new file mode 100644
index 0000000..e1df589
--- /dev/null
+++ b/pigeonhole/src/managesieve/managesieve-common.h
@@ -0,0 +1,31 @@
+#ifndef MANAGESIEVE_COMMON_H
+#define MANAGESIEVE_COMMON_H
+
+#include "pigeonhole-config.h"
+
+/* Disconnect client after idling this many milliseconds */
+#define CLIENT_IDLE_TIMEOUT_MSECS (60*30*1000)
+
+/* If we can't send anything to client for this long, disconnect the client */
+#define CLIENT_OUTPUT_TIMEOUT_MSECS (5*60*1000)
+
+/* Stop buffering more data into output stream after this many bytes */
+#define CLIENT_OUTPUT_OPTIMAL_SIZE 2048
+
+/* Disconnect client when it sends too many bad commands in a row */
+#define CLIENT_MAX_BAD_COMMANDS 20
+
+#define CRITICAL_MSG \
+ "Internal error occurred. Refer to server log for more information."
+#define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]"
+
+#include "lib.h"
+#include "managesieve-client.h"
+#include "managesieve-settings.h"
+
+extern void (*hook_client_created)(struct client **client);
+extern struct event_category event_category_managesieve;
+
+void managesieve_refresh_proctitle(void);
+
+#endif
diff --git a/pigeonhole/src/managesieve/managesieve-quota.c b/pigeonhole/src/managesieve/managesieve-quota.c
new file mode 100644
index 0000000..07b58ca
--- /dev/null
+++ b/pigeonhole/src/managesieve/managesieve-quota.c
@@ -0,0 +1,98 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "strfuncs.h"
+
+#include "sieve.h"
+#include "sieve-storage.h"
+
+#include "managesieve-client.h"
+#include "managesieve-quota.h"
+
+uint64_t managesieve_quota_max_script_size(struct client *client)
+{
+ return sieve_storage_quota_max_script_size(client->storage);
+}
+
+bool managesieve_quota_check_validsize(struct client_command_context *cmd,
+ size_t size)
+{
+ struct client *client = cmd->client;
+ uint64_t limit;
+
+ if (!sieve_storage_quota_validsize(client->storage, size, &limit)) {
+ const char *error_msg;
+
+ error_msg = t_strdup_printf(
+ "Script is too large (max %llu bytes).",
+ (unsigned long long int)limit);
+
+ struct event_passthrough *e =
+ client_command_create_finish_event(cmd);
+ e_debug(e->event(),
+ "Script size check failed (size %zu bytes): %s",
+ size, error_msg);
+
+ client_send_noresp(client, "QUOTA/MAXSIZE", error_msg);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool managesieve_quota_check_all(struct client_command_context *cmd,
+ const char *scriptname, size_t size)
+{
+ struct client *client = cmd->client;
+ enum sieve_storage_quota quota;
+ uint64_t limit;
+ const char *resp_code = NULL, *error_msg = NULL;
+ int ret;
+
+ ret = sieve_storage_quota_havespace(client->storage, scriptname,
+ size, &quota, &limit);
+ if (ret > 0)
+ return TRUE;
+ if (ret < 0) {
+ client_command_storage_error(
+ cmd, "Failed to check quota for script `%s' "
+ "(size %zu bytes)", scriptname, size);
+ return FALSE;
+ }
+
+ switch (quota) {
+ case SIEVE_STORAGE_QUOTA_MAXSIZE:
+ resp_code = "QUOTA/MAXSIZE";
+ error_msg = t_strdup_printf("Script is too large "
+ "(max %llu bytes).",
+ (unsigned long long int)limit);
+ break;
+ case SIEVE_STORAGE_QUOTA_MAXSCRIPTS:
+ resp_code = "QUOTA/MAXSCRIPTS";
+ error_msg = t_strdup_printf("Script count quota exceeded "
+ "(max %llu scripts).",
+ (unsigned long long int)limit);
+ break;
+ case SIEVE_STORAGE_QUOTA_MAXSTORAGE:
+ resp_code = "QUOTA/MAXSTORAGE";
+ error_msg = t_strdup_printf("Script storage quota exceeded "
+ "(max %llu bytes).",
+ (unsigned long long int)limit);
+ break;
+ default:
+ resp_code = "QUOTA";
+ error_msg = "Quota exceeded.";
+ }
+
+ struct event_passthrough *e =
+ client_command_create_finish_event(cmd)->
+ add_str("error", error_msg);
+ e_debug(e->event(),
+ "Quota check failed for script `%s' (size %zu bytes): %s",
+ scriptname, size, error_msg);
+
+ client_send_noresp(client, resp_code, error_msg);
+
+ return FALSE;
+}
+
diff --git a/pigeonhole/src/managesieve/managesieve-quota.h b/pigeonhole/src/managesieve/managesieve-quota.h
new file mode 100644
index 0000000..f6b37bf
--- /dev/null
+++ b/pigeonhole/src/managesieve/managesieve-quota.h
@@ -0,0 +1,11 @@
+#ifndef MANAGESIEVE_QUOTA_H
+#define MANAGESIEVE_QUOTA_H
+
+uint64_t managesieve_quota_max_script_size(struct client *client);
+
+bool managesieve_quota_check_validsize(struct client_command_context *cmd,
+ size_t size);
+bool managesieve_quota_check_all(struct client_command_context *cmd,
+ const char *scriptname, size_t size);
+
+#endif
diff --git a/pigeonhole/src/managesieve/managesieve-settings.c b/pigeonhole/src/managesieve/managesieve-settings.c
new file mode 100644
index 0000000..8e6e88b
--- /dev/null
+++ b/pigeonhole/src/managesieve/managesieve-settings.c
@@ -0,0 +1,170 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "buffer.h"
+#include "settings-parser.h"
+#include "service-settings.h"
+#include "mail-storage-settings.h"
+
+#include "pigeonhole-config.h"
+
+#include "managesieve-settings.h"
+
+#include <stddef.h>
+#include <unistd.h>
+
+static bool managesieve_settings_verify(void *_set, pool_t pool,
+ const char **error_r);
+
+/* <settings checks> */
+static struct file_listener_settings managesieve_unix_listeners_array[] = {
+ { "login/sieve", 0666, "", "" }
+};
+static struct file_listener_settings *managesieve_unix_listeners[] = {
+ &managesieve_unix_listeners_array[0]
+};
+static buffer_t managesieve_unix_listeners_buf = {
+ { { managesieve_unix_listeners, sizeof(managesieve_unix_listeners) } }
+};
+/* </settings checks> */
+
+struct service_settings managesieve_settings_service_settings = {
+ .name = "managesieve",
+ .protocol = "sieve",
+ .type = "",
+ .executable = "managesieve",
+ .user = "",
+ .group = "",
+ .privileged_group = "",
+ .extra_groups = "",
+ .chroot = "",
+
+ .drop_priv_before_exec = FALSE,
+
+ .process_min_avail = 0,
+ .process_limit = 0,
+ .client_limit = 1,
+ .service_count = 1,
+ .idle_kill = 0,
+ .vsz_limit = (uoff_t)-1,
+
+ .unix_listeners = { { &managesieve_unix_listeners_buf,
+ sizeof(managesieve_unix_listeners[0]) } },
+ .fifo_listeners = ARRAY_INIT,
+ .inet_listeners = ARRAY_INIT
+};
+
+#undef DEF
+#define DEF(type, name) \
+ SETTING_DEFINE_STRUCT_##type(#name, name, struct managesieve_settings)
+
+static struct setting_define managesieve_setting_defines[] = {
+ DEF(BOOL, mail_debug),
+ DEF(BOOL, verbose_proctitle),
+ DEF(STR_VARS, rawlog_dir),
+
+ DEF(SIZE, managesieve_max_line_length),
+ DEF(STR, managesieve_implementation_string),
+ DEF(STR, managesieve_client_workarounds),
+ DEF(STR, managesieve_logout_format),
+ DEF(UINT, managesieve_max_compile_errors),
+
+
+ SETTING_DEFINE_LIST_END
+};
+
+static struct managesieve_settings managesieve_default_settings = {
+ .mail_debug = FALSE,
+ .verbose_proctitle = FALSE,
+ .rawlog_dir = "",
+
+ /* RFC-2683 recommends at least 8000 bytes. Some clients however don't
+ break large message sets to multiple commands, so we're pretty
+ liberal by default. */
+ .managesieve_max_line_length = 65536,
+ .managesieve_implementation_string = DOVECOT_NAME " " PIGEONHOLE_NAME,
+ .managesieve_client_workarounds = "",
+ .managesieve_logout_format = "bytes=%i/%o",
+ .managesieve_max_compile_errors = 5
+};
+
+static const struct setting_parser_info *managesieve_setting_dependencies[] = {
+ &mail_user_setting_parser_info,
+ NULL
+};
+
+const struct setting_parser_info managesieve_setting_parser_info = {
+ .module_name = "managesieve",
+ .defines = managesieve_setting_defines,
+ .defaults = &managesieve_default_settings,
+
+ .type_offset = (size_t)-1,
+ .struct_size = sizeof(struct managesieve_settings),
+
+ .parent_offset = (size_t)-1,
+ .parent = NULL,
+
+ .check_func = managesieve_settings_verify,
+ .dependencies = managesieve_setting_dependencies
+};
+
+const struct setting_parser_info *managesieve_settings_set_roots[] = {
+ &managesieve_setting_parser_info,
+ NULL
+};
+
+/* <settings checks> */
+struct managesieve_client_workaround_list {
+ const char *name;
+ enum managesieve_client_workarounds num;
+};
+
+static const struct managesieve_client_workaround_list
+managesieve_client_workaround_list[] = {
+ { NULL, 0 }
+};
+
+static int
+managesieve_settings_parse_workarounds(struct managesieve_settings *set,
+ const char **error_r)
+{
+ enum managesieve_client_workarounds client_workarounds = 0;
+ const struct managesieve_client_workaround_list *list;
+ const char *const *str;
+
+ str = t_strsplit_spaces(set->managesieve_client_workarounds, " ,");
+ for (; *str != NULL; str++) {
+ list = managesieve_client_workaround_list;
+ for (; list->name != NULL; list++) {
+ if (strcasecmp(*str, list->name) == 0) {
+ client_workarounds |= list->num;
+ break;
+ }
+ }
+ if (list->name == NULL) {
+ *error_r = t_strdup_printf(
+ "managesieve_client_workarounds: "
+ "Unknown workaround: %s", *str);
+ return -1;
+ }
+ }
+ set->parsed_workarounds = client_workarounds;
+ return 0;
+}
+
+
+static bool
+managesieve_settings_verify(void *_set, pool_t pool ATTR_UNUSED,
+ const char **error_r)
+{
+ struct managesieve_settings *set = _set;
+
+ if (managesieve_settings_parse_workarounds(set, error_r) < 0)
+ return FALSE;
+ return TRUE;
+}
+
+/* </settings checks> */
+
+const char *managesieve_settings_version = DOVECOT_ABI_VERSION;
diff --git a/pigeonhole/src/managesieve/managesieve-settings.h b/pigeonhole/src/managesieve/managesieve-settings.h
new file mode 100644
index 0000000..a72338b
--- /dev/null
+++ b/pigeonhole/src/managesieve/managesieve-settings.h
@@ -0,0 +1,29 @@
+#ifndef MANAGESIEVE_SETTINGS_H
+#define MANAGESIEVE_SETTINGS_H
+
+struct mail_user_settings;
+
+/* <settings checks> */
+enum managesieve_client_workarounds {
+ WORKAROUND_NONE = 0x00
+};
+/* </settings checks> */
+
+struct managesieve_settings {
+ bool mail_debug;
+ bool verbose_proctitle;
+ const char *rawlog_dir;
+
+ /* managesieve: */
+ uoff_t managesieve_max_line_length;
+ const char *managesieve_implementation_string;
+ const char *managesieve_client_workarounds;
+ const char *managesieve_logout_format;
+ unsigned int managesieve_max_compile_errors;
+
+ enum managesieve_client_workarounds parsed_workarounds;
+};
+
+extern const struct setting_parser_info managesieve_setting_parser_info;
+
+#endif
diff --git a/pigeonhole/src/plugins/Makefile.am b/pigeonhole/src/plugins/Makefile.am
new file mode 100644
index 0000000..b6c7551
--- /dev/null
+++ b/pigeonhole/src/plugins/Makefile.am
@@ -0,0 +1,7 @@
+SUBDIRS = \
+ doveadm-sieve \
+ lda-sieve \
+ sieve-extprograms \
+ imapsieve \
+ imap-filter-sieve \
+ settings
diff --git a/pigeonhole/src/plugins/Makefile.in b/pigeonhole/src/plugins/Makefile.in
new file mode 100644
index 0000000..890ce14
--- /dev/null
+++ b/pigeonhole/src/plugins/Makefile.in
@@ -0,0 +1,699 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/plugins
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = \
+ doveadm-sieve \
+ lda-sieve \
+ sieve-extprograms \
+ imapsieve \
+ imap-filter-sieve \
+ settings
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/plugins/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/plugins/doveadm-sieve/Makefile.am b/pigeonhole/src/plugins/doveadm-sieve/Makefile.am
new file mode 100644
index 0000000..9f98dab
--- /dev/null
+++ b/pigeonhole/src/plugins/doveadm-sieve/Makefile.am
@@ -0,0 +1,31 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib-sieve \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_STORAGE_INCLUDE) \
+ $(LIBDOVECOT_DOVEADM_INCLUDE)
+
+doveadm_moduledir = $(dovecot_moduledir)/doveadm
+lib10_doveadm_sieve_plugin_la_LDFLAGS = -module -avoid-version
+
+doveadm_module_LTLIBRARIES = lib10_doveadm_sieve_plugin.la
+
+lib10_doveadm_sieve_plugin_la_LIBADD = \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la
+
+commands = \
+ doveadm-sieve-cmd-list.c \
+ doveadm-sieve-cmd-get.c \
+ doveadm-sieve-cmd-put.c \
+ doveadm-sieve-cmd-delete.c \
+ doveadm-sieve-cmd-activate.c \
+ doveadm-sieve-cmd-rename.c
+
+lib10_doveadm_sieve_plugin_la_SOURCES = \
+ $(commands) \
+ doveadm-sieve-cmd.c \
+ doveadm-sieve-sync.c \
+ doveadm-sieve-plugin.c
+
+noinst_HEADERS = \
+ doveadm-sieve-cmd.h \
+ doveadm-sieve-plugin.h
diff --git a/pigeonhole/src/plugins/doveadm-sieve/Makefile.in b/pigeonhole/src/plugins/doveadm-sieve/Makefile.in
new file mode 100644
index 0000000..be3b853
--- /dev/null
+++ b/pigeonhole/src/plugins/doveadm-sieve/Makefile.in
@@ -0,0 +1,796 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/plugins/doveadm-sieve
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(doveadm_moduledir)"
+LTLIBRARIES = $(doveadm_module_LTLIBRARIES)
+lib10_doveadm_sieve_plugin_la_DEPENDENCIES = \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la
+am__objects_1 = doveadm-sieve-cmd-list.lo doveadm-sieve-cmd-get.lo \
+ doveadm-sieve-cmd-put.lo doveadm-sieve-cmd-delete.lo \
+ doveadm-sieve-cmd-activate.lo doveadm-sieve-cmd-rename.lo
+am_lib10_doveadm_sieve_plugin_la_OBJECTS = $(am__objects_1) \
+ doveadm-sieve-cmd.lo doveadm-sieve-sync.lo \
+ doveadm-sieve-plugin.lo
+lib10_doveadm_sieve_plugin_la_OBJECTS = \
+ $(am_lib10_doveadm_sieve_plugin_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+lib10_doveadm_sieve_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) \
+ $(lib10_doveadm_sieve_plugin_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/doveadm-sieve-cmd-activate.Plo \
+ ./$(DEPDIR)/doveadm-sieve-cmd-delete.Plo \
+ ./$(DEPDIR)/doveadm-sieve-cmd-get.Plo \
+ ./$(DEPDIR)/doveadm-sieve-cmd-list.Plo \
+ ./$(DEPDIR)/doveadm-sieve-cmd-put.Plo \
+ ./$(DEPDIR)/doveadm-sieve-cmd-rename.Plo \
+ ./$(DEPDIR)/doveadm-sieve-cmd.Plo \
+ ./$(DEPDIR)/doveadm-sieve-plugin.Plo \
+ ./$(DEPDIR)/doveadm-sieve-sync.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(lib10_doveadm_sieve_plugin_la_SOURCES)
+DIST_SOURCES = $(lib10_doveadm_sieve_plugin_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib-sieve \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_STORAGE_INCLUDE) \
+ $(LIBDOVECOT_DOVEADM_INCLUDE)
+
+doveadm_moduledir = $(dovecot_moduledir)/doveadm
+lib10_doveadm_sieve_plugin_la_LDFLAGS = -module -avoid-version
+doveadm_module_LTLIBRARIES = lib10_doveadm_sieve_plugin.la
+lib10_doveadm_sieve_plugin_la_LIBADD = \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la
+
+commands = \
+ doveadm-sieve-cmd-list.c \
+ doveadm-sieve-cmd-get.c \
+ doveadm-sieve-cmd-put.c \
+ doveadm-sieve-cmd-delete.c \
+ doveadm-sieve-cmd-activate.c \
+ doveadm-sieve-cmd-rename.c
+
+lib10_doveadm_sieve_plugin_la_SOURCES = \
+ $(commands) \
+ doveadm-sieve-cmd.c \
+ doveadm-sieve-sync.c \
+ doveadm-sieve-plugin.c
+
+noinst_HEADERS = \
+ doveadm-sieve-cmd.h \
+ doveadm-sieve-plugin.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/doveadm-sieve/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/plugins/doveadm-sieve/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-doveadm_moduleLTLIBRARIES: $(doveadm_module_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(doveadm_module_LTLIBRARIES)'; test -n "$(doveadm_moduledir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(doveadm_moduledir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(doveadm_moduledir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(doveadm_moduledir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(doveadm_moduledir)"; \
+ }
+
+uninstall-doveadm_moduleLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(doveadm_module_LTLIBRARIES)'; test -n "$(doveadm_moduledir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(doveadm_moduledir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(doveadm_moduledir)/$$f"; \
+ done
+
+clean-doveadm_moduleLTLIBRARIES:
+ -test -z "$(doveadm_module_LTLIBRARIES)" || rm -f $(doveadm_module_LTLIBRARIES)
+ @list='$(doveadm_module_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+lib10_doveadm_sieve_plugin.la: $(lib10_doveadm_sieve_plugin_la_OBJECTS) $(lib10_doveadm_sieve_plugin_la_DEPENDENCIES) $(EXTRA_lib10_doveadm_sieve_plugin_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(lib10_doveadm_sieve_plugin_la_LINK) -rpath $(doveadm_moduledir) $(lib10_doveadm_sieve_plugin_la_OBJECTS) $(lib10_doveadm_sieve_plugin_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-cmd-activate.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-cmd-delete.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-cmd-get.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-cmd-list.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-cmd-put.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-cmd-rename.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-cmd.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-plugin.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-sync.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(doveadm_moduledir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-doveadm_moduleLTLIBRARIES clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-activate.Plo
+ -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-delete.Plo
+ -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-get.Plo
+ -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-list.Plo
+ -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-put.Plo
+ -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-rename.Plo
+ -rm -f ./$(DEPDIR)/doveadm-sieve-cmd.Plo
+ -rm -f ./$(DEPDIR)/doveadm-sieve-plugin.Plo
+ -rm -f ./$(DEPDIR)/doveadm-sieve-sync.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-doveadm_moduleLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-activate.Plo
+ -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-delete.Plo
+ -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-get.Plo
+ -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-list.Plo
+ -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-put.Plo
+ -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-rename.Plo
+ -rm -f ./$(DEPDIR)/doveadm-sieve-cmd.Plo
+ -rm -f ./$(DEPDIR)/doveadm-sieve-plugin.Plo
+ -rm -f ./$(DEPDIR)/doveadm-sieve-sync.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-doveadm_moduleLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-doveadm_moduleLTLIBRARIES clean-generic clean-libtool \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-doveadm_moduleLTLIBRARIES \
+ install-dvi install-dvi-am install-exec install-exec-am \
+ install-html install-html-am install-info install-info-am \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-doveadm_moduleLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-activate.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-activate.c
new file mode 100644
index 0000000..f392478
--- /dev/null
+++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-activate.c
@@ -0,0 +1,145 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "doveadm-mail.h"
+
+#include "sieve.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+
+#include "doveadm-sieve-cmd.h"
+
+struct doveadm_sieve_activate_cmd_context {
+ struct doveadm_sieve_cmd_context ctx;
+
+ const char *scriptname;
+};
+
+static int
+cmd_sieve_activate_run(struct doveadm_sieve_cmd_context *_ctx)
+{
+ struct doveadm_sieve_activate_cmd_context *ctx =
+ (struct doveadm_sieve_activate_cmd_context *)_ctx;
+ struct sieve_storage *storage = _ctx->storage;
+ struct sieve_script *script;
+ enum sieve_error error;
+ int ret = 0;
+
+ script = sieve_storage_open_script
+ (storage, ctx->scriptname, NULL);
+ if ( script == NULL ) {
+ i_error("Failed to activate Sieve script: %s",
+ sieve_storage_get_last_error(storage, &error));
+ doveadm_sieve_cmd_failed_error(_ctx, error);
+ return -1;
+ }
+
+ if ( sieve_script_is_active(script) <= 0 ) {
+ /* Script is first being activated; compile it again without the UPLOAD
+ * flag.
+ */
+ struct sieve_error_handler *ehandler;
+ enum sieve_compile_flags cpflags =
+ SIEVE_COMPILE_FLAG_NOGLOBAL | SIEVE_COMPILE_FLAG_ACTIVATED;
+ struct sieve_binary *sbin;
+ enum sieve_error error;
+
+ /* Compile */
+ ehandler = sieve_master_ehandler_create(ctx->ctx.svinst, 0);
+ if ( (sbin=sieve_compile_script
+ (script, ehandler, cpflags, &error)) == NULL ) {
+ doveadm_sieve_cmd_failed_error(_ctx, error);
+ ret = -1;
+ } else {
+ sieve_close(&sbin);
+ }
+ sieve_error_handler_unref(&ehandler);
+ }
+
+ /* Activate only when script is valid (or already active) */
+ if ( ret == 0 ) {
+ /* Refresh activation no matter what; this can also resolve some erroneous
+ * situations.
+ */
+ ret = sieve_script_activate(script, (time_t)-1);
+ if ( ret < 0 ) {
+ i_error("Failed to activate Sieve script: %s",
+ sieve_storage_get_last_error(storage, &error));
+ doveadm_sieve_cmd_failed_error(_ctx, error);
+ ret = -1;
+ }
+ }
+
+ sieve_script_unref(&script);
+ return ret;
+}
+
+static int cmd_sieve_deactivate_run
+(struct doveadm_sieve_cmd_context *_ctx)
+{
+ struct sieve_storage *storage = _ctx->storage;
+ enum sieve_error error;
+
+ if (sieve_storage_deactivate(storage, (time_t)-1) < 0) {
+ i_error("Failed to deactivate Sieve script: %s",
+ sieve_storage_get_last_error(storage, &error));
+ doveadm_sieve_cmd_failed_error(_ctx, error);
+ return -1;
+ }
+ return 0;
+}
+
+static void cmd_sieve_activate_init
+(struct doveadm_mail_cmd_context *_ctx,
+ const char *const args[])
+{
+ struct doveadm_sieve_activate_cmd_context *ctx =
+ (struct doveadm_sieve_activate_cmd_context *)_ctx;
+
+ if (str_array_length(args) != 1)
+ doveadm_mail_help_name("sieve activate");
+ doveadm_sieve_cmd_scriptnames_check(args);
+
+ ctx->scriptname = p_strdup(ctx->ctx.ctx.pool, args[0]);
+}
+
+static struct doveadm_mail_cmd_context *
+cmd_sieve_activate_alloc(void)
+{
+ struct doveadm_sieve_activate_cmd_context *ctx;
+
+ ctx = doveadm_sieve_cmd_alloc(struct doveadm_sieve_activate_cmd_context);
+ ctx->ctx.ctx.v.init = cmd_sieve_activate_init;
+ ctx->ctx.v.run = cmd_sieve_activate_run;
+ return &ctx->ctx.ctx;
+}
+
+static struct doveadm_mail_cmd_context *
+cmd_sieve_deactivate_alloc(void)
+{
+ struct doveadm_sieve_cmd_context *ctx;
+
+ ctx = doveadm_sieve_cmd_alloc(struct doveadm_sieve_cmd_context);
+ ctx->v.run = cmd_sieve_deactivate_run;
+ return &ctx->ctx;
+}
+
+struct doveadm_cmd_ver2 doveadm_sieve_cmd_activate = {
+ .name = "sieve activate",
+ .mail_cmd = cmd_sieve_activate_alloc,
+ .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"<scriptname>",
+DOVEADM_CMD_PARAMS_START
+DOVEADM_CMD_MAIL_COMMON
+DOVEADM_CMD_PARAM('\0',"scriptname",CMD_PARAM_STR,CMD_PARAM_FLAG_POSITIONAL)
+DOVEADM_CMD_PARAMS_END
+};
+
+struct doveadm_cmd_ver2 doveadm_sieve_cmd_deactivate = {
+ .name = "sieve deactivate",
+ .mail_cmd = cmd_sieve_deactivate_alloc,
+ .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX,
+DOVEADM_CMD_PARAMS_START
+DOVEADM_CMD_MAIL_COMMON
+DOVEADM_CMD_PARAMS_END
+};
diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-delete.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-delete.c
new file mode 100644
index 0000000..8517abd
--- /dev/null
+++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-delete.c
@@ -0,0 +1,116 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "doveadm-mail.h"
+
+#include "sieve.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+
+#include "doveadm-sieve-cmd.h"
+
+struct doveadm_sieve_delete_cmd_context {
+ struct doveadm_sieve_cmd_context ctx;
+
+ ARRAY_TYPE(const_string) scriptnames;
+ bool ignore_active:1;
+};
+
+static int
+cmd_sieve_delete_run(struct doveadm_sieve_cmd_context *_ctx)
+{
+ struct doveadm_sieve_delete_cmd_context *ctx =
+ (struct doveadm_sieve_delete_cmd_context *)_ctx;
+ struct sieve_storage *storage = _ctx->storage;
+ const ARRAY_TYPE(const_string) *scriptnames = &ctx->scriptnames;
+ const char *scriptname;
+ struct sieve_script *script;
+ enum sieve_error error;
+ int ret = 0;
+
+ array_foreach_elem(scriptnames, scriptname) {
+ int sret = 0;
+
+ script = sieve_storage_open_script
+ (storage, scriptname, NULL);
+ if (script == NULL) {
+ sret = -1;
+ } else {
+ if (sieve_script_delete(script, ctx->ignore_active) < 0) {
+ (void)sieve_storage_get_last_error(storage, &error);
+ sret = -1;
+ }
+ sieve_script_unref(&script);
+ }
+
+ if (sret < 0) {
+ i_error("Failed to delete Sieve script: %s",
+ sieve_storage_get_last_error(storage, &error));
+ doveadm_sieve_cmd_failed_error(_ctx, error);
+ ret = -1;
+ }
+ }
+ return ret;
+}
+
+static void cmd_sieve_delete_init
+(struct doveadm_mail_cmd_context *_ctx,
+ const char *const args[])
+{
+ struct doveadm_sieve_delete_cmd_context *ctx =
+ (struct doveadm_sieve_delete_cmd_context *)_ctx;
+ const char *name;
+ unsigned int i;
+
+ if (args[0] == NULL)
+ doveadm_mail_help_name("sieve delete");
+ doveadm_sieve_cmd_scriptnames_check(args);
+
+ for (i = 0; args[i] != NULL; i++) {
+ name = p_strdup(ctx->ctx.ctx.pool, args[i]);
+ array_append(&ctx->scriptnames, &name, 1);
+ }
+}
+
+static bool
+cmd_sieve_delete_parse_arg(struct doveadm_mail_cmd_context *_ctx, int c)
+{
+ struct doveadm_sieve_delete_cmd_context *ctx =
+ (struct doveadm_sieve_delete_cmd_context *)_ctx;
+
+ switch ( c ) {
+ case 'a':
+ ctx->ignore_active = TRUE;
+ break;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static struct doveadm_mail_cmd_context *
+cmd_sieve_delete_alloc(void)
+{
+ struct doveadm_sieve_delete_cmd_context *ctx;
+
+ ctx = doveadm_sieve_cmd_alloc(struct doveadm_sieve_delete_cmd_context);
+ ctx->ctx.ctx.getopt_args = "a";
+ ctx->ctx.ctx.v.parse_arg = cmd_sieve_delete_parse_arg;
+ ctx->ctx.ctx.v.init = cmd_sieve_delete_init;
+ ctx->ctx.v.run = cmd_sieve_delete_run;
+ p_array_init(&ctx->scriptnames, ctx->ctx.ctx.pool, 16);
+ return &ctx->ctx.ctx;
+}
+
+struct doveadm_cmd_ver2 doveadm_sieve_cmd_delete = {
+ .name = "sieve delete",
+ .mail_cmd = cmd_sieve_delete_alloc,
+ .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"[-a] <scriptname> [...]",
+DOVEADM_CMD_PARAMS_START
+DOVEADM_CMD_MAIL_COMMON
+DOVEADM_CMD_PARAM('a',"ignore-active",CMD_PARAM_BOOL,0)
+DOVEADM_CMD_PARAM('\0',"scriptname",CMD_PARAM_ARRAY,CMD_PARAM_FLAG_POSITIONAL)
+DOVEADM_CMD_PARAMS_END
+};
diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-get.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-get.c
new file mode 100644
index 0000000..e1bf7e3
--- /dev/null
+++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-get.c
@@ -0,0 +1,83 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "doveadm-print.h"
+#include "doveadm-mail.h"
+
+#include "sieve.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+
+#include "doveadm-sieve-cmd.h"
+
+struct doveadm_sieve_get_cmd_context {
+ struct doveadm_sieve_cmd_context ctx;
+
+ const char *scriptname;
+};
+
+static int
+cmd_sieve_get_run(struct doveadm_sieve_cmd_context *_ctx)
+{
+ struct doveadm_sieve_get_cmd_context *ctx =
+ (struct doveadm_sieve_get_cmd_context *)_ctx;
+ struct sieve_script *script;
+ struct istream *input;
+ enum sieve_error error;
+ int ret;
+
+ script = sieve_storage_open_script
+ (_ctx->storage, ctx->scriptname, &error);
+ if ( script == NULL || sieve_script_get_stream
+ (script, &input, &error) < 0 ) {
+ i_error("Failed to open Sieve script: %s",
+ sieve_storage_get_last_error(_ctx->storage, &error));
+ doveadm_sieve_cmd_failed_error(_ctx, error);
+ if (script != NULL)
+ sieve_script_unref(&script);
+ return -1;
+ }
+
+ ret = doveadm_print_istream(input);
+ sieve_script_unref(&script);
+ return ret;
+}
+
+static void cmd_sieve_get_init
+(struct doveadm_mail_cmd_context *_ctx,
+ const char *const args[])
+{
+ struct doveadm_sieve_get_cmd_context *ctx =
+ (struct doveadm_sieve_get_cmd_context *)_ctx;
+
+ if ( str_array_length(args) != 1 )
+ doveadm_mail_help_name("sieve get");
+ doveadm_sieve_cmd_scriptnames_check(args);
+
+ ctx->scriptname = p_strdup(ctx->ctx.ctx.pool, args[0]);
+
+ doveadm_print_header_simple("sieve script");
+}
+
+static struct doveadm_mail_cmd_context *
+cmd_sieve_get_alloc(void)
+{
+ struct doveadm_sieve_get_cmd_context *ctx;
+
+ ctx = doveadm_sieve_cmd_alloc(struct doveadm_sieve_get_cmd_context);
+ ctx->ctx.ctx.v.init = cmd_sieve_get_init;
+ ctx->ctx.v.run = cmd_sieve_get_run;
+ doveadm_print_init("pager");
+ return &ctx->ctx.ctx;
+}
+
+struct doveadm_cmd_ver2 doveadm_sieve_cmd_get = {
+ .name = "sieve get",
+ .mail_cmd = cmd_sieve_get_alloc,
+ .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"<scriptname>",
+DOVEADM_CMD_PARAMS_START
+DOVEADM_CMD_MAIL_COMMON
+DOVEADM_CMD_PARAM('\0',"scriptname",CMD_PARAM_STR,CMD_PARAM_FLAG_POSITIONAL)
+DOVEADM_CMD_PARAMS_END
+};
diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-list.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-list.c
new file mode 100644
index 0000000..0dbf379
--- /dev/null
+++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-list.c
@@ -0,0 +1,79 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "doveadm-print.h"
+#include "doveadm-mail.h"
+
+#include "sieve.h"
+#include "sieve-storage.h"
+
+#include "doveadm-sieve-cmd.h"
+
+static int
+cmd_sieve_list_run(struct doveadm_sieve_cmd_context *_ctx)
+{
+ struct sieve_storage *storage = _ctx->storage;
+ struct sieve_storage_list_context *lctx;
+ enum sieve_error error;
+ const char *scriptname;
+ bool active;
+
+ if ( (lctx = sieve_storage_list_init(storage))
+ == NULL ) {
+ i_error("Listing Sieve scripts failed: %s",
+ sieve_storage_get_last_error(storage, &error));
+ doveadm_sieve_cmd_failed_error(_ctx, error);
+ return -1;
+ }
+
+ while ( (scriptname=sieve_storage_list_next(lctx, &active))
+ != NULL ) {
+ doveadm_print(scriptname);
+ if ( active )
+ doveadm_print("ACTIVE");
+ else
+ doveadm_print("");
+ }
+
+ if ( sieve_storage_list_deinit(&lctx) < 0 ) {
+ i_error("Listing Sieve scripts failed: %s",
+ sieve_storage_get_last_error(storage, &error));
+ doveadm_sieve_cmd_failed_error(_ctx, error);
+ return -1;
+ }
+ return 0;
+}
+
+static void cmd_sieve_list_init
+(struct doveadm_mail_cmd_context *_ctx ATTR_UNUSED,
+ const char *const args[] ATTR_UNUSED)
+{
+ doveadm_print_header("script", "script",
+ DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE);
+ doveadm_print_header("active", "active",
+ DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE);
+}
+
+static struct doveadm_mail_cmd_context *
+cmd_sieve_list_alloc(void)
+{
+ struct doveadm_sieve_cmd_context *ctx;
+
+ ctx = doveadm_sieve_cmd_alloc(struct doveadm_sieve_cmd_context);
+ ctx->ctx.v.init = cmd_sieve_list_init;
+ ctx->ctx.getopt_args = "s";
+ ctx->v.run = cmd_sieve_list_run;
+ doveadm_print_init(DOVEADM_PRINT_TYPE_FLOW);
+ return &ctx->ctx;
+}
+
+struct doveadm_cmd_ver2 doveadm_sieve_cmd_list = {
+ .name = "sieve list",
+ .mail_cmd = cmd_sieve_list_alloc,
+ .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX,
+DOVEADM_CMD_PARAMS_START
+DOVEADM_CMD_MAIL_COMMON
+DOVEADM_CMD_PARAMS_END
+};
+
diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-put.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-put.c
new file mode 100644
index 0000000..ef9472d
--- /dev/null
+++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-put.c
@@ -0,0 +1,189 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "istream.h"
+#include "doveadm-mail.h"
+
+#include "sieve.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+
+#include "doveadm-sieve-cmd.h"
+
+struct doveadm_sieve_put_cmd_context {
+ struct doveadm_sieve_cmd_context ctx;
+
+ const char *scriptname;
+
+ bool activate:1;
+};
+
+static int cmd_sieve_put_run
+(struct doveadm_sieve_cmd_context *_ctx)
+{
+ struct doveadm_sieve_put_cmd_context *ctx =
+ (struct doveadm_sieve_put_cmd_context *)_ctx;
+ struct sieve_storage_save_context *save_ctx;
+ struct sieve_storage *storage = _ctx->storage;
+ struct istream *input = _ctx->ctx.cmd_input;
+ enum sieve_error error;
+ ssize_t ret;
+ bool save_failed = FALSE;
+
+ save_ctx = sieve_storage_save_init
+ (storage, ctx->scriptname, input);
+ if ( save_ctx == NULL ) {
+ i_error("Saving failed: %s",
+ sieve_storage_get_last_error(storage, &error));
+ doveadm_sieve_cmd_failed_error(_ctx, error);
+ return -1;
+ }
+
+ while ( (ret = i_stream_read(input)) > 0 || ret == -2 ) {
+ if ( sieve_storage_save_continue(save_ctx) < 0 ) {
+ save_failed = TRUE;
+ ret = -1;
+ break;
+ }
+ }
+ i_assert(ret == -1);
+
+ if ( input->stream_errno != 0 ) {
+ i_error("read(script input) failed: %s", i_stream_get_error(input));
+ doveadm_sieve_cmd_failed_error
+ (&ctx->ctx, SIEVE_ERROR_TEMP_FAILURE);
+ } else if ( save_failed ) {
+ i_error("Saving failed: %s",
+ sieve_storage_get_last_error(storage, NULL));
+ doveadm_sieve_cmd_failed_storage(&ctx->ctx, storage);
+ } else if ( sieve_storage_save_finish(save_ctx) < 0 ) {
+ i_error("Saving failed: %s",
+ sieve_storage_get_last_error(storage, NULL));
+ doveadm_sieve_cmd_failed_storage(&ctx->ctx, storage);
+ } else {
+ ret = 0;
+ }
+
+ /* Verify that script compiles */
+ if ( ret == 0 ) {
+ struct sieve_error_handler *ehandler;
+ enum sieve_compile_flags cpflags =
+ SIEVE_COMPILE_FLAG_NOGLOBAL | SIEVE_COMPILE_FLAG_UPLOADED;
+ struct sieve_script *script;
+ struct sieve_binary *sbin;
+
+ /* Obtain script object for uploaded script */
+ script = sieve_storage_save_get_tempscript(save_ctx);
+
+ /* Check result */
+ if ( script == NULL ) {
+ i_error("Saving failed: %s",
+ sieve_storage_get_last_error(storage, &error));
+ doveadm_sieve_cmd_failed_error(_ctx, error);
+ ret = -1;
+
+ } else {
+ /* Mark this as an activation when we are replacing the active script */
+ if ( ctx->activate || sieve_storage_save_will_activate(save_ctx) )
+ cpflags |= SIEVE_COMPILE_FLAG_ACTIVATED;
+
+ /* Compile */
+ ehandler = sieve_master_ehandler_create(ctx->ctx.svinst, 0);
+ if ( (sbin=sieve_compile_script
+ (script, ehandler, cpflags, &error)) == NULL ) {
+ doveadm_sieve_cmd_failed_error(_ctx, error);
+ ret = -1;
+ } else {
+ sieve_close(&sbin);
+
+ /* Script is valid; commit it to storage */
+ ret = sieve_storage_save_commit(&save_ctx);
+ if (ret < 0) {
+ i_error("Saving failed: %s",
+ sieve_storage_get_last_error(storage, &error));
+ doveadm_sieve_cmd_failed_error(_ctx, error);
+ ret = -1;
+ }
+ }
+ sieve_error_handler_unref(&ehandler);
+ }
+ }
+
+ if ( save_ctx != NULL )
+ sieve_storage_save_cancel(&save_ctx);
+
+ if ( ctx->activate && ret == 0 ) {
+ struct sieve_script *script = sieve_storage_open_script
+ (storage, ctx->scriptname, NULL);
+ if ( script == NULL ||
+ sieve_script_activate(script, (time_t)-1) < 0) {
+ i_error("Failed to activate Sieve script: %s",
+ sieve_storage_get_last_error(storage, &error));
+ doveadm_sieve_cmd_failed_error(_ctx, error);
+ ret = -1;
+ }
+ if (script != NULL)
+ sieve_script_unref(&script);
+ }
+
+ i_assert(input->eof);
+ return ret < 0 ? -1 : 0;
+}
+
+static void cmd_sieve_put_init
+(struct doveadm_mail_cmd_context *_ctx,
+ const char *const args[])
+{
+ struct doveadm_sieve_put_cmd_context *ctx =
+ (struct doveadm_sieve_put_cmd_context *)_ctx;
+
+ if ( str_array_length(args) != 1 )
+ doveadm_mail_help_name("sieve put");
+ doveadm_sieve_cmd_scriptnames_check(args);
+
+ ctx->scriptname = p_strdup(ctx->ctx.ctx.pool, args[0]);
+
+ doveadm_mail_get_input(_ctx);
+}
+
+static bool
+cmd_sieve_put_parse_arg(struct doveadm_mail_cmd_context *_ctx, int c)
+{
+ struct doveadm_sieve_put_cmd_context *ctx =
+ (struct doveadm_sieve_put_cmd_context *)_ctx;
+
+ switch ( c ) {
+ case 'a':
+ ctx->activate = TRUE;
+ break;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static struct doveadm_mail_cmd_context *
+cmd_sieve_put_alloc(void)
+{
+ struct doveadm_sieve_put_cmd_context *ctx;
+
+ ctx = doveadm_sieve_cmd_alloc(struct doveadm_sieve_put_cmd_context);
+ ctx->ctx.ctx.getopt_args = "a";
+ ctx->ctx.ctx.v.parse_arg = cmd_sieve_put_parse_arg;
+ ctx->ctx.ctx.v.init = cmd_sieve_put_init;
+ ctx->ctx.v.run = cmd_sieve_put_run;
+ return &ctx->ctx.ctx;
+}
+
+struct doveadm_cmd_ver2 doveadm_sieve_cmd_put = {
+ .name = "sieve put",
+ .mail_cmd = cmd_sieve_put_alloc,
+ .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"[-a] <scriptname>",
+DOVEADM_CMD_PARAMS_START
+DOVEADM_CMD_MAIL_COMMON
+DOVEADM_CMD_PARAM('a',"activate",CMD_PARAM_BOOL,0)
+DOVEADM_CMD_PARAM('\0',"scriptname",CMD_PARAM_STR,CMD_PARAM_FLAG_POSITIONAL)
+DOVEADM_CMD_PARAM('\0',"file",CMD_PARAM_ISTREAM,CMD_PARAM_FLAG_POSITIONAL)
+DOVEADM_CMD_PARAMS_END
+};
diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-rename.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-rename.c
new file mode 100644
index 0000000..3cc53c7
--- /dev/null
+++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-rename.c
@@ -0,0 +1,83 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "doveadm-mail.h"
+
+#include "sieve.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+
+#include "doveadm-sieve-cmd.h"
+
+struct doveadm_sieve_rename_cmd_context {
+ struct doveadm_sieve_cmd_context ctx;
+
+ const char *oldname, *newname;
+};
+
+static int
+cmd_sieve_rename_run(struct doveadm_sieve_cmd_context *_ctx)
+{
+ struct doveadm_sieve_rename_cmd_context *ctx =
+ (struct doveadm_sieve_rename_cmd_context *)_ctx;
+ struct sieve_storage *storage = _ctx->storage;
+ struct sieve_script *script;
+ enum sieve_error error;
+ int ret = 0;
+
+ script = sieve_storage_open_script
+ (storage, ctx->oldname, NULL);
+ if ( script == NULL ) {
+ i_error("Failed to rename Sieve script: %s",
+ sieve_storage_get_last_error(storage, &error));
+ doveadm_sieve_cmd_failed_error(_ctx, error);
+ ret = -1;
+ } else if ( sieve_script_rename(script, ctx->newname) < 0 ) {
+ i_error("Failed to rename Sieve script: %s",
+ sieve_storage_get_last_error(storage, &error));
+ doveadm_sieve_cmd_failed_error(_ctx, error);
+ ret = -1;
+ }
+
+ if ( script != NULL )
+ sieve_script_unref(&script);
+ return ret;
+}
+
+static void cmd_sieve_rename_init
+(struct doveadm_mail_cmd_context *_ctx,
+ const char *const args[])
+{
+ struct doveadm_sieve_rename_cmd_context *ctx =
+ (struct doveadm_sieve_rename_cmd_context *)_ctx;
+
+ if ( str_array_length(args) != 2 )
+ doveadm_mail_help_name("sieve rename");
+ doveadm_sieve_cmd_scriptnames_check(args);
+
+ ctx->oldname = p_strdup(ctx->ctx.ctx.pool, args[0]);
+ ctx->newname = p_strdup(ctx->ctx.ctx.pool, args[1]);
+}
+
+static struct doveadm_mail_cmd_context *
+cmd_sieve_rename_alloc(void)
+{
+ struct doveadm_sieve_rename_cmd_context *ctx;
+
+ ctx = doveadm_sieve_cmd_alloc(struct doveadm_sieve_rename_cmd_context);
+ ctx->ctx.ctx.v.init = cmd_sieve_rename_init;
+ ctx->ctx.v.run = cmd_sieve_rename_run;
+ return &ctx->ctx.ctx;
+}
+
+struct doveadm_cmd_ver2 doveadm_sieve_cmd_rename = {
+ .name = "sieve rename",
+ .mail_cmd = cmd_sieve_rename_alloc,
+ .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"<oldname> <newname>",
+DOVEADM_CMD_PARAMS_START
+DOVEADM_CMD_MAIL_COMMON
+DOVEADM_CMD_PARAM('\0',"oldname",CMD_PARAM_STR,CMD_PARAM_FLAG_POSITIONAL)
+DOVEADM_CMD_PARAM('\0',"newname",CMD_PARAM_STR,CMD_PARAM_FLAG_POSITIONAL)
+DOVEADM_CMD_PARAMS_END
+};
diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd.c
new file mode 100644
index 0000000..eb9318c
--- /dev/null
+++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd.c
@@ -0,0 +1,179 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "unichar.h"
+#include "mail-storage.h"
+#include "doveadm-mail.h"
+
+#include "sieve.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+
+#include "doveadm-sieve-cmd.h"
+
+void doveadm_sieve_cmd_failed_error
+(struct doveadm_sieve_cmd_context *ctx, enum sieve_error error)
+{
+ struct doveadm_mail_cmd_context *mctx = &ctx->ctx;
+ int exit_code = 0;
+
+ switch ( error ) {
+ case SIEVE_ERROR_NONE:
+ i_unreached();
+ return;
+ case SIEVE_ERROR_TEMP_FAILURE:
+ exit_code = EX_TEMPFAIL;
+ break;
+ case SIEVE_ERROR_NOT_POSSIBLE:
+ case SIEVE_ERROR_EXISTS:
+ case SIEVE_ERROR_NOT_VALID:
+ case SIEVE_ERROR_ACTIVE:
+ exit_code = DOVEADM_EX_NOTPOSSIBLE;
+ break;
+ case SIEVE_ERROR_BAD_PARAMS:
+ exit_code = EX_USAGE;
+ break;
+ case SIEVE_ERROR_NO_PERMISSION:
+ exit_code = EX_NOPERM;
+ break;
+ case SIEVE_ERROR_NO_QUOTA:
+ exit_code = EX_CANTCREAT;
+ break;
+ case SIEVE_ERROR_NOT_FOUND:
+ exit_code = DOVEADM_EX_NOTFOUND;
+ break;
+ default:
+ i_unreached();
+ }
+ /* tempfail overrides all other exit codes, otherwise use whatever
+ error happened first */
+ if ( mctx->exit_code == 0 || exit_code == EX_TEMPFAIL )
+ mctx->exit_code = exit_code;
+}
+
+void doveadm_sieve_cmd_failed_storage
+(struct doveadm_sieve_cmd_context *ctx, struct sieve_storage *storage)
+{
+ enum sieve_error error;
+
+ (void)sieve_storage_get_last_error(storage, &error);
+ doveadm_sieve_cmd_failed_error(ctx, error);
+}
+
+static const char *doveadm_sieve_cmd_get_setting
+(void *context, const char *identifier)
+{
+ struct doveadm_sieve_cmd_context *ctx =
+ (struct doveadm_sieve_cmd_context *) context;
+
+ return mail_user_plugin_getenv(ctx->ctx.cur_mail_user, identifier);
+}
+
+static const struct sieve_callbacks sieve_callbacks = {
+ NULL,
+ doveadm_sieve_cmd_get_setting
+};
+
+static bool doveadm_sieve_cmd_parse_arg
+(struct doveadm_mail_cmd_context *_ctx ATTR_UNUSED,
+ int c ATTR_UNUSED)
+{
+ return FALSE;
+}
+
+void doveadm_sieve_cmd_scriptnames_check(const char *const args[])
+{
+ unsigned int i;
+
+ for (i = 0; args[i] != NULL; i++) {
+ if (!uni_utf8_str_is_valid(args[i])) {
+ i_fatal_status(EX_DATAERR,
+ "Sieve script name not valid UTF-8: %s", args[i]);
+ }
+ if ( !sieve_script_name_is_valid(args[i]) ) {
+ i_fatal_status(EX_DATAERR,
+ "Sieve script name not valid: %s", args[i]);
+ }
+ }
+}
+
+static int
+doveadm_sieve_cmd_run
+(struct doveadm_mail_cmd_context *_ctx,
+ struct mail_user *user)
+{
+ struct doveadm_sieve_cmd_context *ctx =
+ (struct doveadm_sieve_cmd_context *)_ctx;
+ struct sieve_environment svenv;
+ enum sieve_error error;
+ int ret;
+
+ memset((void*)&svenv, 0, sizeof(svenv));
+ svenv.username = user->username;
+ (void)mail_user_get_home(user, &svenv.home_dir);
+ svenv.base_dir = user->set->base_dir;
+ svenv.flags = SIEVE_FLAG_HOME_RELATIVE;
+
+ ctx->svinst = sieve_init
+ (&svenv, &sieve_callbacks, (void *)ctx, user->mail_debug);
+
+ ctx->storage = sieve_storage_create_main
+ (ctx->svinst, user, SIEVE_STORAGE_FLAG_READWRITE, &error);
+ if ( ctx->storage == NULL ) {
+ switch ( error ) {
+ case SIEVE_ERROR_NOT_POSSIBLE:
+ error = SIEVE_ERROR_NOT_FOUND;
+ i_error("Failed to open Sieve storage: "
+ "Sieve is disabled for this user");
+ break;
+ case SIEVE_ERROR_NOT_FOUND:
+ i_error("Failed to open Sieve storage: "
+ "User cannot manage personal Sieve scripts.");
+ break;
+ default:
+ i_error("Failed to open Sieve storage.");
+ }
+ doveadm_sieve_cmd_failed_error(ctx, error);
+ ret = -1;
+
+ } else {
+ i_assert( ctx->v.run != NULL );
+ ret = ctx->v.run(ctx);
+ sieve_storage_unref(&ctx->storage);
+ }
+
+ sieve_deinit(&ctx->svinst);
+ return ret;
+}
+
+struct doveadm_sieve_cmd_context *
+doveadm_sieve_cmd_alloc_size(size_t size)
+{
+ struct doveadm_sieve_cmd_context *ctx;
+
+ ctx = (struct doveadm_sieve_cmd_context *)
+ doveadm_mail_cmd_alloc_size(size);
+ ctx->ctx.getopt_args = "s";
+ ctx->ctx.v.parse_arg = doveadm_sieve_cmd_parse_arg;
+ ctx->ctx.v.run = doveadm_sieve_cmd_run;
+ return ctx;
+}
+
+static struct doveadm_cmd_ver2 *doveadm_sieve_commands[] = {
+ &doveadm_sieve_cmd_list,
+ &doveadm_sieve_cmd_get,
+ &doveadm_sieve_cmd_put,
+ &doveadm_sieve_cmd_delete,
+ &doveadm_sieve_cmd_activate,
+ &doveadm_sieve_cmd_deactivate,
+ &doveadm_sieve_cmd_rename
+};
+
+void doveadm_sieve_cmds_init(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < N_ELEMENTS(doveadm_sieve_commands); i++)
+ doveadm_cmd_register_ver2(doveadm_sieve_commands[i]);
+}
diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd.h b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd.h
new file mode 100644
index 0000000..1296701
--- /dev/null
+++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd.h
@@ -0,0 +1,43 @@
+#ifndef DOVEADM_SIEVE_CMD_H
+#define DOVEADM_SIEVE_CMD_H
+
+struct doveadm_sieve_cmd_context;
+
+struct doveadm_sieve_cmd_vfuncs {
+ /* This is the main function which performs all the work for the
+ command. This is called once per each user. */
+ int (*run)(struct doveadm_sieve_cmd_context *ctx);
+};
+
+struct doveadm_sieve_cmd_context {
+ struct doveadm_mail_cmd_context ctx;
+
+ struct sieve_instance *svinst;
+ struct sieve_storage *storage;
+
+ struct doveadm_sieve_cmd_vfuncs v;
+};
+
+void doveadm_sieve_cmd_failed_error
+(struct doveadm_sieve_cmd_context *ctx, enum sieve_error error);
+void doveadm_sieve_cmd_failed_storage
+(struct doveadm_sieve_cmd_context *ctx, struct sieve_storage *storage);
+
+#define doveadm_sieve_cmd_alloc(type) \
+ (type *)doveadm_sieve_cmd_alloc_size(sizeof(type))
+struct doveadm_sieve_cmd_context *
+doveadm_sieve_cmd_alloc_size(size_t size);
+
+void doveadm_sieve_cmd_scriptnames_check(const char *const args[]);
+
+extern struct doveadm_cmd_ver2 doveadm_sieve_cmd_list;
+extern struct doveadm_cmd_ver2 doveadm_sieve_cmd_get;
+extern struct doveadm_cmd_ver2 doveadm_sieve_cmd_put;
+extern struct doveadm_cmd_ver2 doveadm_sieve_cmd_delete;
+extern struct doveadm_cmd_ver2 doveadm_sieve_cmd_activate;
+extern struct doveadm_cmd_ver2 doveadm_sieve_cmd_deactivate;
+extern struct doveadm_cmd_ver2 doveadm_sieve_cmd_rename;
+
+void doveadm_sieve_cmds_init(void);
+
+#endif
diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-plugin.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
new file mode 100644
index 0000000..0478b55
--- /dev/null
+++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-plugin.c
@@ -0,0 +1,24 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "doveadm-mail.h"
+
+#include "sieve.h"
+
+#include "doveadm-sieve-cmd.h"
+#include "doveadm-sieve-plugin.h"
+
+const char *doveadm_sieve_plugin_version = DOVECOT_ABI_VERSION;
+
+void doveadm_sieve_plugin_init(struct module *module)
+{
+ doveadm_sieve_sync_init(module);
+ doveadm_sieve_cmds_init();
+}
+
+void doveadm_sieve_plugin_deinit(void)
+{
+ /* the hooks array is freed already */
+ /*mail_storage_hooks_remove(&doveadm_sieve_mail_storage_hooks);*/
+}
diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-plugin.h b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-plugin.h
new file mode 100644
index 0000000..6e9446d
--- /dev/null
+++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-plugin.h
@@ -0,0 +1,17 @@
+#ifndef DOVEADM_SIEVE_PLUGIN_H
+#define DOVEADM_SIEVE_PLUGIN_H
+
+/*
+ * Plugin interface
+ */
+
+void doveadm_sieve_plugin_init(struct module *module);
+void doveadm_sieve_plugin_deinit(void);
+
+/*
+ * Replication
+ */
+
+void doveadm_sieve_sync_init(struct module *module);
+
+#endif
diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-sync.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-sync.c
new file mode 100644
index 0000000..c85a3fc
--- /dev/null
+++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-sync.c
@@ -0,0 +1,746 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "ioloop.h"
+#include "time-util.h"
+#include "istream.h"
+#include "istream-concat.h"
+#include "mail-storage-private.h"
+
+#include "sieve.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+
+#include "doveadm-sieve-plugin.h"
+
+#define SIEVE_MAIL_CONTEXT(obj) \
+ MODULE_CONTEXT_REQUIRE(obj, sieve_storage_module)
+#define SIEVE_USER_CONTEXT(obj) \
+ MODULE_CONTEXT_REQUIRE(obj, sieve_user_module)
+
+struct sieve_mail_user {
+ union mail_user_module_context module_ctx;
+
+ struct sieve_instance *svinst;
+ struct sieve_storage *sieve_storage;
+};
+
+struct sieve_mailbox_attribute_iter {
+ struct mailbox_attribute_iter iter;
+ struct mailbox_attribute_iter *super;
+
+ struct sieve_storage_list_context *sieve_list;
+ string_t *name;
+
+ bool failed;
+ bool have_active;
+};
+
+static MODULE_CONTEXT_DEFINE_INIT(sieve_storage_module,
+ &mail_storage_module_register);
+static MODULE_CONTEXT_DEFINE_INIT(sieve_user_module,
+ &mail_user_module_register);
+
+static const char *
+mail_sieve_get_setting(void *context, const char *identifier)
+{
+ struct mail_user *mail_user = context;
+
+ return mail_user_plugin_getenv(mail_user, identifier);
+}
+
+static const struct sieve_callbacks mail_sieve_callbacks = {
+ NULL,
+ mail_sieve_get_setting
+};
+
+static void mail_sieve_user_deinit(struct mail_user *user)
+{
+ struct sieve_mail_user *suser = SIEVE_USER_CONTEXT(user);
+
+ if ( suser->svinst != NULL ) {
+ if (suser->sieve_storage != NULL)
+ sieve_storage_unref(&suser->sieve_storage);
+ sieve_deinit(&suser->svinst);
+ }
+
+ suser->module_ctx.super.deinit(user);
+}
+
+static int
+mail_sieve_user_init
+(struct mail_user *user, struct sieve_storage **svstorage_r)
+{
+ struct sieve_mail_user *suser = SIEVE_USER_CONTEXT(user);
+ enum sieve_storage_flags storage_flags =
+ SIEVE_STORAGE_FLAG_READWRITE |
+ SIEVE_STORAGE_FLAG_SYNCHRONIZING;
+ struct sieve_environment svenv;
+
+ if ( suser->svinst != NULL ) {
+ *svstorage_r = suser->sieve_storage;
+ return suser->sieve_storage != NULL ? 1 : 0;
+ }
+
+ /* Delayed initialization of sieve storage until it's actually needed */
+ i_zero(&svenv);
+ svenv.username = user->username;
+ (void)mail_user_get_home(user, &svenv.home_dir);
+ svenv.base_dir = user->set->base_dir;
+ svenv.flags = SIEVE_FLAG_HOME_RELATIVE;
+
+ suser->svinst = sieve_init(&svenv, &mail_sieve_callbacks,
+ user, user->mail_debug);
+ suser->sieve_storage = sieve_storage_create_main
+ (suser->svinst, user, storage_flags, NULL);
+
+ *svstorage_r = suser->sieve_storage;
+ return suser->sieve_storage != NULL ? 1 : 0;
+}
+
+static int sieve_attribute_unset_script(struct mail_storage *storage,
+ struct sieve_storage *svstorage,
+ const char *scriptname)
+{
+ struct sieve_script *script;
+ const char *errstr;
+ enum sieve_error error;
+ int ret = 0;
+
+ script = sieve_storage_open_script(svstorage, scriptname, NULL);
+ if (script == NULL) {
+ ret = -1;
+ } else {
+ ret = sieve_script_delete(script, TRUE);
+ sieve_script_unref(&script);
+ }
+
+ if (ret < 0) {
+ errstr = sieve_storage_get_last_error(svstorage, &error);
+ if (error == SIEVE_ERROR_NOT_FOUND) {
+ /* already deleted, ignore */
+ return 0;
+ }
+ mail_storage_set_critical(storage,
+ "Failed to delete Sieve script '%s': %s", scriptname,
+ errstr);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+sieve_attribute_set_active(struct mail_storage *storage,
+ struct sieve_storage *svstorage,
+ const struct mail_attribute_value *value)
+{
+ const char *scriptname;
+ struct sieve_script *script;
+ time_t last_change =
+ (value->last_change == 0 ? ioloop_time : value->last_change);
+ int ret;
+
+ if (mailbox_attribute_value_to_string(storage, value, &scriptname) < 0)
+ return -1;
+
+ if (scriptname == NULL) {
+ /* don't affect non-link active script */
+ if ((ret=sieve_storage_is_singular(svstorage)) != 0) {
+ if (ret < 0) {
+ mail_storage_set_internal_error(storage);
+ return -1;
+ }
+ return 0;
+ }
+
+ /* deactivate current script */
+ if (sieve_storage_deactivate(svstorage, last_change) < 0) {
+ mail_storage_set_critical(storage,
+ "Failed to deactivate Sieve: %s",
+ sieve_storage_get_last_error(svstorage, NULL));
+ return -1;
+ }
+ return 0;
+ }
+ i_assert(scriptname[0] == MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_LINK);
+ scriptname++;
+
+ /* activate specified script */
+ script = sieve_storage_open_script(svstorage, scriptname, NULL);
+ ret = script == NULL ? -1 :
+ sieve_script_activate(script, last_change);
+ if (ret < 0) {
+ mail_storage_set_critical(storage,
+ "Failed to activate Sieve script '%s': %s", scriptname,
+ sieve_storage_get_last_error(svstorage, NULL));
+ }
+ if (script != NULL)
+ sieve_script_unref(&script);
+ sieve_storage_set_modified(svstorage, last_change);
+ return ret;
+}
+
+static int
+sieve_attribute_unset_active_script(struct mail_storage *storage,
+ struct sieve_storage *svstorage, time_t last_change)
+{
+ int ret;
+
+ if ((ret=sieve_storage_is_singular(svstorage)) != 0) {
+ if (ret < 0)
+ mail_storage_set_internal_error(storage);
+ return ret;
+ }
+
+ if (sieve_storage_deactivate(svstorage, last_change) < 0) {
+ mail_storage_set_critical(storage,
+ "Failed to deactivate sieve: %s",
+ sieve_storage_get_last_error(svstorage, NULL));
+ return -1;
+ }
+ return 0;
+}
+
+static int
+sieve_attribute_set_active_script(struct mail_storage *storage,
+ struct sieve_storage *svstorage,
+ const struct mail_attribute_value *value)
+{
+ struct istream *input;
+ time_t last_change =
+ (value->last_change == 0 ? ioloop_time : value->last_change);
+
+ if (value->value != NULL) {
+ input = i_stream_create_from_data(value->value, strlen(value->value));
+ } else if (value->value_stream != NULL) {
+ input = value->value_stream;
+ i_stream_ref(input);
+ } else {
+ return sieve_attribute_unset_active_script
+ (storage, svstorage, last_change);
+ }
+ /* skip over the 'S' type */
+ i_stream_skip(input, 1);
+
+ if (sieve_storage_save_as_active
+ (svstorage, input, last_change) < 0) {
+ mail_storage_set_critical(storage,
+ "Failed to save active sieve script: %s",
+ sieve_storage_get_last_error(svstorage, NULL));
+ i_stream_unref(&input);
+ return -1;
+ }
+
+ sieve_storage_set_modified(svstorage, last_change);
+ i_stream_unref(&input);
+ return 0;
+}
+
+static int
+sieve_attribute_set_default(struct mail_storage *storage,
+ struct sieve_storage *svstorage,
+ const struct mail_attribute_value *value)
+{
+ const unsigned char *data;
+ size_t size;
+ ssize_t ret;
+ char type;
+
+ if (value->value != NULL) {
+ type = value->value[0];
+ } else if (value->value_stream != NULL) {
+ ret = i_stream_read_more(value->value_stream, &data, &size);
+ if (ret == -1) {
+ mail_storage_set_critical(storage, "read(%s) failed: %m",
+ i_stream_get_name(value->value_stream));
+ return -1;
+ }
+ i_assert(ret > 0);
+ type = data[0];
+ } else {
+ type = MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_SCRIPT;
+ }
+ if (type == MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_LINK)
+ return sieve_attribute_set_active(storage, svstorage, value);
+ if (type == MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_SCRIPT)
+ return sieve_attribute_set_active_script(storage, svstorage, value);
+ mail_storage_set_error(storage, MAIL_ERROR_PARAMS,
+ "Invalid value for default sieve attribute");
+ return -1;
+}
+
+static int
+sieve_attribute_set_sieve(struct mail_storage *storage,
+ const char *key,
+ const struct mail_attribute_value *value)
+{
+ struct sieve_storage *svstorage;
+ struct sieve_storage_save_context *save_ctx;
+ struct istream *input;
+ const char *scriptname;
+ int ret;
+
+ if ((ret = mail_sieve_user_init(storage->user, &svstorage)) <= 0) {
+ if (ret == 0) {
+ mail_storage_set_error(storage, MAIL_ERROR_NOTFOUND,
+ "Sieve not enabled for user");
+ }
+ return -1;
+ }
+
+ if (strcmp(key, MAILBOX_ATTRIBUTE_SIEVE_DEFAULT) == 0)
+ return sieve_attribute_set_default(storage, svstorage, value);
+ if (!str_begins(key, MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES)) {
+ mail_storage_set_error(storage, MAIL_ERROR_NOTFOUND,
+ "Nonexistent sieve attribute");
+ return -1;
+ }
+ scriptname = key + strlen(MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES);
+
+ if (value->value != NULL) {
+ input = i_stream_create_from_data(value->value,
+ strlen(value->value));
+ save_ctx = sieve_storage_save_init(svstorage, scriptname, input);
+ } else if (value->value_stream != NULL) {
+ input = value->value_stream;
+ i_stream_ref(input);
+ save_ctx = sieve_storage_save_init(svstorage, scriptname, input);
+ } else {
+ return sieve_attribute_unset_script(storage, svstorage, scriptname);
+ }
+
+ if (save_ctx == NULL) {
+ /* save initialization failed */
+ mail_storage_set_critical(storage,
+ "Failed to save sieve script '%s': %s", scriptname,
+ sieve_storage_get_last_error(svstorage, NULL));
+ i_stream_unref(&input);
+ return -1;
+ }
+
+ if (value->last_change != 0)
+ sieve_storage_save_set_mtime(save_ctx, value->last_change);
+
+ ret = 0;
+ while (input->stream_errno == 0 &&
+ !i_stream_read_eof(input)) {
+ if (sieve_storage_save_continue(save_ctx) < 0) {
+ mail_storage_set_critical(storage,
+ "Failed to save sieve script '%s': %s", scriptname,
+ sieve_storage_get_last_error(svstorage, NULL));
+ ret = -1;
+ break;
+ }
+ }
+ if (input->stream_errno != 0) {
+ errno = input->stream_errno;
+ mail_storage_set_critical(storage,
+ "Saving sieve script: read(%s) failed: %m",
+ i_stream_get_name(input));
+ ret = -1;
+ }
+ i_assert(input->eof || ret < 0);
+ if (ret == 0 && sieve_storage_save_finish(save_ctx) < 0) {
+ mail_storage_set_critical(storage,
+ "Failed to save sieve script '%s': %s", scriptname,
+ sieve_storage_get_last_error(svstorage, NULL));
+ ret = -1;
+ }
+ if (ret < 0)
+ sieve_storage_save_cancel(&save_ctx);
+ else if (sieve_storage_save_commit(&save_ctx) < 0) {
+ mail_storage_set_critical(storage,
+ "Failed to save sieve script '%s': %s", scriptname,
+ sieve_storage_get_last_error(svstorage, NULL));
+ ret = -1;
+ }
+ i_stream_unref(&input);
+ return ret;
+}
+
+static int
+sieve_attribute_set(struct mailbox_transaction_context *t,
+ enum mail_attribute_type type, const char *key,
+ const struct mail_attribute_value *value)
+{
+ struct mail_user *user = t->box->storage->user;
+ union mailbox_module_context *sbox = SIEVE_MAIL_CONTEXT(t->box);
+
+ if (t->box->storage->user->dsyncing &&
+ type == MAIL_ATTRIBUTE_TYPE_PRIVATE &&
+ str_begins(key, MAILBOX_ATTRIBUTE_PREFIX_SIEVE)) {
+ time_t ts =
+ (value->last_change != 0 ? value->last_change : ioloop_time);
+
+ if (sieve_attribute_set_sieve(t->box->storage, key, value) < 0)
+ return -1;
+
+ if (user->mail_debug) {
+ const char *change;
+ if (value->last_change != 0) {
+ change = t_strflocaltime
+ ("(last change: %Y-%m-%d %H:%M:%S)", value->last_change);
+ } else {
+ change = t_strflocaltime
+ ("(time: %Y-%m-%d %H:%M:%S)", ioloop_time);
+ }
+ i_debug("doveadm-sieve: Assigned value for key `%s' %s",
+ key, change);
+ }
+
+ /* FIXME: set value len to sieve script size / active name
+ length */
+ if (value->value != NULL || value->value_stream != NULL)
+ mail_index_attribute_set(t->itrans, TRUE, key, ts, 0);
+ else
+ mail_index_attribute_unset(t->itrans, TRUE, key, ts);
+ return 0;
+ }
+ return sbox->super.attribute_set(t, type, key, value);
+}
+
+static int
+sieve_attribute_retrieve_script(struct mail_storage *storage,
+ struct sieve_storage *svstorage, struct sieve_script *script,
+ bool add_type_prefix,
+ struct mail_attribute_value *value_r, const char **errorstr_r)
+{
+ static char type = MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_SCRIPT;
+ struct istream *input, *inputs[3];
+ const struct stat *st;
+ enum sieve_error error;
+
+ if (script == NULL)
+ *errorstr_r = sieve_storage_get_last_error(svstorage, &error);
+ else if (sieve_script_get_stream(script, &input, &error) < 0)
+ sieve_script_unref(&script);
+
+ if (script == NULL) {
+ if (error == SIEVE_ERROR_NOT_FOUND) {
+ /* already deleted, but return the last_change */
+ (void)sieve_storage_get_last_change(svstorage,
+ &value_r->last_change);
+ return 0;
+ }
+ *errorstr_r = sieve_storage_get_last_error(svstorage, &error);
+ return -1;
+ }
+ if (i_stream_stat(input, FALSE, &st) < 0) {
+ mail_storage_set_critical(storage,
+ "stat(%s) failed: %m", i_stream_get_name(input));
+ } else {
+ value_r->last_change = st->st_mtime;
+ }
+ if (!add_type_prefix) {
+ i_stream_ref(input);
+ value_r->value_stream = input;
+ } else {
+ inputs[0] = i_stream_create_from_data(&type, 1);
+ inputs[1] = input;
+ inputs[2] = NULL;
+ value_r->value_stream = i_stream_create_concat(inputs);
+ i_stream_unref(&inputs[0]);
+ }
+ sieve_script_unref(&script);
+ return 1;
+}
+
+static int
+sieve_attribute_get_active_script(struct mail_storage *storage,
+ struct sieve_storage *svstorage,
+ struct mail_attribute_value *value_r)
+{
+ struct sieve_script *script;
+ const char *errstr;
+ int ret;
+
+ if ((ret=sieve_storage_is_singular(svstorage)) <= 0) {
+ if (ret == 0 && sieve_storage_active_script_get_last_change
+ (svstorage, &value_r->last_change) < 0) {
+ ret = -1;
+ }
+ if (ret < 0)
+ mail_storage_set_internal_error(storage);
+ return ret;
+ }
+
+ if ((script=sieve_storage_active_script_open
+ (svstorage, NULL)) == NULL)
+ return 0;
+
+ if ((ret=sieve_attribute_retrieve_script
+ (storage, svstorage, script, TRUE, value_r, &errstr)) < 0) {
+ mail_storage_set_critical(storage,
+ "Failed to access active sieve script: %s", errstr);
+ }
+ return ret;
+}
+
+static int
+sieve_attribute_get_default(struct mail_storage *storage,
+ struct sieve_storage *svstorage,
+ struct mail_attribute_value *value_r)
+{
+ const char *scriptname;
+ int ret;
+
+ ret = sieve_storage_active_script_get_name(svstorage, &scriptname);
+ if (ret == 0)
+ return sieve_attribute_get_active_script(storage, svstorage, value_r);
+
+ if (ret > 0) {
+ value_r->value = t_strdup_printf("%c%s",
+ MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_LINK, scriptname);
+ if (sieve_storage_active_script_get_last_change
+ (svstorage, &value_r->last_change) < 0)
+ ret = -1;
+ }
+ if (ret < 0)
+ mail_storage_set_internal_error(storage);
+ return ret;
+}
+
+static int
+sieve_attribute_get_sieve(struct mail_storage *storage, const char *key,
+ struct mail_attribute_value *value_r)
+{
+ struct sieve_storage *svstorage;
+ struct sieve_script *script;
+ const char *scriptname, *errstr;
+ int ret;
+
+ if ((ret = mail_sieve_user_init(storage->user, &svstorage)) <= 0)
+ return ret;
+
+ if (strcmp(key, MAILBOX_ATTRIBUTE_SIEVE_DEFAULT) == 0)
+ return sieve_attribute_get_default(storage, svstorage, value_r);
+ if (!str_begins(key, MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES))
+ return 0;
+ if ((value_r->flags & MAIL_ATTRIBUTE_VALUE_FLAG_INT_STREAMS) == 0) {
+ mail_storage_set_error(storage, MAIL_ERROR_PARAMS,
+ "Sieve attributes are available only as streams");
+ return -1;
+ }
+ scriptname = key + strlen(MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES);
+ script = sieve_storage_open_script(svstorage, scriptname, NULL);
+ if ((ret=sieve_attribute_retrieve_script
+ (storage, svstorage, script, FALSE, value_r, &errstr)) < 0) {
+ mail_storage_set_critical(storage,
+ "Failed to access sieve script '%s': %s",
+ scriptname, errstr);
+ }
+ return ret;
+}
+
+static int
+sieve_attribute_get(struct mailbox *box,
+ enum mail_attribute_type type, const char *key,
+ struct mail_attribute_value *value_r)
+{
+ union mailbox_module_context *sbox = SIEVE_MAIL_CONTEXT(box);
+ struct mail_user *user = box->storage->user;
+ int ret;
+
+ if (box->storage->user->dsyncing &&
+ type == MAIL_ATTRIBUTE_TYPE_PRIVATE &&
+ str_begins(key, MAILBOX_ATTRIBUTE_PREFIX_SIEVE)) {
+
+ ret = sieve_attribute_get_sieve(box->storage, key, value_r);
+ if (ret >= 0 && user->mail_debug) {
+ struct tm *tm = localtime(&value_r->last_change);
+ char str[256];
+ const char *timestamp = "";
+
+ if (strftime(str, sizeof(str),
+ " (last change: %Y-%m-%d %H:%M:%S)", tm) > 0)
+ timestamp = str;
+
+ if (ret > 0) {
+ i_debug("doveadm-sieve: Retrieved value for key `%s'%s",
+ key, timestamp);
+ } else {
+ i_debug("doveadm-sieve: Value missing for key `%s'%s",
+ key, timestamp);
+ }
+ }
+ return ret;
+ }
+ return sbox->super.attribute_get(box, type, key, value_r);
+}
+
+static int
+sieve_attribute_iter_script_init(struct sieve_mailbox_attribute_iter *siter)
+{
+ struct mail_user *user = siter->iter.box->storage->user;
+ struct sieve_storage *svstorage;
+ int ret;
+
+ if (user->mail_debug)
+ i_debug("doveadm-sieve: Iterating Sieve mailbox attributes");
+
+ if ((ret = mail_sieve_user_init(user, &svstorage)) <= 0)
+ return ret;
+
+ siter->sieve_list = sieve_storage_list_init(svstorage);
+ if (siter->sieve_list == NULL) {
+ mail_storage_set_critical(siter->iter.box->storage,
+ "Failed to iterate sieve scripts: %s",
+ sieve_storage_get_last_error(svstorage, NULL));
+ return -1;
+ }
+ siter->name = str_new(default_pool, 128);
+ str_append(siter->name, MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES);
+ return 0;
+}
+
+static struct mailbox_attribute_iter *
+sieve_attribute_iter_init(struct mailbox *box, enum mail_attribute_type type,
+ const char *prefix)
+{
+ union mailbox_module_context *sbox = SIEVE_MAIL_CONTEXT(box);
+ struct sieve_mailbox_attribute_iter *siter;
+
+ siter = i_new(struct sieve_mailbox_attribute_iter, 1);
+ siter->iter.box = box;
+ siter->super = sbox->super.attribute_iter_init(box, type, prefix);
+
+ if (box->storage->user->dsyncing &&
+ type == MAIL_ATTRIBUTE_TYPE_PRIVATE) {
+ if (sieve_attribute_iter_script_init(siter) < 0)
+ siter->failed = TRUE;
+ }
+ return &siter->iter;
+}
+
+static const char *
+sieve_attribute_iter_next_script(struct sieve_mailbox_attribute_iter *siter)
+{
+ struct mail_user *user = siter->iter.box->storage->user;
+ struct sieve_mail_user *suser = SIEVE_USER_CONTEXT(user);
+ struct sieve_storage *svstorage = suser->sieve_storage;
+ const char *scriptname;
+ bool active;
+ int ret;
+
+ if (siter->sieve_list == NULL)
+ return NULL;
+
+ /* Iterate through all scripts in sieve_dir */
+ while ((scriptname = sieve_storage_list_next(siter->sieve_list, &active))
+ != NULL) {
+ if (active)
+ siter->have_active = TRUE;
+ str_truncate(siter->name, strlen(MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES));
+ str_append(siter->name, scriptname);
+ return str_c(siter->name);
+ }
+ if (sieve_storage_list_deinit(&siter->sieve_list) < 0) {
+ mail_storage_set_critical(siter->iter.box->storage,
+ "Failed to iterate sieve scripts: %s",
+ sieve_storage_get_last_error(svstorage, NULL));
+ siter->failed = TRUE;
+ return NULL;
+ }
+
+ /* Check whether active script is a proper symlink or a regular file */
+ if ((ret=sieve_storage_is_singular(svstorage)) < 0) {
+ mail_storage_set_critical(siter->iter.box->storage,
+ "Failed to iterate sieve scripts: %s",
+ sieve_storage_get_last_error(svstorage, NULL));
+ return NULL;
+ }
+
+ /* Regular file */
+ if (ret > 0)
+ return MAILBOX_ATTRIBUTE_SIEVE_DEFAULT;
+
+ /* Symlink or none active */
+ return siter->have_active ? MAILBOX_ATTRIBUTE_SIEVE_DEFAULT : NULL;
+}
+
+static const char *
+sieve_attribute_iter_next(struct mailbox_attribute_iter *iter)
+{
+ struct sieve_mailbox_attribute_iter *siter =
+ (struct sieve_mailbox_attribute_iter *)iter;
+ union mailbox_module_context *sbox = SIEVE_MAIL_CONTEXT(iter->box);
+ struct mail_user *user = iter->box->storage->user;
+ const char *key;
+
+ if (siter->sieve_list != NULL) {
+ if ((key = sieve_attribute_iter_next_script(siter)) != NULL) {
+ if (user->mail_debug) {
+ i_debug("doveadm-sieve: Iterating Sieve mailbox attribute: %s", key);
+ }
+ return key;
+ }
+ }
+ return sbox->super.attribute_iter_next(siter->super);
+}
+
+static int
+sieve_attribute_iter_deinit(struct mailbox_attribute_iter *iter)
+{
+ struct sieve_mailbox_attribute_iter *siter =
+ (struct sieve_mailbox_attribute_iter *)iter;
+ union mailbox_module_context *sbox = SIEVE_MAIL_CONTEXT(iter->box);
+ int ret = siter->failed ? -1 : 0;
+
+ if (siter->super != NULL) {
+ if (sbox->super.attribute_iter_deinit(siter->super) < 0)
+ ret = -1;
+ }
+ if (siter->sieve_list != NULL)
+ (void)sieve_storage_list_deinit(&siter->sieve_list);
+ if (siter->name != NULL)
+ str_free(&siter->name);
+ i_free(siter);
+ return ret;
+}
+
+static void
+sieve_mail_user_created(struct mail_user *user)
+{
+ struct sieve_mail_user *suser;
+ struct mail_user_vfuncs *v = user->vlast;
+
+ suser = p_new(user->pool, struct sieve_mail_user, 1);
+ suser->module_ctx.super = *v;
+ user->vlast = &suser->module_ctx.super;
+ v->deinit = mail_sieve_user_deinit;
+ MODULE_CONTEXT_SET(user, sieve_user_module, suser);
+}
+
+static void
+sieve_mailbox_allocated(struct mailbox *box)
+{
+ struct mailbox_vfuncs *v = box->vlast;
+ union mailbox_module_context *sbox;
+
+ /* attribute syncing is done via INBOX */
+ if (!box->inbox_user)
+ return;
+
+ sbox = p_new(box->pool, union mailbox_module_context, 1);
+ sbox->super = *v;
+ box->vlast = &sbox->super;
+ v->attribute_set = sieve_attribute_set;
+ v->attribute_get = sieve_attribute_get;
+ v->attribute_iter_init = sieve_attribute_iter_init;
+ v->attribute_iter_next = sieve_attribute_iter_next;
+ v->attribute_iter_deinit = sieve_attribute_iter_deinit;
+ MODULE_CONTEXT_SET_SELF(box, sieve_storage_module, sbox);
+}
+
+static struct mail_storage_hooks doveadm_sieve_mail_storage_hooks = {
+ .mail_user_created = sieve_mail_user_created,
+ .mailbox_allocated = sieve_mailbox_allocated
+};
+
+void doveadm_sieve_sync_init(struct module *module)
+{
+ mail_storage_hooks_add_forced
+ (module, &doveadm_sieve_mail_storage_hooks);
+}
diff --git a/pigeonhole/src/plugins/imap-filter-sieve/Makefile.am b/pigeonhole/src/plugins/imap-filter-sieve/Makefile.am
new file mode 100644
index 0000000..915e128
--- /dev/null
+++ b/pigeonhole/src/plugins/imap-filter-sieve/Makefile.am
@@ -0,0 +1,26 @@
+imap_moduledir = $(dovecot_moduledir)
+
+imap_module_LTLIBRARIES = lib95_imap_filter_sieve_plugin.la
+
+lib95_imap_filter_sieve_plugin_la_LDFLAGS = -module -avoid-version
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib-sieve \
+ $(LIBDOVECOT_IMAP_INCLUDE) \
+ $(LIBDOVECOT_LDA_INCLUDE) \
+ $(LIBDOVECOT_INCLUDE) \
+ -DPKG_RUNDIR=\""$(rundir)"\"
+
+lib95_imap_filter_sieve_plugin_la_SOURCES = \
+ cmd-filter.c \
+ cmd-filter-sieve.c \
+ imap-filter.c \
+ imap-filter-sieve.c \
+ imap-filter-sieve-plugin.c
+lib95_imap_filter_sieve_plugin_la_LIBADD = \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la
+
+noinst_HEADERS = \
+ imap-filter.h \
+ imap-filter-sieve.h \
+ imap-filter-sieve-plugin.h
diff --git a/pigeonhole/src/plugins/imap-filter-sieve/Makefile.in b/pigeonhole/src/plugins/imap-filter-sieve/Makefile.in
new file mode 100644
index 0000000..b74a15b
--- /dev/null
+++ b/pigeonhole/src/plugins/imap-filter-sieve/Makefile.in
@@ -0,0 +1,771 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/plugins/imap-filter-sieve
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(imap_moduledir)"
+LTLIBRARIES = $(imap_module_LTLIBRARIES)
+lib95_imap_filter_sieve_plugin_la_DEPENDENCIES = \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la
+am_lib95_imap_filter_sieve_plugin_la_OBJECTS = cmd-filter.lo \
+ cmd-filter-sieve.lo imap-filter.lo imap-filter-sieve.lo \
+ imap-filter-sieve-plugin.lo
+lib95_imap_filter_sieve_plugin_la_OBJECTS = \
+ $(am_lib95_imap_filter_sieve_plugin_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+lib95_imap_filter_sieve_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(lib95_imap_filter_sieve_plugin_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cmd-filter-sieve.Plo \
+ ./$(DEPDIR)/cmd-filter.Plo \
+ ./$(DEPDIR)/imap-filter-sieve-plugin.Plo \
+ ./$(DEPDIR)/imap-filter-sieve.Plo ./$(DEPDIR)/imap-filter.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(lib95_imap_filter_sieve_plugin_la_SOURCES)
+DIST_SOURCES = $(lib95_imap_filter_sieve_plugin_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+imap_moduledir = $(dovecot_moduledir)
+imap_module_LTLIBRARIES = lib95_imap_filter_sieve_plugin.la
+lib95_imap_filter_sieve_plugin_la_LDFLAGS = -module -avoid-version
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib-sieve \
+ $(LIBDOVECOT_IMAP_INCLUDE) \
+ $(LIBDOVECOT_LDA_INCLUDE) \
+ $(LIBDOVECOT_INCLUDE) \
+ -DPKG_RUNDIR=\""$(rundir)"\"
+
+lib95_imap_filter_sieve_plugin_la_SOURCES = \
+ cmd-filter.c \
+ cmd-filter-sieve.c \
+ imap-filter.c \
+ imap-filter-sieve.c \
+ imap-filter-sieve-plugin.c
+
+lib95_imap_filter_sieve_plugin_la_LIBADD = \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la
+
+noinst_HEADERS = \
+ imap-filter.h \
+ imap-filter-sieve.h \
+ imap-filter-sieve-plugin.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/imap-filter-sieve/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/plugins/imap-filter-sieve/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-imap_moduleLTLIBRARIES: $(imap_module_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(imap_module_LTLIBRARIES)'; test -n "$(imap_moduledir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(imap_moduledir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(imap_moduledir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(imap_moduledir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(imap_moduledir)"; \
+ }
+
+uninstall-imap_moduleLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(imap_module_LTLIBRARIES)'; test -n "$(imap_moduledir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(imap_moduledir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(imap_moduledir)/$$f"; \
+ done
+
+clean-imap_moduleLTLIBRARIES:
+ -test -z "$(imap_module_LTLIBRARIES)" || rm -f $(imap_module_LTLIBRARIES)
+ @list='$(imap_module_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+lib95_imap_filter_sieve_plugin.la: $(lib95_imap_filter_sieve_plugin_la_OBJECTS) $(lib95_imap_filter_sieve_plugin_la_DEPENDENCIES) $(EXTRA_lib95_imap_filter_sieve_plugin_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(lib95_imap_filter_sieve_plugin_la_LINK) -rpath $(imap_moduledir) $(lib95_imap_filter_sieve_plugin_la_OBJECTS) $(lib95_imap_filter_sieve_plugin_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-filter-sieve.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-filter.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-filter-sieve-plugin.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-filter-sieve.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-filter.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(imap_moduledir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-imap_moduleLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/cmd-filter-sieve.Plo
+ -rm -f ./$(DEPDIR)/cmd-filter.Plo
+ -rm -f ./$(DEPDIR)/imap-filter-sieve-plugin.Plo
+ -rm -f ./$(DEPDIR)/imap-filter-sieve.Plo
+ -rm -f ./$(DEPDIR)/imap-filter.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-imap_moduleLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/cmd-filter-sieve.Plo
+ -rm -f ./$(DEPDIR)/cmd-filter.Plo
+ -rm -f ./$(DEPDIR)/imap-filter-sieve-plugin.Plo
+ -rm -f ./$(DEPDIR)/imap-filter-sieve.Plo
+ -rm -f ./$(DEPDIR)/imap-filter.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-imap_moduleLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-imap_moduleLTLIBRARIES clean-libtool \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-imap_moduleLTLIBRARIES install-info install-info-am \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-imap_moduleLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/plugins/imap-filter-sieve/cmd-filter-sieve.c b/pigeonhole/src/plugins/imap-filter-sieve/cmd-filter-sieve.c
new file mode 100644
index 0000000..6b96bd3
--- /dev/null
+++ b/pigeonhole/src/plugins/imap-filter-sieve/cmd-filter-sieve.c
@@ -0,0 +1,403 @@
+/* Copyright (c) 2017-2018 Pigeonhole authors, see the included COPYING file */
+
+#include "imap-common.h"
+#include "str.h"
+#include "istream.h"
+#include "istream-seekable.h"
+#include "ostream.h"
+#include "imap-commands.h"
+
+#include "imap-filter.h"
+#include "imap-filter-sieve.h"
+
+#define FILTER_MAX_INMEM_SIZE (1024*128)
+
+static int cmd_filter_sieve_compile_script(struct imap_filter_context *ctx)
+{
+ struct client_command_context *cmd = ctx->cmd;
+ struct imap_filter_sieve_context *sctx = ctx->sieve;
+ struct client *client = cmd->client;
+ string_t *errors = NULL;
+ bool have_warnings = FALSE;
+ int ret = 0;
+
+ ret = imap_filter_sieve_compile(sctx, &errors, &have_warnings);
+ if (ret >= 0 && !have_warnings)
+ return 0;
+
+ o_stream_nsend_str(client->output,
+ t_strdup_printf("* FILTER (TAG %s) "
+ "%s {%zu}\r\n",
+ cmd->tag, (ret < 0 ? "ERRORS" : "WARNINGS"),
+ str_len(errors)));
+ o_stream_nsend(client->output,
+ str_data(errors), str_len(errors));
+ o_stream_nsend_str(client->output, "\r\n");
+
+ if (ret < 0) {
+ ctx->compile_failure = TRUE;
+ ctx->failed = TRUE;
+ return -1;
+ }
+ return 0;
+}
+
+static bool cmd_filter_sieve_delivery(struct client_command_context *cmd)
+{
+ struct imap_filter_context *ctx = cmd->context;
+ struct client *client = cmd->client;
+ struct imap_filter_sieve_context *sctx = ctx->sieve;
+ enum mail_error error;
+ const char *error_string;
+ int ret;
+
+ if (cmd->cancel) {
+ imap_filter_deinit(ctx);
+ return TRUE;
+ }
+
+ i_assert(sctx->filter_type == IMAP_FILTER_SIEVE_TYPE_DELIVERY);
+ ret = imap_filter_sieve_open_personal(sctx, NULL,
+ &error, &error_string);
+ if (ret < 0) {
+ client_send_tagline(
+ cmd, imap_get_error_string(cmd, error_string, error));
+ imap_filter_deinit(ctx);
+ return TRUE;
+ }
+ if (cmd_filter_sieve_compile_script(ctx) < 0) {
+ client_send_tagline(cmd, "NO Failed to compile Sieve script");
+ client->input_skip_line = TRUE;
+ imap_filter_deinit(ctx);
+ return TRUE;
+ }
+
+ imap_parser_reset(ctx->parser);
+ cmd->func = imap_filter_search;
+ return imap_filter_search(cmd);
+}
+
+static int
+cmd_filter_sieve_script_parse_name_arg(struct imap_filter_context *ctx)
+{
+ struct client_command_context *cmd = ctx->cmd;
+ const struct imap_arg *args;
+ const char *error;
+ enum imap_parser_error parse_error;
+ int ret;
+
+ ret = imap_parser_read_args(ctx->parser, 1, 0, &args);
+ if (ret < 0) {
+ if (ret == -2)
+ return 0;
+ error = imap_parser_get_error(ctx->parser, &parse_error);
+ switch (parse_error) {
+ case IMAP_PARSE_ERROR_NONE:
+ i_unreached();
+ case IMAP_PARSE_ERROR_LITERAL_TOO_BIG:
+ client_disconnect_with_error(ctx->cmd->client, error);
+ break;
+ default:
+ client_send_command_error(ctx->cmd, error);
+ break;
+ }
+ return -1;
+ }
+
+ switch (args[0].type) {
+ case IMAP_ARG_EOL:
+ client_send_command_error(ctx->cmd, "Script name missing");
+ return -1;
+ case IMAP_ARG_NIL:
+ case IMAP_ARG_LIST:
+ client_send_command_error(
+ ctx->cmd, "Script name must be an atom or a string");
+ return -1;
+ case IMAP_ARG_ATOM:
+ case IMAP_ARG_STRING:
+ /* We have the value already */
+ if (ctx->failed)
+ return 1;
+ ctx->script_name = p_strdup(cmd->pool,
+ imap_arg_as_astring(&args[0]));
+ break;
+ case IMAP_ARG_LITERAL:
+ case IMAP_ARG_LITERAL_SIZE:
+ case IMAP_ARG_LITERAL_SIZE_NONSYNC:
+ i_unreached();
+ }
+ return 1;
+}
+
+static bool
+cmd_filter_sieve_script_parse_name(struct client_command_context *cmd)
+{
+ struct imap_filter_context *ctx = cmd->context;
+ struct client *client = cmd->client;
+ struct imap_filter_sieve_context *sctx = ctx->sieve;
+ enum mail_error error;
+ const char *error_string;
+ int ret;
+
+ if (cmd->cancel) {
+ imap_filter_deinit(ctx);
+ return TRUE;
+ }
+
+ if ((ret = cmd_filter_sieve_script_parse_name_arg(ctx)) == 0)
+ return FALSE;
+ if (ret < 0) {
+ /* Already sent the error to client */
+ imap_filter_deinit(ctx);
+ return TRUE;
+ }
+
+ switch (sctx->filter_type) {
+ case IMAP_FILTER_SIEVE_TYPE_PERSONAL:
+ ret = imap_filter_sieve_open_personal(sctx, ctx->script_name,
+ &error, &error_string);
+ break;
+ case IMAP_FILTER_SIEVE_TYPE_GLOBAL:
+ ret = imap_filter_sieve_open_global(sctx, ctx->script_name,
+ &error, &error_string);
+ break;
+ case IMAP_FILTER_SIEVE_TYPE_DELIVERY:
+ case IMAP_FILTER_SIEVE_TYPE_SCRIPT:
+ i_unreached();
+ }
+ if (ret < 0) {
+ client_send_tagline(
+ cmd, imap_get_error_string(cmd, error_string, error));
+ imap_filter_deinit(ctx);
+ return TRUE;
+ }
+ if (cmd_filter_sieve_compile_script(ctx) < 0) {
+ client_send_tagline(cmd, "NO Failed to compile Sieve script");
+ client->input_skip_line = TRUE;
+ imap_filter_deinit(ctx);
+ return TRUE;
+ }
+
+ imap_parser_reset(ctx->parser);
+ cmd->func = imap_filter_search;
+ return imap_filter_search(cmd);
+}
+
+static void
+cmd_filter_sieve_compile_input(struct imap_filter_context *ctx,
+ struct istream *input)
+{
+ struct imap_filter_sieve_context *sctx = ctx->sieve;
+
+ imap_filter_sieve_open_input(sctx, input);
+ (void)cmd_filter_sieve_compile_script(ctx);
+}
+
+static int cmd_filter_sieve_script_read_stream(struct imap_filter_context *ctx)
+{
+ struct istream *input = ctx->script_input;
+ const unsigned char *data;
+ size_t size;
+ int ret;
+
+ while ((ret = i_stream_read_more(input, &data, &size)) > 0)
+ i_stream_skip(input, size);
+ if (ret == 0)
+ return 0;
+
+ if (input->v_offset != ctx->script_len) {
+ /* Client disconnected */
+ i_assert(input->eof);
+ return -1;
+ }
+ /* Finished reading the value */
+ i_stream_seek(input, 0);
+
+ if (ctx->failed) {
+ i_stream_unref(&ctx->script_input);
+ return 1;
+ }
+
+ cmd_filter_sieve_compile_input(ctx, ctx->script_input);
+ i_stream_unref(&ctx->script_input);
+ return 1;
+}
+
+static int
+cmd_filter_sieve_script_parse_value_arg(struct imap_filter_context *ctx)
+{
+ const struct imap_arg *args;
+ const char *value, *error;
+ enum imap_parser_error parse_error;
+ struct istream *input, *inputs[2];
+ string_t *path;
+ int ret;
+
+ ret = imap_parser_read_args(ctx->parser, 1,
+ IMAP_PARSE_FLAG_LITERAL_SIZE |
+ IMAP_PARSE_FLAG_LITERAL8, &args);
+ if (ret < 0) {
+ if (ret == -2)
+ return 0;
+ error = imap_parser_get_error(ctx->parser, &parse_error);
+ switch (parse_error) {
+ case IMAP_PARSE_ERROR_NONE:
+ i_unreached();
+ case IMAP_PARSE_ERROR_LITERAL_TOO_BIG:
+ client_disconnect_with_error(ctx->cmd->client, error);
+ break;
+ default:
+ client_send_command_error(ctx->cmd, error);
+ break;
+ }
+ return -1;
+ }
+
+ switch (args[0].type) {
+ case IMAP_ARG_EOL:
+ client_send_command_error(ctx->cmd, "Script value missing");
+ return -1;
+ case IMAP_ARG_NIL:
+ case IMAP_ARG_ATOM:
+ case IMAP_ARG_LIST:
+ client_send_command_error(ctx->cmd,
+ "Script value must be a string");
+ return -1;
+ case IMAP_ARG_STRING:
+ /* We have the value already */
+ if (ctx->failed)
+ return 1;
+ value = imap_arg_as_astring(&args[0]);
+ input = i_stream_create_from_data(value, strlen(value));
+ cmd_filter_sieve_compile_input(ctx, input);
+ i_stream_unref(&input);
+ return 1;
+ case IMAP_ARG_LITERAL_SIZE:
+ o_stream_nsend(ctx->cmd->client->output, "+ OK\r\n", 6);
+ o_stream_uncork(ctx->cmd->client->output);
+ o_stream_cork(ctx->cmd->client->output);
+ /* Fall through */
+ case IMAP_ARG_LITERAL_SIZE_NONSYNC:
+ ctx->script_len = imap_arg_as_literal_size(&args[0]);
+
+ inputs[0] = i_stream_create_limit(ctx->cmd->client->input,
+ ctx->script_len);
+ inputs[1] = NULL;
+
+ path = t_str_new(128);
+ mail_user_set_get_temp_prefix(path,
+ ctx->cmd->client->user->set);
+ ctx->script_input = i_stream_create_seekable_path(
+ inputs, FILTER_MAX_INMEM_SIZE, str_c(path));
+ i_stream_set_name(ctx->script_input,
+ i_stream_get_name(inputs[0]));
+ i_stream_unref(&inputs[0]);
+ break;
+ case IMAP_ARG_LITERAL:
+ i_unreached();
+ }
+ return cmd_filter_sieve_script_read_stream(ctx);
+}
+
+static bool
+cmd_filter_sieve_script_parse_value(struct client_command_context *cmd)
+{
+ struct imap_filter_context *ctx = cmd->context;
+ struct client *client = cmd->client;
+ int ret;
+
+ if (cmd->cancel) {
+ imap_filter_deinit(ctx);
+ return TRUE;
+ }
+
+ if (ctx->script_input != NULL) {
+ if ((ret = cmd_filter_sieve_script_read_stream(ctx)) == 0)
+ return FALSE;
+ } else {
+ if ((ret = cmd_filter_sieve_script_parse_value_arg(ctx)) == 0)
+ return FALSE;
+ }
+
+ if (ret < 0) {
+ /* Already sent the error to client */ ;
+ imap_filter_deinit(ctx);
+ return TRUE;
+ } else if (ctx->compile_failure) {
+ client_send_tagline(cmd, "NO Failed to compile Sieve script");
+ client->input_skip_line = TRUE;
+ imap_filter_deinit(ctx);
+ return TRUE;
+ }
+
+ imap_parser_reset(ctx->parser);
+ cmd->func = imap_filter_search;
+ return imap_filter_search(cmd);
+}
+
+bool cmd_filter_sieve(struct client_command_context *cmd)
+{
+ struct imap_filter_context *ctx = cmd->context;
+ struct client *client = cmd->client;
+ enum imap_filter_sieve_type type;
+ const struct imap_arg *args;
+ const char *sieve_type;
+
+ if (!client_read_args(cmd, 2, 0, &args))
+ return FALSE;
+ args++;
+
+ /* sieve-type */
+ if (IMAP_ARG_IS_EOL(args)) {
+ client_send_command_error(
+ cmd, "Missing SIEVE filter sub-type.");
+ return TRUE;
+ }
+ if (!imap_arg_get_atom(args, &sieve_type)) {
+ client_send_command_error(
+ cmd, "SIEVE filter sub-type is not an atom.");
+ return TRUE;
+ }
+ if (strcasecmp(sieve_type, "DELIVERY") == 0) {
+ type = IMAP_FILTER_SIEVE_TYPE_DELIVERY;
+ } else if (strcasecmp(sieve_type, "PERSONAL") == 0) {
+ type = IMAP_FILTER_SIEVE_TYPE_PERSONAL;
+ } else if (strcasecmp(sieve_type, "GLOBAL") == 0) {
+ type = IMAP_FILTER_SIEVE_TYPE_GLOBAL;
+ } else if (strcasecmp(sieve_type, "SCRIPT") == 0) {
+ type = IMAP_FILTER_SIEVE_TYPE_SCRIPT;
+ } else {
+ client_send_command_error(cmd, t_strdup_printf(
+ "Unknown SIEVE filter sub-type `%s'",
+ sieve_type));
+ return TRUE;
+ }
+
+ ctx->sieve = imap_filter_sieve_context_create(ctx, type);
+
+ /* We support large scripts, so read the values from client
+ asynchronously the same way as APPEND does. */
+ client->input_lock = cmd;
+ ctx->parser = imap_parser_create(client->input, client->output,
+ client->set->imap_max_line_length);
+ if (client->set->imap_literal_minus)
+ imap_parser_enable_literal_minus(ctx->parser);
+ o_stream_unset_flush_callback(client->output);
+
+ switch (type) {
+ case IMAP_FILTER_SIEVE_TYPE_DELIVERY:
+ cmd->func = cmd_filter_sieve_delivery;
+ break;
+ case IMAP_FILTER_SIEVE_TYPE_PERSONAL:
+ cmd->func = cmd_filter_sieve_script_parse_name;
+ break;
+ case IMAP_FILTER_SIEVE_TYPE_GLOBAL:
+ cmd->func = cmd_filter_sieve_script_parse_name;
+ break;
+ case IMAP_FILTER_SIEVE_TYPE_SCRIPT:
+ cmd->func = cmd_filter_sieve_script_parse_value;
+ break;
+ }
+ cmd->context = ctx;
+ return cmd->func(cmd);
+}
diff --git a/pigeonhole/src/plugins/imap-filter-sieve/cmd-filter.c b/pigeonhole/src/plugins/imap-filter-sieve/cmd-filter.c
new file mode 100644
index 0000000..2458047
--- /dev/null
+++ b/pigeonhole/src/plugins/imap-filter-sieve/cmd-filter.c
@@ -0,0 +1,57 @@
+/* Copyright (c) 2017-2018 Pigeonhole authors, see the included COPYING file */
+
+#include "imap-common.h"
+
+#include "imap-filter.h"
+#include "imap-filter-sieve.h"
+
+static bool
+cmd_filter_parse_spec(struct imap_filter_context *ctx,
+ const struct imap_arg **_args)
+{
+ const struct imap_arg *args = *_args;
+ struct client_command_context *cmd = ctx->cmd;
+ const char *filter_type;
+
+ /* filter-type */
+ if (IMAP_ARG_IS_EOL(args)) {
+ client_send_command_error(cmd,
+ "Missing filter type.");
+ return TRUE;
+ }
+ if (!imap_arg_get_atom(args, &filter_type)) {
+ client_send_command_error(cmd,
+ "Filter type is not an atom.");
+ return TRUE;
+ }
+ if (strcasecmp(filter_type, "SIEVE") != 0) {
+ client_send_command_error(cmd, t_strdup_printf(
+ "Unknown filter type `%s'", filter_type));
+ return TRUE;
+ }
+
+ cmd->func = cmd_filter_sieve;
+ cmd->context = ctx;
+ return cmd_filter_sieve(cmd);
+}
+
+bool cmd_filter(struct client_command_context *cmd)
+{
+ struct imap_filter_context *ctx;
+ const struct imap_arg *args;
+
+ if (!client_read_args(cmd, 1, 0, &args))
+ return FALSE;
+
+ if (!client_verify_open_mailbox(cmd))
+ return TRUE;
+
+ ctx = p_new(cmd->pool, struct imap_filter_context, 1);
+ ctx->cmd = cmd;
+
+ if (!cmd_filter_parse_spec(ctx, &args))
+ return FALSE;
+
+ imap_filter_context_free(ctx);
+ return TRUE;
+}
diff --git a/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.c b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.c
new file mode 100644
index 0000000..3021dbe
--- /dev/null
+++ b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.c
@@ -0,0 +1,56 @@
+/* Copyright (c) 2017-2018 Pigeonhole authors, see the included COPYING file */
+
+#include "imap-common.h"
+#include "str.h"
+
+#include "imap-filter-sieve.h"
+#include "imap-filter-sieve-plugin.h"
+
+static struct module *imap_filter_sieve_module;
+static imap_client_created_func_t *next_hook_client_created;
+
+/*
+ * Client
+ */
+
+static void imap_filter_sieve_plugin_client_created(struct client **clientp)
+{
+ struct client *client = *clientp;
+ struct mail_user *user = client->user;
+
+ if (mail_user_is_plugin_loaded(user, imap_filter_sieve_module)) {
+ client_add_capability(client, "FILTER=SIEVE");
+
+ imap_filter_sieve_client_created(client);
+ }
+
+ if (next_hook_client_created != NULL)
+ next_hook_client_created(clientp);
+}
+
+/*
+ * Plugin
+ */
+
+const char *imap_filter_sieve_plugin_version = DOVECOT_ABI_VERSION;
+const char imap_filter_sieve_plugin_binary_dependency[] = "imap";
+
+void imap_filter_sieve_plugin_init(struct module *module)
+{
+ command_register("FILTER", cmd_filter, COMMAND_FLAG_USES_SEQS);
+ command_register("UID FILTER", cmd_filter, COMMAND_FLAG_BREAKS_SEQS);
+
+ imap_filter_sieve_module = module;
+ next_hook_client_created = imap_client_created_hook_set(
+ imap_filter_sieve_plugin_client_created);
+ imap_filter_sieve_init(module);
+}
+
+void imap_filter_sieve_plugin_deinit(void)
+{
+ command_unregister("FILTER");
+ command_unregister("UID FILTER");
+
+ imap_filter_sieve_deinit();
+ imap_client_created_hook_set(next_hook_client_created);
+}
diff --git a/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.h b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.h
new file mode 100644
index 0000000..59b4b11
--- /dev/null
+++ b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.h
@@ -0,0 +1,16 @@
+/* Copyright (c) 2017-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#ifndef IMAP_FILTER_SIEVE_PLUGIN_H
+#define IMAP_FILTER_SIEVE_PLUGIN_H
+
+struct module;
+
+extern const char imap_filter_sieve_plugin_binary_dependency[];
+
+bool cmd_filter(struct client_command_context *cmd);
+
+void imap_filter_sieve_plugin_init(struct module *module);
+void imap_filter_sieve_plugin_deinit(void);
+
+#endif
diff --git a/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve.c b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve.c
new file mode 100644
index 0000000..62519f4
--- /dev/null
+++ b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve.c
@@ -0,0 +1,1188 @@
+/* Copyright (c) 2017-2018 Pigeonhole authors, see the included COPYING file */
+
+#include "imap-common.h"
+#include "str.h"
+#include "ioloop.h"
+#include "time-util.h"
+#include "module-context.h"
+#include "message-address.h"
+#include "mail-user.h"
+#include "mail-duplicate.h"
+#include "mail-storage-private.h"
+#include "iostream-ssl.h"
+#include "smtp-submit.h"
+#include "sieve.h"
+#include "sieve-storage.h"
+#include "sieve-script.h"
+
+#include "imap-filter-sieve.h"
+
+#define DUPLICATE_DB_NAME "lda-dupes"
+
+#define IMAP_FILTER_SIEVE_USER_CONTEXT(obj) \
+ MODULE_CONTEXT(obj, imap_filter_sieve_user_module)
+#define IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(obj) \
+ MODULE_CONTEXT_REQUIRE(obj, imap_filter_sieve_user_module)
+
+struct imap_filter_sieve_script {
+ struct sieve_script *script;
+ struct sieve_binary *binary;
+
+ /* Compile failed once with this error;
+ don't try again for this transaction */
+ enum sieve_error compile_error;
+
+ /* Binary corrupt after recompile; don't recompile again */
+ bool binary_corrupt:1;
+ /* Resource usage exceeded */
+ bool rusage_exceeded:1;
+};
+
+struct imap_filter_sieve_user {
+ union mail_user_module_context module_ctx;
+ struct client *client;
+
+ struct sieve_instance *svinst;
+ struct sieve_storage *storage;
+ struct sieve_storage *global_storage;
+
+ struct mail_duplicate_db *dup_db;
+
+ struct sieve_error_handler *master_ehandler;
+};
+
+static MODULE_CONTEXT_DEFINE_INIT(imap_filter_sieve_user_module,
+ &mail_user_module_register);
+
+/*
+ *
+ */
+
+static const char *
+imap_filter_sieve_get_setting(void *context, const char *identifier)
+{
+ struct imap_filter_sieve_user *ifsuser = context;
+ struct mail_user *user = ifsuser->client->user;
+
+ return mail_user_plugin_getenv(user, identifier);
+}
+
+static const struct sieve_callbacks imap_filter_sieve_callbacks = {
+ NULL,
+ imap_filter_sieve_get_setting
+};
+
+static struct sieve_instance *
+imap_filter_sieve_get_svinst(struct imap_filter_sieve_context *sctx)
+{
+ struct mail_user *user = sctx->user;
+ struct imap_filter_sieve_user *ifsuser =
+ IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(user);
+ struct sieve_environment svenv;
+ const struct mail_storage_settings *mail_set;
+ bool debug = user->mail_debug;
+
+ if (ifsuser->svinst != NULL)
+ return ifsuser->svinst;
+
+ mail_set = mail_user_set_get_storage_set(user);
+
+ ifsuser->dup_db = mail_duplicate_db_init(user, DUPLICATE_DB_NAME);
+
+ i_zero(&svenv);
+ svenv.username = user->username;
+ (void)mail_user_get_home(user, &svenv.home_dir);
+ svenv.hostname = mail_set->hostname;
+ svenv.base_dir = user->set->base_dir;
+ svenv.event_parent = ifsuser->client->event;
+ svenv.flags = SIEVE_FLAG_HOME_RELATIVE;
+ svenv.location = SIEVE_ENV_LOCATION_MS;
+ svenv.delivery_phase = SIEVE_DELIVERY_PHASE_POST;
+
+ ifsuser->svinst = sieve_init(&svenv, &imap_filter_sieve_callbacks,
+ ifsuser, debug);
+
+ ifsuser->master_ehandler =
+ sieve_master_ehandler_create(ifsuser->svinst, 0);
+ sieve_error_handler_accept_infolog(ifsuser->master_ehandler, TRUE);
+ sieve_error_handler_accept_debuglog(ifsuser->master_ehandler, debug);
+
+ return ifsuser->svinst;
+}
+
+static void
+imap_filter_sieve_init_trace_log(struct imap_filter_sieve_context *sctx,
+ struct sieve_trace_config *trace_config_r,
+ struct sieve_trace_log **trace_log_r)
+{
+ struct sieve_instance *svinst = imap_filter_sieve_get_svinst(sctx);
+ struct client_command_context *cmd = sctx->filter_context->cmd;
+ struct mail_user *user = sctx->user;
+
+ if (sctx->trace_log_initialized) {
+ *trace_config_r = sctx->trace_config;
+ *trace_log_r = sctx->trace_log;
+ return;
+ }
+ sctx->trace_log_initialized = TRUE;
+
+ if (sieve_trace_config_get(svinst, &sctx->trace_config) < 0 ||
+ sieve_trace_log_open(svinst, &sctx->trace_log) < 0) {
+ i_zero(&sctx->trace_config);
+ sctx->trace_log = NULL;
+
+ i_zero(trace_config_r);
+ *trace_log_r = NULL;
+ return;
+ }
+
+ /* Write header for trace file */
+ sieve_trace_log_printf(sctx->trace_log,
+ "Sieve trace log for IMAP FILTER=SIEVE:\n"
+ "\n"
+ " Username: %s\n", user->username);
+ if (user->session_id != NULL) {
+ sieve_trace_log_printf(sctx->trace_log,
+ " Session ID: %s\n", user->session_id);
+ }
+ sieve_trace_log_printf(sctx->trace_log,
+ " Mailbox: %s\n"
+ " Command: %s %s %s\n\n",
+ mailbox_get_vname(sctx->filter_context->box),
+ cmd->tag, cmd->name,
+ cmd->human_args != NULL ? cmd->human_args : "");
+
+ *trace_config_r = sctx->trace_config;
+ *trace_log_r = sctx->trace_log;
+}
+
+static int
+imap_filter_sieve_get_personal_storage(struct imap_filter_sieve_context *sctx,
+ struct sieve_storage **storage_r,
+ enum mail_error *error_code_r,
+ const char **error_r)
+{
+ struct mail_user *user = sctx->user;
+ struct imap_filter_sieve_user *ifsuser =
+ IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(user);
+ enum sieve_storage_flags storage_flags = 0;
+ struct sieve_instance *svinst;
+ enum sieve_error error;
+
+ *error_code_r = MAIL_ERROR_NONE;
+ *error_r = NULL;
+
+ if (ifsuser->storage != NULL) {
+ *storage_r = ifsuser->storage;
+ return 0;
+ }
+
+ // FIXME: limit interval between retries
+
+ svinst = imap_filter_sieve_get_svinst(sctx);
+ ifsuser->storage = sieve_storage_create_main(svinst, user,
+ storage_flags, &error);
+ if (ifsuser->storage != NULL) {
+ *storage_r = ifsuser->storage;
+ return 0;
+ }
+
+ switch (error) {
+ case SIEVE_ERROR_NOT_POSSIBLE:
+ *error_r = "Sieve processing is disabled for this user";
+ *error_code_r = MAIL_ERROR_NOTPOSSIBLE;
+ break;
+ case SIEVE_ERROR_NOT_FOUND:
+ *error_r = "Sieve script storage not accessible";
+ *error_code_r = MAIL_ERROR_NOTFOUND;
+ break;
+ default:
+ *error_r = t_strflocaltime(MAIL_ERRSTR_CRITICAL_MSG_STAMP,
+ ioloop_time);
+ *error_code_r = MAIL_ERROR_TEMP;
+ break;
+ }
+
+ return -1;
+}
+
+static int
+imap_filter_sieve_get_global_storage(struct imap_filter_sieve_context *sctx,
+ struct sieve_storage **storage_r,
+ enum mail_error *error_code_r,
+ const char **error_r)
+{
+ struct mail_user *user = sctx->user;
+ struct imap_filter_sieve_user *ifsuser =
+ IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(user);
+ struct sieve_instance *svinst;
+ const char *location;
+ enum sieve_error error;
+
+ *error_code_r = MAIL_ERROR_NONE;
+ *error_r = NULL;
+
+ if (ifsuser->global_storage != NULL) {
+ *storage_r = ifsuser->global_storage;
+ return 0;
+ }
+
+ svinst = imap_filter_sieve_get_svinst(sctx);
+
+ location = mail_user_plugin_getenv(user, "sieve_global");
+ if (location == NULL) {
+ e_info(sieve_get_event(svinst),
+ "include: sieve_global is unconfigured; "
+ "include of `:global' script is therefore not possible");
+ *error_code_r = MAIL_ERROR_NOTFOUND;
+ *error_r = "No global Sieve scripts available";
+ return -1;
+ }
+ ifsuser->global_storage =
+ sieve_storage_create(svinst, location, 0, &error);
+ if (ifsuser->global_storage != NULL) {
+ *storage_r = ifsuser->global_storage;
+ return 0;
+ }
+
+ switch (error) {
+ case SIEVE_ERROR_NOT_POSSIBLE:
+ case SIEVE_ERROR_NOT_FOUND:
+ *error_r = "No global Sieve scripts available";
+ *error_code_r = MAIL_ERROR_NOTFOUND;
+ break;
+ default:
+ *error_r = t_strflocaltime(MAIL_ERRSTR_CRITICAL_MSG_STAMP,
+ ioloop_time);
+ *error_code_r = MAIL_ERROR_TEMP;
+ break;
+ }
+
+ return -1;
+}
+
+/*
+ *
+ */
+
+struct imap_filter_sieve_context *
+imap_filter_sieve_context_create(struct imap_filter_context *ctx,
+ enum imap_filter_sieve_type type)
+{
+ struct client_command_context *cmd = ctx->cmd;
+ struct imap_filter_sieve_context *sctx;
+
+ sctx = p_new(cmd->pool, struct imap_filter_sieve_context, 1);
+ sctx->pool = cmd->pool;
+ sctx->filter_context = ctx;
+ sctx->filter_type = type;
+ sctx->user = ctx->cmd->client->user;
+
+ return sctx;
+}
+
+void imap_filter_sieve_context_free(struct imap_filter_sieve_context **_sctx)
+{
+ struct imap_filter_sieve_context *sctx = *_sctx;
+ struct imap_filter_sieve_script *scripts;
+ unsigned int i;
+
+ *_sctx = NULL;
+
+ if (sctx == NULL)
+ return;
+
+ scripts = sctx->scripts;
+ for (i = 0; i < sctx->scripts_count; i++) {
+ if (scripts[i].binary != NULL)
+ sieve_close(&scripts[i].binary);
+ if (scripts[i].script != NULL)
+ sieve_script_unref(&scripts[i].script);
+ }
+
+ if (sctx->trace_log != NULL)
+ sieve_trace_log_free(&sctx->trace_log);
+
+ str_free(&sctx->errors);
+}
+
+/*
+ * Error handling
+ */
+
+static struct sieve_error_handler *
+imap_filter_sieve_create_error_handler(struct imap_filter_sieve_context *sctx)
+{
+ struct sieve_instance *svinst = imap_filter_sieve_get_svinst(sctx);
+
+ /* Prepare error handler */
+ if (sctx->errors == NULL)
+ sctx->errors = str_new(default_pool, 1024);
+ else
+ str_truncate(sctx->errors, 0);
+ return sieve_strbuf_ehandler_create(svinst, sctx->errors, TRUE,
+ 10 /* client->set->_max_compile_errors */);
+}
+
+/*
+ *
+ */
+
+static struct sieve_binary *
+imap_sieve_filter_open_script(struct imap_filter_sieve_context *sctx,
+ struct sieve_script *script,
+ enum sieve_compile_flags cpflags,
+ struct sieve_error_handler *user_ehandler,
+ bool recompile, enum sieve_error *error_r)
+{
+ struct mail_user *user = sctx->user;
+ struct imap_filter_sieve_user *ifsuser =
+ IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(user);
+ struct sieve_instance *svinst = imap_filter_sieve_get_svinst(sctx);
+ struct sieve_error_handler *ehandler;
+ struct sieve_binary *sbin;
+ const char *compile_name = "compile";
+
+ if (recompile) {
+ /* Warn */
+ e_warning(sieve_get_event(svinst),
+ "Encountered corrupt binary: re-compiling script %s",
+ sieve_script_location(script));
+ compile_name = "re-compile";
+ } else {
+ e_debug(sieve_get_event(svinst), "Loading script %s",
+ sieve_script_location(script));
+ }
+
+ if (script == sctx->user_script)
+ ehandler = user_ehandler;
+ else
+ ehandler = ifsuser->master_ehandler;
+ sieve_error_handler_reset(ehandler);
+
+ /* Load or compile the sieve script */
+ if (recompile) {
+ sbin = sieve_compile_script(script, ehandler, cpflags, error_r);
+ } else {
+ sbin = sieve_open_script(script, ehandler, cpflags, error_r);
+ }
+
+ /* Handle error */
+ if (sbin == NULL) {
+ switch (*error_r) {
+ /* Script not found */
+ case SIEVE_ERROR_NOT_FOUND:
+ e_debug(sieve_get_event(svinst),
+ "Script `%s' is missing for %s",
+ sieve_script_location(script), compile_name);
+ break;
+ /* Temporary failure */
+ case SIEVE_ERROR_TEMP_FAILURE:
+ e_error(sieve_get_event(svinst),
+ "Failed to open script `%s' for %s "
+ "(temporary failure)",
+ sieve_script_location(script), compile_name);
+ break;
+ /* Compile failed */
+ case SIEVE_ERROR_NOT_VALID:
+ if (script == sctx->user_script)
+ break;
+ e_error(sieve_get_event(svinst),
+ "Failed to %s script `%s'",
+ compile_name, sieve_script_location(script));
+ break;
+ /* Cumulative resource limit exceeded */
+ case SIEVE_ERROR_RESOURCE_LIMIT:
+ e_error(sieve_get_event(svinst),
+ "Failed to open script `%s' for %s "
+ "(cumulative resource limit exceeded)",
+ sieve_script_location(script), compile_name);
+ break;
+ /* Something else */
+ default:
+ e_error(sieve_get_event(svinst),
+ "Failed to open script `%s' for %s",
+ sieve_script_location(script), compile_name);
+ break;
+ }
+
+ return NULL;
+ }
+
+ if (!recompile)
+ (void)sieve_save(sbin, FALSE, NULL);
+ return sbin;
+}
+
+int imap_filter_sieve_compile(struct imap_filter_sieve_context *sctx,
+ string_t **errors_r, bool *have_warnings_r)
+{
+ struct imap_filter_sieve_script *scripts = sctx->scripts;
+ unsigned int count = sctx->scripts_count, i;
+ struct sieve_error_handler *ehandler;
+ enum sieve_error error;
+ int ret = 0;
+
+ *errors_r = NULL;
+ *have_warnings_r = FALSE;
+
+ /* Prepare error handler */
+ ehandler = imap_filter_sieve_create_error_handler(sctx);
+
+ for (i = 0; i < count; i++) {
+ struct sieve_script *script = scripts[i].script;
+
+ i_assert(script != NULL);
+
+ scripts[i].binary =
+ imap_sieve_filter_open_script(sctx, script, 0, ehandler,
+ FALSE, &error);
+ if (scripts[i].binary == NULL) {
+ if (error != SIEVE_ERROR_NOT_VALID) {
+ const char *errormsg =
+ sieve_script_get_last_error(
+ script, &error);
+ if (error != SIEVE_ERROR_NONE) {
+ str_truncate(sctx->errors, 0);
+ str_append(sctx->errors, errormsg);
+ }
+ }
+ ret = -1;
+ break;
+ }
+ }
+
+ if (ret < 0 && str_len(sctx->errors) == 0) {
+ /* Failed, but no user error was logged: log a generic internal
+ error instead. */
+ sieve_internal_error(ehandler, NULL, NULL);
+ }
+
+ *have_warnings_r = (sieve_get_warnings(ehandler) > 0);
+ *errors_r = sctx->errors;
+
+ sieve_error_handler_unref(&ehandler);
+ return ret;
+}
+
+void imap_filter_sieve_open_input(struct imap_filter_sieve_context *sctx,
+ struct istream *input)
+{
+ struct sieve_instance *svinst;
+ struct sieve_script *script;
+
+ svinst = imap_filter_sieve_get_svinst(sctx);
+ script = sieve_data_script_create_from_input(svinst, "script", input);
+
+ sctx->user_script = script;
+ sctx->scripts = p_new(sctx->pool, struct imap_filter_sieve_script, 1);
+ sctx->scripts_count = 1;
+ sctx->scripts[0].script = script;
+}
+
+int imap_filter_sieve_open_personal(struct imap_filter_sieve_context *sctx,
+ const char *name,
+ enum mail_error *error_code_r,
+ const char **error_r)
+{
+ struct sieve_storage *storage;
+ struct sieve_script *script;
+ enum sieve_error error;
+
+ if (imap_filter_sieve_get_personal_storage(sctx, &storage,
+ error_code_r, error_r) < 0)
+ return -1;
+
+ if (name == NULL)
+ script = sieve_storage_active_script_open(storage, NULL);
+ else
+ script = sieve_storage_open_script(storage, name, NULL);
+ if (script == NULL) {
+ *error_r = sieve_storage_get_last_error(storage, &error);
+
+ switch (error) {
+ case SIEVE_ERROR_NOT_FOUND:
+ *error_code_r = MAIL_ERROR_NOTFOUND;
+ break;
+ case SIEVE_ERROR_NOT_POSSIBLE:
+ *error_code_r = MAIL_ERROR_NOTPOSSIBLE;
+ break;
+ default:
+ *error_code_r = MAIL_ERROR_TEMP;
+ }
+ return -1;
+ }
+
+ sctx->user_script = script;
+ sctx->scripts = p_new(sctx->pool, struct imap_filter_sieve_script, 1);
+ sctx->scripts_count = 1;
+ sctx->scripts[0].script = script;
+ return 0;
+}
+
+int imap_filter_sieve_open_global(struct imap_filter_sieve_context *sctx,
+ const char *name,
+ enum mail_error *error_code_r,
+ const char **error_r)
+{
+ struct sieve_storage *storage;
+ struct sieve_script *script;
+ enum sieve_error error;
+
+ if (imap_filter_sieve_get_global_storage(sctx, &storage,
+ error_code_r, error_r) < 0)
+ return -1;
+
+ script = sieve_storage_open_script(storage, name, NULL);
+ if (script == NULL) {
+ *error_r = sieve_storage_get_last_error(storage, &error);
+
+ switch (error) {
+ case SIEVE_ERROR_NOT_FOUND:
+ *error_code_r = MAIL_ERROR_NOTFOUND;
+ break;
+ case SIEVE_ERROR_NOT_POSSIBLE:
+ *error_code_r = MAIL_ERROR_NOTPOSSIBLE;
+ break;
+ default:
+ *error_code_r = MAIL_ERROR_TEMP;
+ }
+ return -1;
+ }
+
+ sctx->user_script = script;
+ sctx->scripts = p_new(sctx->pool, struct imap_filter_sieve_script, 1);
+ sctx->scripts_count = 1;
+ sctx->scripts[0].script = script;
+ return 0;
+}
+
+/*
+ * Mail transmission
+ */
+
+static void *
+imap_filter_sieve_smtp_start(const struct sieve_script_env *senv,
+ const struct smtp_address *mail_from)
+{
+ struct imap_filter_sieve_context *sctx = senv->script_context;
+ struct mail_user *user = sctx->user;
+ struct imap_filter_sieve_user *ifsuser =
+ IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(user);
+ const struct smtp_submit_settings *smtp_set = ifsuser->client->smtp_set;
+ struct ssl_iostream_settings ssl_set;
+ struct smtp_submit_input submit_input;
+
+ i_zero(&ssl_set);
+ mail_user_init_ssl_client_settings(user, &ssl_set);
+
+ i_zero(&submit_input);
+ submit_input.ssl = &ssl_set;
+
+ return (void *)smtp_submit_init_simple(&submit_input, smtp_set,
+ mail_from);
+}
+
+static void
+imap_filter_sieve_smtp_add_rcpt(const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle,
+ const struct smtp_address *rcpt_to)
+{
+ struct smtp_submit *smtp_submit = handle;
+
+ smtp_submit_add_rcpt(smtp_submit, rcpt_to);
+}
+
+static struct ostream *
+imap_filter_sieve_smtp_send(const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle)
+{
+ struct smtp_submit *smtp_submit = handle;
+
+ return smtp_submit_send(smtp_submit);
+}
+
+static void
+imap_filter_sieve_smtp_abort(const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle)
+{
+ struct smtp_submit *smtp_submit = handle;
+
+ smtp_submit_deinit(&smtp_submit);
+}
+
+static int
+imap_filter_sieve_smtp_finish(const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle, const char **error_r)
+{
+ struct smtp_submit *smtp_submit = handle;
+ int ret;
+
+ ret = smtp_submit_run(smtp_submit, error_r);
+ smtp_submit_deinit(&smtp_submit);
+ return ret;
+}
+
+/*
+ * Duplicate checking
+ */
+
+static void *
+imap_filter_sieve_duplicate_transaction_begin(
+ const struct sieve_script_env *senv)
+{
+ struct imap_filter_sieve_context *sctx = senv->script_context;
+ struct imap_filter_sieve_user *ifsuser =
+ IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(sctx->user);
+
+ return mail_duplicate_transaction_begin(ifsuser->dup_db);
+}
+
+static void imap_filter_sieve_duplicate_transaction_commit(void **_dup_trans)
+{
+ struct mail_duplicate_transaction *dup_trans = *_dup_trans;
+
+ *_dup_trans = NULL;
+
+ mail_duplicate_transaction_commit(&dup_trans);
+}
+
+static void imap_filter_sieve_duplicate_transaction_rollback(void **_dup_trans)
+{
+ struct mail_duplicate_transaction *dup_trans = *_dup_trans;
+
+ *_dup_trans = NULL;
+
+ mail_duplicate_transaction_rollback(&dup_trans);
+}
+
+static enum sieve_duplicate_check_result
+imap_filter_sieve_duplicate_check(void *_dup_trans,
+ const struct sieve_script_env *senv,
+ const void *id, size_t id_size)
+{
+ struct mail_duplicate_transaction *dup_trans = _dup_trans;
+
+ switch (mail_duplicate_check(dup_trans, id, id_size,
+ senv->user->username)) {
+ case MAIL_DUPLICATE_CHECK_RESULT_EXISTS:
+ return SIEVE_DUPLICATE_CHECK_RESULT_EXISTS;
+ case MAIL_DUPLICATE_CHECK_RESULT_NOT_FOUND:
+ return SIEVE_DUPLICATE_CHECK_RESULT_NOT_FOUND;
+ case MAIL_DUPLICATE_CHECK_RESULT_DEADLOCK:
+ case MAIL_DUPLICATE_CHECK_RESULT_LOCK_TIMEOUT:
+ return SIEVE_DUPLICATE_CHECK_RESULT_TEMP_FAILURE;
+ case MAIL_DUPLICATE_CHECK_RESULT_IO_ERROR:
+ case MAIL_DUPLICATE_CHECK_RESULT_TOO_MANY_LOCKS:
+ break;
+ }
+ return SIEVE_DUPLICATE_CHECK_RESULT_FAILURE;
+}
+
+static void
+imap_filter_sieve_duplicate_mark(void *_dup_trans,
+ const struct sieve_script_env *senv,
+ const void *id, size_t id_size, time_t time)
+{
+ struct mail_duplicate_transaction *dup_trans = _dup_trans;
+
+ mail_duplicate_mark(dup_trans, id, id_size, senv->user->username, time);
+}
+
+/*
+ * Result logging
+ */
+
+static const char *
+imap_filter_sieve_result_amend_log_message(const struct sieve_script_env *senv,
+ enum log_type log_type ATTR_UNUSED,
+ const char *message)
+{
+ struct imap_filter_sieve_context *sctx = senv->script_context;
+ string_t *str;
+
+ if (sctx->mail == NULL)
+ return message;
+
+ str = t_str_new(256);
+ str_printfa(str, "uid=%u: ", sctx->mail->uid);
+ str_append(str, message);
+ return str_c(str);
+}
+
+/*
+ *
+ */
+
+static int
+imap_sieve_filter_handle_exec_status(struct imap_filter_sieve_context *sctx,
+ struct sieve_script *script, int status,
+ struct sieve_exec_status *estatus,
+ bool *fatal_r)
+{
+ struct imap_filter_sieve_user *ifsuser =
+ IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(sctx->user);
+ struct sieve_instance *svinst = ifsuser->svinst;
+ enum log_type log_level, user_log_level;
+ enum mail_error mail_error = MAIL_ERROR_NONE;
+ int ret = -1;
+
+ *fatal_r = FALSE;
+
+ log_level = user_log_level = LOG_TYPE_ERROR;
+
+ if (estatus->last_storage != NULL && estatus->store_failed) {
+ (void)mail_storage_get_last_error(estatus->last_storage,
+ &mail_error);
+
+ /* Don't bother administrator too much with benign errors */
+ if (mail_error == MAIL_ERROR_NOQUOTA) {
+ log_level = LOG_TYPE_INFO;
+ user_log_level = LOG_TYPE_INFO;
+ }
+ }
+
+ switch (status) {
+ case SIEVE_EXEC_FAILURE:
+ e_log(sieve_get_event(svinst), user_log_level,
+ "Execution of script %s failed",
+ sieve_script_location(script));
+ ret = -1;
+ break;
+ case SIEVE_EXEC_TEMP_FAILURE:
+ e_log(sieve_get_event(svinst), log_level,
+ "Execution of script %s was aborted "
+ "due to temporary failure",
+ sieve_script_location(script));
+ *fatal_r = TRUE;
+ ret = -1;
+ break;
+ case SIEVE_EXEC_BIN_CORRUPT:
+ e_error(sieve_get_event(svinst),
+ "!!BUG!!: Binary compiled from %s is still corrupt; "
+ "bailing out and reverting to default action",
+ sieve_script_location(script));
+ *fatal_r = TRUE;
+ ret = -1;
+ break;
+ case SIEVE_EXEC_RESOURCE_LIMIT:
+ e_error(sieve_get_event(svinst),
+ "Execution of script %s was aborted "
+ "due to excessive resource usage",
+ sieve_script_location(script));
+ *fatal_r = TRUE;
+ ret = -1;
+ break;
+ case SIEVE_EXEC_KEEP_FAILED:
+ e_log(sieve_get_event(svinst), log_level,
+ "Execution of script %s failed "
+ "with unsuccessful implicit keep",
+ sieve_script_location(script));
+ ret = -1;
+ break;
+ case SIEVE_EXEC_OK:
+ ret = (estatus->keep_original ? 0 : 1);
+ break;
+ }
+
+ return ret;
+}
+
+static int
+imap_sieve_filter_run_scripts(struct imap_filter_sieve_context *sctx,
+ struct sieve_error_handler *user_ehandler,
+ const struct sieve_message_data *msgdata,
+ const struct sieve_script_env *scriptenv,
+ bool *fatal_r)
+{
+ struct mail_user *user = sctx->user;
+ struct imap_filter_sieve_user *ifsuser =
+ IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(user);
+ struct sieve_instance *svinst = ifsuser->svinst;
+ struct imap_filter_sieve_script *scripts = sctx->scripts;
+ unsigned int count = sctx->scripts_count;
+ struct sieve_resource_usage *rusage =
+ &scriptenv->exec_status->resource_usage;
+ struct sieve_multiscript *mscript;
+ struct sieve_error_handler *ehandler;
+ struct sieve_script *last_script = NULL;
+ bool user_script = FALSE, more = TRUE, rusage_exceeded = FALSE;
+ enum sieve_compile_flags cpflags;
+ enum sieve_execute_flags exflags;
+ enum sieve_error compile_error = SIEVE_ERROR_NONE;
+ unsigned int i;
+ int ret;
+
+ *fatal_r = FALSE;
+
+ /* Start execution */
+ mscript = sieve_multiscript_start_execute(svinst, msgdata, scriptenv);
+
+ /* Execute scripts */
+ for (i = 0; i < count && more; i++) {
+ struct sieve_script *script = scripts[i].script;
+ struct sieve_binary *sbin = scripts[i].binary;
+ int mstatus;
+
+ if (sbin == NULL) {
+ e_debug(sieve_get_event(svinst),
+ "Skipping script from `%s'",
+ sieve_script_location(script));
+ continue;
+ }
+
+ cpflags = 0;
+ exflags = SIEVE_EXECUTE_FLAG_SKIP_RESPONSES;
+
+ user_script = (script == sctx->user_script);
+ last_script = script;
+
+ if (scripts[i].rusage_exceeded) {
+ rusage_exceeded = TRUE;
+ break;
+ }
+
+ sieve_resource_usage_init(rusage);
+ if (user_script) {
+ cpflags |= SIEVE_COMPILE_FLAG_NOGLOBAL;
+ exflags |= SIEVE_EXECUTE_FLAG_NOGLOBAL;
+ ehandler = user_ehandler;
+ } else {
+ ehandler = ifsuser->master_ehandler;
+ }
+
+ /* Execute */
+ e_debug(sieve_get_event(svinst),
+ "Executing script from `%s'",
+ sieve_get_source(sbin));
+ more = sieve_multiscript_run(mscript,
+ sbin, ehandler, ehandler, exflags);
+
+ mstatus = sieve_multiscript_status(mscript);
+ if (!more && mstatus == SIEVE_EXEC_BIN_CORRUPT &&
+ !scripts[i].binary_corrupt && sieve_is_loaded(sbin)) {
+ /* Close corrupt script */
+ sieve_close(&sbin);
+
+ /* Recompile */
+ scripts[i].binary = sbin =
+ imap_sieve_filter_open_script(
+ sctx, script, cpflags, user_ehandler,
+ FALSE, &compile_error);
+ if (sbin == NULL) {
+ scripts[i].compile_error = compile_error;
+ break;
+ }
+
+ /* Execute again */
+ more = sieve_multiscript_run(mscript, sbin,
+ ehandler, ehandler,
+ exflags);
+
+ /* Save new version */
+
+ mstatus = sieve_multiscript_status(mscript);
+ if (mstatus == SIEVE_EXEC_BIN_CORRUPT)
+ scripts[i].binary_corrupt = TRUE;
+ else if (more)
+ (void)sieve_save(sbin, FALSE, NULL);
+ }
+
+ if (user_script && !sieve_record_resource_usage(sbin, rusage)) {
+ rusage_exceeded = ((i + 1) < count && more);
+ scripts[i].rusage_exceeded = TRUE;
+ break;
+ }
+ }
+
+ /* Finish execution */
+ exflags = SIEVE_EXECUTE_FLAG_SKIP_RESPONSES;
+ ehandler = (user_ehandler != NULL ?
+ user_ehandler : ifsuser->master_ehandler);
+ if (compile_error == SIEVE_ERROR_TEMP_FAILURE) {
+ ret = sieve_multiscript_finish(&mscript, ehandler, exflags,
+ SIEVE_EXEC_TEMP_FAILURE);
+ } else if (rusage_exceeded) {
+ i_assert(last_script != NULL);
+ (void)sieve_multiscript_finish(&mscript, ehandler, exflags,
+ SIEVE_EXEC_TEMP_FAILURE);
+ sieve_error(ehandler, sieve_script_name(last_script),
+ "cumulative resource usage limit exceeded");
+ ret = SIEVE_EXEC_RESOURCE_LIMIT;
+ } else {
+ ret = sieve_multiscript_finish(&mscript, ehandler, exflags,
+ SIEVE_EXEC_OK);
+ }
+
+ /* Don't log additional messages about compile failure */
+ if (compile_error != SIEVE_ERROR_NONE &&
+ ret == SIEVE_EXEC_FAILURE) {
+ e_info(sieve_get_event(svinst),
+ "Aborted script execution sequence "
+ "with successful implicit keep");
+ return 0;
+ }
+
+ if (last_script == NULL && ret == SIEVE_EXEC_OK)
+ return 0;
+ i_assert(last_script != NULL); /* at least one script is executed */
+ return imap_sieve_filter_handle_exec_status(sctx, last_script, ret,
+ scriptenv->exec_status,
+ fatal_r);
+}
+
+static int
+parse_address(const char *address, const struct smtp_address **addr_r)
+{
+ struct message_address *msg_addr;
+ struct smtp_address *smtp_addr;
+
+ if (message_address_parse_path(pool_datastack_create(),
+ (const unsigned char *)address,
+ strlen(address), &msg_addr) < 0) {
+ *addr_r = NULL;
+ return -1;
+ }
+ if (smtp_address_create_from_msg_temp(msg_addr, &smtp_addr) < 0) {
+ *addr_r = NULL;
+ return -1;
+ }
+
+ *addr_r = smtp_addr;
+ return 1;
+}
+
+int imap_sieve_filter_run_init(struct imap_filter_sieve_context *sctx)
+{
+ struct sieve_instance *svinst = imap_filter_sieve_get_svinst(sctx);
+ struct sieve_script_env *scriptenv = &sctx->scriptenv;
+ struct mail_user *user = sctx->user;
+ const char *error;
+
+ if (sieve_script_env_init(scriptenv, user, &error) < 0) {
+ e_error(sieve_get_event(svinst),
+ "Failed to initialize script execution: %s",
+ error);
+ return -1;
+ }
+
+ scriptenv->smtp_start = imap_filter_sieve_smtp_start;
+ scriptenv->smtp_add_rcpt = imap_filter_sieve_smtp_add_rcpt;
+ scriptenv->smtp_send = imap_filter_sieve_smtp_send;
+ scriptenv->smtp_abort = imap_filter_sieve_smtp_abort;
+ scriptenv->smtp_finish = imap_filter_sieve_smtp_finish;
+ scriptenv->duplicate_transaction_begin =
+ imap_filter_sieve_duplicate_transaction_begin;
+ scriptenv->duplicate_transaction_commit =
+ imap_filter_sieve_duplicate_transaction_commit;
+ scriptenv->duplicate_transaction_rollback =
+ imap_filter_sieve_duplicate_transaction_rollback;
+ scriptenv->duplicate_mark = imap_filter_sieve_duplicate_mark;
+ scriptenv->duplicate_check = imap_filter_sieve_duplicate_check;
+ scriptenv->script_context = sctx;
+ return 0;
+}
+
+static void
+imap_sieve_filter_get_msgdata(struct imap_filter_sieve_context *sctx,
+ struct mail *mail,
+ struct sieve_message_data *msgdata_r)
+{
+ struct sieve_instance *svinst = imap_filter_sieve_get_svinst(sctx);
+ struct mail_user *user = sctx->user;
+ const char *address, *error;
+ const struct smtp_address *mail_from, *rcpt_to;
+ struct smtp_address *user_addr;
+ int ret;
+
+ mail_from = NULL;
+ if ((ret = mail_get_special(mail, MAIL_FETCH_FROM_ENVELOPE,
+ &address)) > 0 &&
+ (ret = parse_address(address, &mail_from)) < 0) {
+ e_warning(sieve_get_event(svinst),
+ "Failed to parse message FROM_ENVELOPE");
+ }
+ if (ret <= 0 &&
+ mail_get_first_header(mail, "Return-Path",
+ &address) > 0 &&
+ parse_address(address, &mail_from) < 0) {
+ e_info(sieve_get_event(svinst),
+ "Failed to parse Return-Path header");
+ }
+
+ rcpt_to = NULL;
+ if (mail_get_first_header(mail, "Delivered-To",
+ &address) > 0 &&
+ parse_address(address, &rcpt_to) < 0) {
+ e_info(sieve_get_event(svinst),
+ "Failed to parse Delivered-To header");
+ }
+ if (rcpt_to == NULL) {
+ if (svinst->user_email != NULL)
+ rcpt_to = svinst->user_email;
+ else if (smtp_address_parse_username(sctx->pool, user->username,
+ &user_addr, &error) < 0) {
+ e_warning(sieve_get_event(svinst),
+ "Cannot obtain SMTP address from username `%s': %s",
+ user->username, error);
+ } else {
+ if (user_addr->domain == NULL)
+ user_addr->domain = svinst->domainname;
+ rcpt_to = user_addr;
+ }
+ }
+
+ // FIXME: maybe parse top Received header.
+
+ i_zero(msgdata_r);
+ msgdata_r->mail = mail;
+ msgdata_r->envelope.mail_from = mail_from;
+ msgdata_r->envelope.rcpt_to = rcpt_to;
+ msgdata_r->auth_user = user->username;
+ (void)mail_get_message_id(mail, &msgdata_r->id);
+}
+
+int imap_sieve_filter_run_mail(struct imap_filter_sieve_context *sctx,
+ struct mail *mail, string_t **errors_r,
+ bool *have_warnings_r, bool *have_changes_r,
+ bool *fatal_r)
+{
+ struct sieve_error_handler *user_ehandler;
+ struct sieve_message_data msgdata;
+ struct sieve_script_env *scriptenv = &sctx->scriptenv;
+ struct sieve_exec_status estatus;
+ struct sieve_trace_config trace_config;
+ struct sieve_trace_log *trace_log;
+ int ret;
+
+ *errors_r = NULL;
+ *have_warnings_r = FALSE;
+ *have_changes_r = FALSE;
+ i_zero(&estatus);
+
+ sctx->mail = mail;
+
+ /* Prepare error handler */
+ user_ehandler = imap_filter_sieve_create_error_handler(sctx);
+
+ /* Initialize trace logging */
+ imap_filter_sieve_init_trace_log(sctx, &trace_config, &trace_log);
+
+ T_BEGIN {
+ if (trace_log != NULL) {
+ /* Write trace header for message */
+ sieve_trace_log_printf(trace_log,
+ "Filtering message:\n"
+ "\n"
+ " UID: %u\n", mail->uid);
+ }
+
+ /* Collect necessary message data */
+
+ imap_sieve_filter_get_msgdata(sctx, mail, &msgdata);
+
+ /* Complete script execution environment */
+
+ scriptenv->default_mailbox = mailbox_get_vname(mail->box);
+ scriptenv->result_amend_log_message =
+ imap_filter_sieve_result_amend_log_message;
+ scriptenv->trace_log = trace_log;
+ scriptenv->trace_config = trace_config;
+ scriptenv->script_context = sctx;
+
+ scriptenv->exec_status = &estatus;
+
+ /* Execute script(s) */
+
+ ret = imap_sieve_filter_run_scripts(sctx, user_ehandler,
+ &msgdata, scriptenv,
+ fatal_r);
+ } T_END;
+
+ if (ret < 0 && str_len(sctx->errors) == 0) {
+ /* Failed, but no user error was logged: log a generic internal
+ error instead. */
+ sieve_internal_error(user_ehandler, NULL, NULL);
+ }
+
+ *have_warnings_r = (sieve_get_warnings(user_ehandler) > 0);
+ *have_changes_r = estatus.significant_action_executed;
+ *errors_r = sctx->errors;
+
+ sieve_error_handler_unref(&user_ehandler);
+
+ sctx->mail = NULL;
+
+ return ret;
+}
+
+/*
+ * User
+ */
+
+static void imap_filter_sieve_user_deinit(struct mail_user *user)
+{
+ struct imap_filter_sieve_user *ifsuser =
+ IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(user);
+
+ sieve_error_handler_unref(&ifsuser->master_ehandler);
+
+ if (ifsuser->storage != NULL)
+ sieve_storage_unref(&ifsuser->storage);
+ if (ifsuser->global_storage != NULL)
+ sieve_storage_unref(&ifsuser->global_storage);
+ if (ifsuser->svinst != NULL)
+ sieve_deinit(&ifsuser->svinst);
+ if (ifsuser->dup_db != NULL)
+ mail_duplicate_db_deinit(&ifsuser->dup_db);
+
+ ifsuser->module_ctx.super.deinit(user);
+}
+
+static void imap_filter_sieve_user_created(struct mail_user *user)
+{
+ struct imap_filter_sieve_user *ifsuser;
+ struct mail_user_vfuncs *v = user->vlast;
+
+ ifsuser = p_new(user->pool, struct imap_filter_sieve_user, 1);
+ ifsuser->module_ctx.super = *v;
+ user->vlast = &ifsuser->module_ctx.super;
+ v->deinit = imap_filter_sieve_user_deinit;
+ MODULE_CONTEXT_SET(user, imap_filter_sieve_user_module, ifsuser);
+}
+
+/*
+ * Hooks
+ */
+
+static struct mail_storage_hooks imap_filter_sieve_mail_storage_hooks = {
+ .mail_user_created = imap_filter_sieve_user_created,
+};
+
+/*
+ * Client
+ */
+
+void imap_filter_sieve_client_created(struct client *client)
+{
+ struct imap_filter_sieve_user *ifsuser =
+ IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(client->user);
+
+ ifsuser->client = client;
+}
+
+/*
+ *
+ */
+
+void imap_filter_sieve_init(struct module *module)
+{
+ mail_storage_hooks_add(module, &imap_filter_sieve_mail_storage_hooks);
+}
+
+void imap_filter_sieve_deinit(void)
+{
+ mail_storage_hooks_remove(&imap_filter_sieve_mail_storage_hooks);
+}
+
+
diff --git a/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve.h b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve.h
new file mode 100644
index 0000000..c06cbdb
--- /dev/null
+++ b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve.h
@@ -0,0 +1,97 @@
+#ifndef IMAP_FILTER_SIEVE_H
+#define IMAP_FILTER_SIEVE_H
+
+#include "sieve.h"
+#include "imap-filter.h"
+
+struct imap_filter_sieve_script;
+struct imap_filter_sieve_context;
+
+enum imap_filter_sieve_type {
+ IMAP_FILTER_SIEVE_TYPE_DELIVERY,
+ IMAP_FILTER_SIEVE_TYPE_PERSONAL,
+ IMAP_FILTER_SIEVE_TYPE_GLOBAL,
+ IMAP_FILTER_SIEVE_TYPE_SCRIPT,
+};
+
+struct imap_filter_sieve_context {
+ pool_t pool;
+
+ struct imap_filter_context *filter_context;
+ enum imap_filter_sieve_type filter_type;
+
+ struct mail_user *user;
+
+ struct sieve_script *user_script;
+ struct imap_filter_sieve_script *scripts;
+ unsigned int scripts_count;
+
+ struct mail *mail;
+
+ struct sieve_script_env scriptenv;
+ struct sieve_trace_config trace_config;
+ struct sieve_trace_log *trace_log;
+
+ string_t *errors;
+
+ bool warnings:1;
+ bool trace_log_initialized:1;
+};
+
+/*
+ * FILTER Command
+ */
+
+bool cmd_filter_sieve(struct client_command_context *cmd);
+
+/*
+ * Context
+ */
+
+struct imap_filter_sieve_context *
+imap_filter_sieve_context_create(struct imap_filter_context *ctx,
+ enum imap_filter_sieve_type type);
+void imap_filter_sieve_context_free(struct imap_filter_sieve_context **_sctx);
+
+/*
+ * Compile
+ */
+
+int imap_filter_sieve_compile(struct imap_filter_sieve_context *sctx,
+ string_t **errors_r, bool *have_warnings_r);
+
+/*
+ * Open
+ */
+
+void imap_filter_sieve_open_input(struct imap_filter_sieve_context *sctx,
+ struct istream *input);
+int imap_filter_sieve_open_personal(struct imap_filter_sieve_context *sctx,
+ const char *name,
+ enum mail_error *error_code_r,
+ const char **error_r) ATTR_NULL(2);
+int imap_filter_sieve_open_global(struct imap_filter_sieve_context *sctx,
+ const char *name,
+ enum mail_error *error_code_r,
+ const char **error_r);
+
+/*
+ * Run
+ */
+
+int imap_sieve_filter_run_init(struct imap_filter_sieve_context *sctx);
+int imap_sieve_filter_run_mail(struct imap_filter_sieve_context *sctx,
+ struct mail *mail, string_t **errors_r,
+ bool *have_warnings_r, bool *have_changes_r,
+ bool *fatal_r);
+
+/*
+ *
+ */
+
+void imap_filter_sieve_client_created(struct client *client);
+
+void imap_filter_sieve_init(struct module *module);
+void imap_filter_sieve_deinit(void);
+
+#endif
diff --git a/pigeonhole/src/plugins/imap-filter-sieve/imap-filter.c b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter.c
new file mode 100644
index 0000000..fd7d758
--- /dev/null
+++ b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter.c
@@ -0,0 +1,273 @@
+/* Copyright (c) 2017-2018 Pigeonhole authors, see the included COPYING file */
+
+#include "imap-common.h"
+#include "str.h"
+#include "ostream.h"
+#include "time-util.h"
+#include "imap-resp-code.h"
+#include "imap-search-args.h"
+
+#include "imap-filter.h"
+#include "imap-filter-sieve.h"
+
+static void imap_filter_args_check(struct imap_filter_context *ctx,
+ const struct mail_search_arg *sargs)
+{
+ for (; sargs != NULL; sargs = sargs->next) {
+ switch (sargs->type) {
+ case SEARCH_SEQSET:
+ ctx->have_seqsets = TRUE;
+ break;
+ case SEARCH_MODSEQ:
+ ctx->have_modseqs = TRUE;
+ break;
+ case SEARCH_OR:
+ case SEARCH_SUB:
+ imap_filter_args_check(ctx, sargs->value.subargs);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static bool
+imap_filter_mail(struct client_command_context *cmd, struct mail *mail)
+{
+ struct imap_filter_context *ctx = cmd->context;
+ struct client *client = cmd->client;
+ string_t *errors = NULL;
+ bool have_warnings = FALSE, have_changes = FALSE, fatal = FALSE;
+ string_t *reply = t_str_new(128);
+ int ret;
+
+ ret = imap_sieve_filter_run_mail(ctx->sieve, mail, &errors,
+ &have_warnings, &have_changes, &fatal);
+
+ str_printfa(reply, "* %u FILTERED (TAG %s) UID %u ",
+ mail->seq, cmd->tag, mail->uid);
+ if (ret < 0 || have_warnings) {
+ str_printfa(reply, "%s {%zu}\r\n",
+ (ret < 0 ? "ERRORS" : "WARNINGS"),
+ str_len(errors));
+ str_append_str(reply, errors);
+ str_append(reply, "\r\n");
+ } else if (have_changes || ret > 0) {
+ str_append(reply, "OK\r\n");
+ } else {
+ str_truncate(reply, 0);
+ }
+ if (str_len(reply) > 0)
+ o_stream_nsend(client->output, str_data(reply), str_len(reply));
+
+ /* Handle the result */
+ if (ret < 0) {
+ /* Sieve error; keep */
+ } else {
+ if (ret > 0) {
+ /* Discard */
+ mail_update_flags(mail, MODIFY_ADD, MAIL_DELETED);
+ }
+ }
+
+ return !fatal;
+}
+
+static bool imap_filter_more(struct client_command_context *cmd)
+{
+ struct imap_filter_context *ctx = cmd->context;
+ struct mail *mail;
+ enum mailbox_sync_flags sync_flags;
+ const char *ok_reply;
+ bool tryagain, lost_data;
+
+ if (cmd->cancel) {
+ (void)imap_filter_deinit(ctx);
+ return TRUE;
+ }
+
+ while (mailbox_search_next_nonblock(ctx->search_ctx,
+ &mail, &tryagain)) {
+ bool ret;
+ T_BEGIN {
+ ret = imap_filter_mail(cmd, mail);
+ } T_END;
+ if (!ret)
+ break;
+ }
+ if (tryagain)
+ return FALSE;
+
+ lost_data = mailbox_search_seen_lost_data(ctx->search_ctx);
+ if (imap_filter_deinit(ctx) < 0) {
+ client_send_box_error(cmd, cmd->client->mailbox);
+ return TRUE;
+ }
+
+ sync_flags = MAILBOX_SYNC_FLAG_FAST;
+ if (!cmd->uid || ctx->have_seqsets)
+ sync_flags |= MAILBOX_SYNC_FLAG_NO_EXPUNGES;
+ ok_reply = t_strdup_printf("OK %sFilter completed",
+ lost_data ? "["IMAP_RESP_CODE_EXPUNGEISSUED"] " : "");
+ return cmd_sync(cmd, sync_flags, 0, ok_reply);
+}
+
+static void imap_filter_more_callback(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ bool finished;
+
+ o_stream_cork(client->output);
+ finished = command_exec(cmd);
+ o_stream_uncork(client->output);
+
+ if (!finished)
+ (void)client_handle_unfinished_cmd(cmd);
+ else
+ client_command_free(&cmd);
+ cmd_sync_delayed(client);
+
+ if (client->disconnected)
+ client_destroy(client, NULL);
+ else
+ client_continue_pending_input(client);
+}
+
+static bool
+imap_filter_start(struct imap_filter_context *ctx,
+ struct mail_search_args *sargs)
+{
+ struct client_command_context *cmd = ctx->cmd;
+
+ imap_filter_args_check(ctx, sargs->args);
+
+ if (ctx->have_modseqs)
+ (void)client_enable(cmd->client, MAILBOX_FEATURE_CONDSTORE);
+
+ ctx->box = cmd->client->mailbox;
+ ctx->trans = mailbox_transaction_begin(ctx->box, 0,
+ imap_client_command_get_reason(cmd));
+ ctx->sargs = sargs;
+ ctx->search_ctx = mailbox_search_init(ctx->trans, sargs, NULL, 0, NULL);
+
+ if (imap_sieve_filter_run_init(ctx->sieve) < 0) {
+ const char *error = t_strflocaltime(
+ MAIL_ERRSTR_CRITICAL_MSG_STAMP, ioloop_time);
+
+ o_stream_nsend_str(cmd->client->output,
+ t_strdup_printf("* FILTER (TAG %s) "
+ "ERRORS {%zu}\r\n%s\r\n",
+ cmd->tag, strlen(error), error));
+ client_send_tagline(cmd,
+ "NO Failed to initialize script execution");
+ (void)imap_filter_deinit(ctx);
+ return TRUE;
+ }
+
+ cmd->func = imap_filter_more;
+ cmd->context = ctx;
+
+ if (imap_filter_more(cmd))
+ return TRUE;
+
+ /* we may have moved onto syncing by now */
+ if (cmd->func == imap_filter_more) {
+ ctx->to = timeout_add(0, imap_filter_more_callback, cmd);
+ cmd->state = CLIENT_COMMAND_STATE_WAIT_EXTERNAL;
+ }
+ return FALSE;
+}
+
+static bool
+imap_filter_parse_search(struct imap_filter_context *ctx,
+ const struct imap_arg *args)
+{
+ struct client_command_context *cmd = ctx->cmd;
+ struct mail_search_args *sargs;
+ const char *charset;
+ int ret;
+
+ if (imap_arg_atom_equals(args, "CHARSET")) {
+ /* CHARSET specified */
+ if (!imap_arg_get_astring(&args[1], &charset)) {
+ client_send_command_error(cmd,
+ "Invalid charset argument.");
+ imap_filter_context_free(ctx);
+ return TRUE;
+ }
+ args += 2;
+ } else {
+ charset = "UTF-8";
+ }
+
+ ret = imap_search_args_build(cmd, args, charset, &sargs);
+ if (ret <= 0) {
+ imap_filter_context_free(ctx);
+ return ret < 0;
+ }
+
+ return imap_filter_start(ctx, sargs);
+}
+
+bool imap_filter_search(struct client_command_context *cmd)
+{
+ struct imap_filter_context *ctx = cmd->context;
+ const struct imap_arg *args;
+ const char *error;
+ enum imap_parser_error parse_error;
+ int ret;
+
+ ret = imap_parser_read_args(ctx->parser, 0, 0, &args);
+ if (ret < 0) {
+ if (ret == -2)
+ return FALSE;
+ error = imap_parser_get_error(ctx->parser, &parse_error);
+ switch (parse_error) {
+ case IMAP_PARSE_ERROR_NONE:
+ i_unreached();
+ case IMAP_PARSE_ERROR_LITERAL_TOO_BIG:
+ client_disconnect_with_error(ctx->cmd->client, error);
+ break;
+ default:
+ client_send_command_error(ctx->cmd, error);
+ break;
+ }
+ return TRUE;
+ }
+ return imap_filter_parse_search(ctx, args);
+}
+
+int imap_filter_deinit(struct imap_filter_context *ctx)
+{
+ int ret = 0;
+
+ o_stream_set_flush_callback(ctx->cmd->client->output,
+ client_output, ctx->cmd->client);
+ ctx->cmd->client->input_lock = NULL;
+ imap_parser_unref(&ctx->parser);
+
+ if (ctx->search_ctx != NULL &&
+ mailbox_search_deinit(&ctx->search_ctx) < 0)
+ ret = -1;
+
+ if (ctx->trans != NULL)
+ (void)mailbox_transaction_commit(&ctx->trans);
+
+ timeout_remove(&ctx->to);
+ if (ctx->sargs != NULL) {
+ mail_search_args_deinit(ctx->sargs);
+ mail_search_args_unref(&ctx->sargs);
+ }
+ imap_filter_context_free(ctx);
+
+ ctx->cmd->context = NULL;
+ return ret;
+}
+
+void imap_filter_context_free(struct imap_filter_context *ctx)
+{
+ imap_filter_sieve_context_free(&ctx->sieve);
+}
+
+
+
diff --git a/pigeonhole/src/plugins/imap-filter-sieve/imap-filter.h b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter.h
new file mode 100644
index 0000000..d504704
--- /dev/null
+++ b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter.h
@@ -0,0 +1,43 @@
+#ifndef IMAP_FILTER_H
+#define IMAP_FILTER_H
+
+struct mail_duplicate_db;
+
+struct sieve_script;
+struct sieve_storage;
+struct sieve_binary;
+
+struct imap_filter_context {
+ struct client_command_context *cmd;
+ struct mailbox *box;
+ struct mailbox_transaction_context *trans;
+ struct mail_search_context *search_ctx;
+
+ struct imap_parser *parser;
+
+ struct imap_filter_sieve_context *sieve;
+ const char *script_name;
+ uoff_t script_len;
+ struct istream *script_input;
+
+ struct mail_search_args *sargs;
+
+ struct timeout *to;
+
+ bool failed:1;
+ bool compile_failure:1;
+ bool have_seqsets:1;
+ bool have_modseqs:1;
+};
+
+bool imap_filter_search(struct client_command_context *cmd);
+
+int imap_filter_deinit(struct imap_filter_context *ctx);
+
+void imap_filter_context_free(struct imap_filter_context *ctx);
+
+/* Commands */
+
+bool cmd_filter(struct client_command_context *cmd);
+
+#endif
diff --git a/pigeonhole/src/plugins/imapsieve/Makefile.am b/pigeonhole/src/plugins/imapsieve/Makefile.am
new file mode 100644
index 0000000..1fea23e
--- /dev/null
+++ b/pigeonhole/src/plugins/imapsieve/Makefile.am
@@ -0,0 +1,40 @@
+imap_moduledir = $(dovecot_moduledir)
+sieve_plugindir = $(dovecot_moduledir)/sieve
+
+imap_module_LTLIBRARIES = lib95_imap_sieve_plugin.la
+sieve_plugin_LTLIBRARIES = lib90_sieve_imapsieve_plugin.la
+
+lib95_imap_sieve_plugin_la_LDFLAGS = -module -avoid-version
+lib90_sieve_imapsieve_plugin_la_LDFLAGS = -module -avoid-version
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib-sieve \
+ -I$(top_srcdir)/src/lib-sieve/util \
+ -I$(top_srcdir)/src/lib-sieve/plugins/environment \
+ $(LIBDOVECOT_IMAP_INCLUDE) \
+ $(LIBDOVECOT_LDA_INCLUDE) \
+ $(LIBDOVECOT_INCLUDE) \
+ -DPKG_RUNDIR=\""$(rundir)"\"
+
+lib95_imap_sieve_plugin_la_SOURCES = \
+ ext-imapsieve.c \
+ ext-imapsieve-environment.c \
+ imap-sieve.c \
+ imap-sieve-storage.c \
+ imap-sieve-plugin.c
+lib95_imap_sieve_plugin_la_LIBADD = \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la
+
+lib90_sieve_imapsieve_plugin_la_SOURCES = \
+ ext-imapsieve.c \
+ sieve-imapsieve-plugin.c
+lib90_sieve_imapsieve_plugin_la_CPPFLAGS = \
+ ${AM_CPPFLAGS} \
+ -D__IMAPSIEVE_DUMMY
+
+noinst_HEADERS = \
+ ext-imapsieve-common.h \
+ imap-sieve.h \
+ imap-sieve-storage.h \
+ imap-sieve-plugin.h \
+ sieve-imapsieve-plugin.h
diff --git a/pigeonhole/src/plugins/imapsieve/Makefile.in b/pigeonhole/src/plugins/imapsieve/Makefile.in
new file mode 100644
index 0000000..648975b
--- /dev/null
+++ b/pigeonhole/src/plugins/imapsieve/Makefile.in
@@ -0,0 +1,864 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/plugins/imapsieve
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(imap_moduledir)" \
+ "$(DESTDIR)$(sieve_plugindir)"
+LTLIBRARIES = $(imap_module_LTLIBRARIES) $(sieve_plugin_LTLIBRARIES)
+lib90_sieve_imapsieve_plugin_la_LIBADD =
+am_lib90_sieve_imapsieve_plugin_la_OBJECTS = \
+ lib90_sieve_imapsieve_plugin_la-ext-imapsieve.lo \
+ lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.lo
+lib90_sieve_imapsieve_plugin_la_OBJECTS = \
+ $(am_lib90_sieve_imapsieve_plugin_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+lib90_sieve_imapsieve_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) \
+ $(lib90_sieve_imapsieve_plugin_la_LDFLAGS) $(LDFLAGS) -o $@
+lib95_imap_sieve_plugin_la_DEPENDENCIES = \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la
+am_lib95_imap_sieve_plugin_la_OBJECTS = ext-imapsieve.lo \
+ ext-imapsieve-environment.lo imap-sieve.lo \
+ imap-sieve-storage.lo imap-sieve-plugin.lo
+lib95_imap_sieve_plugin_la_OBJECTS = \
+ $(am_lib95_imap_sieve_plugin_la_OBJECTS)
+lib95_imap_sieve_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(lib95_imap_sieve_plugin_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ext-imapsieve-environment.Plo \
+ ./$(DEPDIR)/ext-imapsieve.Plo \
+ ./$(DEPDIR)/imap-sieve-plugin.Plo \
+ ./$(DEPDIR)/imap-sieve-storage.Plo ./$(DEPDIR)/imap-sieve.Plo \
+ ./$(DEPDIR)/lib90_sieve_imapsieve_plugin_la-ext-imapsieve.Plo \
+ ./$(DEPDIR)/lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(lib90_sieve_imapsieve_plugin_la_SOURCES) \
+ $(lib95_imap_sieve_plugin_la_SOURCES)
+DIST_SOURCES = $(lib90_sieve_imapsieve_plugin_la_SOURCES) \
+ $(lib95_imap_sieve_plugin_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+imap_moduledir = $(dovecot_moduledir)
+sieve_plugindir = $(dovecot_moduledir)/sieve
+imap_module_LTLIBRARIES = lib95_imap_sieve_plugin.la
+sieve_plugin_LTLIBRARIES = lib90_sieve_imapsieve_plugin.la
+lib95_imap_sieve_plugin_la_LDFLAGS = -module -avoid-version
+lib90_sieve_imapsieve_plugin_la_LDFLAGS = -module -avoid-version
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib-sieve \
+ -I$(top_srcdir)/src/lib-sieve/util \
+ -I$(top_srcdir)/src/lib-sieve/plugins/environment \
+ $(LIBDOVECOT_IMAP_INCLUDE) \
+ $(LIBDOVECOT_LDA_INCLUDE) \
+ $(LIBDOVECOT_INCLUDE) \
+ -DPKG_RUNDIR=\""$(rundir)"\"
+
+lib95_imap_sieve_plugin_la_SOURCES = \
+ ext-imapsieve.c \
+ ext-imapsieve-environment.c \
+ imap-sieve.c \
+ imap-sieve-storage.c \
+ imap-sieve-plugin.c
+
+lib95_imap_sieve_plugin_la_LIBADD = \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la
+
+lib90_sieve_imapsieve_plugin_la_SOURCES = \
+ ext-imapsieve.c \
+ sieve-imapsieve-plugin.c
+
+lib90_sieve_imapsieve_plugin_la_CPPFLAGS = \
+ ${AM_CPPFLAGS} \
+ -D__IMAPSIEVE_DUMMY
+
+noinst_HEADERS = \
+ ext-imapsieve-common.h \
+ imap-sieve.h \
+ imap-sieve-storage.h \
+ imap-sieve-plugin.h \
+ sieve-imapsieve-plugin.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/imapsieve/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/plugins/imapsieve/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-imap_moduleLTLIBRARIES: $(imap_module_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(imap_module_LTLIBRARIES)'; test -n "$(imap_moduledir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(imap_moduledir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(imap_moduledir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(imap_moduledir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(imap_moduledir)"; \
+ }
+
+uninstall-imap_moduleLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(imap_module_LTLIBRARIES)'; test -n "$(imap_moduledir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(imap_moduledir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(imap_moduledir)/$$f"; \
+ done
+
+clean-imap_moduleLTLIBRARIES:
+ -test -z "$(imap_module_LTLIBRARIES)" || rm -f $(imap_module_LTLIBRARIES)
+ @list='$(imap_module_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+install-sieve_pluginLTLIBRARIES: $(sieve_plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(sieve_plugin_LTLIBRARIES)'; test -n "$(sieve_plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sieve_plugindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sieve_plugindir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(sieve_plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(sieve_plugindir)"; \
+ }
+
+uninstall-sieve_pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sieve_plugin_LTLIBRARIES)'; test -n "$(sieve_plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(sieve_plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(sieve_plugindir)/$$f"; \
+ done
+
+clean-sieve_pluginLTLIBRARIES:
+ -test -z "$(sieve_plugin_LTLIBRARIES)" || rm -f $(sieve_plugin_LTLIBRARIES)
+ @list='$(sieve_plugin_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+lib90_sieve_imapsieve_plugin.la: $(lib90_sieve_imapsieve_plugin_la_OBJECTS) $(lib90_sieve_imapsieve_plugin_la_DEPENDENCIES) $(EXTRA_lib90_sieve_imapsieve_plugin_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(lib90_sieve_imapsieve_plugin_la_LINK) -rpath $(sieve_plugindir) $(lib90_sieve_imapsieve_plugin_la_OBJECTS) $(lib90_sieve_imapsieve_plugin_la_LIBADD) $(LIBS)
+
+lib95_imap_sieve_plugin.la: $(lib95_imap_sieve_plugin_la_OBJECTS) $(lib95_imap_sieve_plugin_la_DEPENDENCIES) $(EXTRA_lib95_imap_sieve_plugin_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(lib95_imap_sieve_plugin_la_LINK) -rpath $(imap_moduledir) $(lib95_imap_sieve_plugin_la_OBJECTS) $(lib95_imap_sieve_plugin_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-imapsieve-environment.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-imapsieve.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-sieve-plugin.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-sieve-storage.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-sieve.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib90_sieve_imapsieve_plugin_la-ext-imapsieve.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+lib90_sieve_imapsieve_plugin_la-ext-imapsieve.lo: ext-imapsieve.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib90_sieve_imapsieve_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib90_sieve_imapsieve_plugin_la-ext-imapsieve.lo -MD -MP -MF $(DEPDIR)/lib90_sieve_imapsieve_plugin_la-ext-imapsieve.Tpo -c -o lib90_sieve_imapsieve_plugin_la-ext-imapsieve.lo `test -f 'ext-imapsieve.c' || echo '$(srcdir)/'`ext-imapsieve.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib90_sieve_imapsieve_plugin_la-ext-imapsieve.Tpo $(DEPDIR)/lib90_sieve_imapsieve_plugin_la-ext-imapsieve.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ext-imapsieve.c' object='lib90_sieve_imapsieve_plugin_la-ext-imapsieve.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib90_sieve_imapsieve_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib90_sieve_imapsieve_plugin_la-ext-imapsieve.lo `test -f 'ext-imapsieve.c' || echo '$(srcdir)/'`ext-imapsieve.c
+
+lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.lo: sieve-imapsieve-plugin.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib90_sieve_imapsieve_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.lo -MD -MP -MF $(DEPDIR)/lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.Tpo -c -o lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.lo `test -f 'sieve-imapsieve-plugin.c' || echo '$(srcdir)/'`sieve-imapsieve-plugin.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.Tpo $(DEPDIR)/lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sieve-imapsieve-plugin.c' object='lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib90_sieve_imapsieve_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.lo `test -f 'sieve-imapsieve-plugin.c' || echo '$(srcdir)/'`sieve-imapsieve-plugin.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(imap_moduledir)" "$(DESTDIR)$(sieve_plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-imap_moduleLTLIBRARIES clean-libtool \
+ clean-sieve_pluginLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ext-imapsieve-environment.Plo
+ -rm -f ./$(DEPDIR)/ext-imapsieve.Plo
+ -rm -f ./$(DEPDIR)/imap-sieve-plugin.Plo
+ -rm -f ./$(DEPDIR)/imap-sieve-storage.Plo
+ -rm -f ./$(DEPDIR)/imap-sieve.Plo
+ -rm -f ./$(DEPDIR)/lib90_sieve_imapsieve_plugin_la-ext-imapsieve.Plo
+ -rm -f ./$(DEPDIR)/lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-imap_moduleLTLIBRARIES \
+ install-sieve_pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ext-imapsieve-environment.Plo
+ -rm -f ./$(DEPDIR)/ext-imapsieve.Plo
+ -rm -f ./$(DEPDIR)/imap-sieve-plugin.Plo
+ -rm -f ./$(DEPDIR)/imap-sieve-storage.Plo
+ -rm -f ./$(DEPDIR)/imap-sieve.Plo
+ -rm -f ./$(DEPDIR)/lib90_sieve_imapsieve_plugin_la-ext-imapsieve.Plo
+ -rm -f ./$(DEPDIR)/lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-imap_moduleLTLIBRARIES \
+ uninstall-sieve_pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-imap_moduleLTLIBRARIES clean-libtool \
+ clean-sieve_pluginLTLIBRARIES cscopelist-am ctags ctags-am \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am \
+ install-imap_moduleLTLIBRARIES install-info install-info-am \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-sieve_pluginLTLIBRARIES install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am \
+ uninstall-imap_moduleLTLIBRARIES \
+ uninstall-sieve_pluginLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/plugins/imapsieve/ext-imapsieve-common.h b/pigeonhole/src/plugins/imapsieve/ext-imapsieve-common.h
new file mode 100644
index 0000000..d3e69cd
--- /dev/null
+++ b/pigeonhole/src/plugins/imapsieve/ext-imapsieve-common.h
@@ -0,0 +1,29 @@
+#ifndef EXT_IMAPSIEVE_COMMON_H
+#define EXT_IMAPSIEVE_COMMON_H
+
+#include "sieve-extensions.h"
+
+#include "imap-sieve.h"
+
+/*
+ * Extensions
+ */
+
+extern const struct sieve_extension_def imapsieve_extension;
+extern const struct sieve_extension_def imapsieve_extension_dummy;
+
+extern const struct sieve_extension_def vnd_imapsieve_extension;
+extern const struct sieve_extension_def vnd_imapsieve_extension_dummy;
+
+/*
+ * Environment items
+ */
+
+void ext_imapsieve_environment_items_register
+ (const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv);
+void ext_imapsieve_environment_vendor_items_register
+ (const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv);
+
+#endif
diff --git a/pigeonhole/src/plugins/imapsieve/ext-imapsieve-environment.c b/pigeonhole/src/plugins/imapsieve/ext-imapsieve-environment.c
new file mode 100644
index 0000000..2b61cd4
--- /dev/null
+++ b/pigeonhole/src/plugins/imapsieve/ext-imapsieve-environment.c
@@ -0,0 +1,184 @@
+/* Copyright (c) 2016-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "mail-storage.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-runtime.h"
+
+#include "sieve-ext-environment.h"
+
+#include "ext-imapsieve-common.h"
+
+/*
+ * Environment items
+ */
+
+/* imap.user */
+
+static const char *
+envit_imap_user_get_value(const struct sieve_runtime_env *renv,
+ const char *name ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+
+ return eenv->svinst->username;
+}
+
+const struct sieve_environment_item imap_user_env_item = {
+ .name = "imap.user",
+ .get_value = envit_imap_user_get_value
+};
+
+/* imap.email */
+
+static const char *
+envit_imap_email_get_value(const struct sieve_runtime_env *renv,
+ const char *name ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct smtp_address *user_email =
+ sieve_get_user_email(eenv->svinst);
+
+ if (user_email == NULL)
+ return NULL;
+ return smtp_address_encode(user_email);
+}
+
+const struct sieve_environment_item imap_email_env_item = {
+ .name = "imap.email",
+ .get_value = envit_imap_email_get_value
+};
+
+/* imap.cause */
+
+static const char *
+envit_imap_cause_get_value(const struct sieve_runtime_env *renv,
+ const char *name ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ struct imap_sieve_context *isctx =
+ (struct imap_sieve_context *)senv->script_context;
+
+ return isctx->event.cause;
+}
+
+const struct sieve_environment_item imap_cause_env_item = {
+ .name = "imap.cause",
+ .get_value = envit_imap_cause_get_value
+};
+
+/* imap.mailbox */
+
+static const char *
+envit_imap_mailbox_get_value(const struct sieve_runtime_env *renv,
+ const char *name ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_message_data *msgdata = eenv->msgdata;
+
+ return mailbox_get_vname(msgdata->mail->box);
+}
+
+const struct sieve_environment_item imap_mailbox_env_item = {
+ .name = "imap.mailbox",
+ .get_value = envit_imap_mailbox_get_value
+};
+
+
+/* imap.changedflags */
+
+static const char *
+envit_imap_changedflags_get_value(const struct sieve_runtime_env *renv,
+ const char *name ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ struct imap_sieve_context *isctx =
+ (struct imap_sieve_context *)senv->script_context;
+
+ return isctx->event.changed_flags;
+}
+
+const struct sieve_environment_item imap_changedflags_env_item = {
+ .name = "imap.changedflags",
+ .get_value = envit_imap_changedflags_get_value
+};
+
+/* vnd.dovecot.mailbox-from */
+
+static const char *
+envit_vnd_mailbox_from_get_value(const struct sieve_runtime_env *renv,
+ const char *name ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ struct imap_sieve_context *isctx =
+ (struct imap_sieve_context *)senv->script_context;
+
+ return mailbox_get_vname(isctx->event.src_mailbox);
+}
+
+const struct sieve_environment_item vnd_mailbox_from_env_item = {
+ .name = "vnd.dovecot.mailbox-from",
+ .get_value = envit_vnd_mailbox_from_get_value
+};
+
+/* vnd.dovecot.mailbox-to */
+
+static const char *
+envit_vnd_mailbox_to_get_value(const struct sieve_runtime_env *renv,
+ const char *name ATTR_UNUSED)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ struct imap_sieve_context *isctx =
+ (struct imap_sieve_context *)senv->script_context;
+
+ return mailbox_get_vname(isctx->event.dest_mailbox);
+}
+
+const struct sieve_environment_item vnd_mailbox_to_env_item = {
+ .name = "vnd.dovecot.mailbox-to",
+ .get_value = envit_vnd_mailbox_to_get_value
+};
+
+/*
+ * Register
+ */
+
+void ext_imapsieve_environment_items_register(
+ const struct sieve_extension *ext, const struct sieve_runtime_env *renv)
+{
+ const struct sieve_extension *env_ext =
+ (const struct sieve_extension *)ext->context;
+
+ sieve_environment_item_register(env_ext, renv->interp,
+ &imap_user_env_item);
+ sieve_environment_item_register(env_ext, renv->interp,
+ &imap_email_env_item);
+ sieve_environment_item_register(env_ext, renv->interp,
+ &imap_cause_env_item);
+ sieve_environment_item_register(env_ext, renv->interp,
+ &imap_mailbox_env_item);
+ sieve_environment_item_register(env_ext, renv->interp,
+ &imap_changedflags_env_item);
+}
+
+void ext_imapsieve_environment_vendor_items_register
+(const struct sieve_extension *ext, const struct sieve_runtime_env *renv)
+{
+ const struct sieve_extension *env_ext =
+ (const struct sieve_extension *)ext->context;
+
+ sieve_environment_item_register(env_ext, renv->interp,
+ &vnd_mailbox_from_env_item);
+ sieve_environment_item_register(env_ext, renv->interp,
+ &vnd_mailbox_to_env_item);
+}
diff --git a/pigeonhole/src/plugins/imapsieve/ext-imapsieve.c b/pigeonhole/src/plugins/imapsieve/ext-imapsieve.c
new file mode 100644
index 0000000..64dfc07
--- /dev/null
+++ b/pigeonhole/src/plugins/imapsieve/ext-imapsieve.c
@@ -0,0 +1,168 @@
+/* Copyright (c) 2016-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension imapsieve
+ * -------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: RFC 6785
+ * Implementation: full
+ * Status: experimental
+ *
+ */
+
+#include "lib.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-binary.h"
+
+#include "sieve-validator.h"
+#include "sieve-interpreter.h"
+
+#include "sieve-ext-environment.h"
+
+#include "ext-imapsieve-common.h"
+
+/*
+ * Extension
+ */
+
+static bool ext_imapsieve_load
+ (const struct sieve_extension *ext, void **context);
+static bool ext_vnd_imapsieve_load
+ (const struct sieve_extension *ext, void **context);
+static bool ext_vnd_imapsieve_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+static bool ext_imapsieve_interpreter_load
+ (const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED);
+
+#ifdef __IMAPSIEVE_DUMMY
+const struct sieve_extension_def imapsieve_extension_dummy = {
+#else
+const struct sieve_extension_def imapsieve_extension = {
+#endif
+ .name = "imapsieve",
+ .load = ext_imapsieve_load,
+ .interpreter_load = ext_imapsieve_interpreter_load
+};
+
+#ifdef __IMAPSIEVE_DUMMY
+const struct sieve_extension_def vnd_imapsieve_extension_dummy = {
+#else
+const struct sieve_extension_def vnd_imapsieve_extension = {
+#endif
+ .name = "vnd.dovecot.imapsieve",
+ .load = ext_vnd_imapsieve_load,
+ .interpreter_load = ext_imapsieve_interpreter_load,
+ .validator_load = ext_vnd_imapsieve_validator_load
+};
+
+/*
+ * Context
+ */
+
+static bool ext_imapsieve_load
+(const struct sieve_extension *ext, void **context)
+{
+ *context = (void*)
+ sieve_ext_environment_require_extension(ext->svinst);
+ return TRUE;
+}
+
+static bool ext_vnd_imapsieve_load
+(const struct sieve_extension *ext, void **context)
+{
+ *context = (void*)sieve_extension_require
+#ifdef __IMAPSIEVE_DUMMY
+ (ext->svinst, &imapsieve_extension_dummy, TRUE);
+#else
+ (ext->svinst, &imapsieve_extension, TRUE);
+#endif
+ return TRUE;
+}
+
+/*
+ * Validator
+ */
+
+static bool ext_vnd_imapsieve_validator_load
+(const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_validator *valdtr)
+{
+ const struct sieve_extension *ims_ext;
+
+ /* Load environment extension implicitly */
+
+ ims_ext = sieve_validator_extension_load_implicit
+#ifdef __IMAPSIEVE_DUMMY
+ (valdtr, imapsieve_extension_dummy.name);
+#else
+ (valdtr, imapsieve_extension.name);
+#endif
+ if ( ims_ext == NULL )
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Interpreter
+ */
+
+static int ext_imapsieve_interpreter_run
+ (const struct sieve_extension *this_ext,
+ const struct sieve_runtime_env *renv,
+ void *context, bool deferred);
+
+const struct sieve_interpreter_extension
+imapsieve_interpreter_extension = {
+#ifdef __IMAPSIEVE_DUMMY
+ .ext_def = &imapsieve_extension_dummy,
+#else
+ .ext_def = &imapsieve_extension,
+#endif
+ .run = ext_imapsieve_interpreter_run
+};
+
+static bool ext_imapsieve_interpreter_load
+(const struct sieve_extension *ext ATTR_UNUSED,
+ const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ sieve_interpreter_extension_register(renv->interp,
+ ext, &imapsieve_interpreter_extension, NULL);
+ return TRUE;
+}
+
+#ifdef __IMAPSIEVE_DUMMY
+static int ext_imapsieve_interpreter_run
+(const struct sieve_extension *ext ATTR_UNUSED,
+ const struct sieve_runtime_env *renv,
+ void *context ATTR_UNUSED, bool deferred)
+{
+ if ( !deferred ) {
+ sieve_runtime_error(renv, NULL,
+ "the imapsieve extension cannot be used outside IMAP");
+ }
+ return SIEVE_EXEC_FAILURE;
+}
+#else
+static int ext_imapsieve_interpreter_run
+(const struct sieve_extension *ext,
+ const struct sieve_runtime_env *renv,
+ void *context ATTR_UNUSED, bool deferred ATTR_UNUSED)
+{
+ if (ext->def == &vnd_imapsieve_extension) {
+ const struct sieve_extension *ims_ext =
+ (const struct sieve_extension *)ext->context;
+ ext_imapsieve_environment_vendor_items_register(ims_ext, renv);
+ } else {
+ ext_imapsieve_environment_items_register(ext, renv);
+ }
+ return SIEVE_EXEC_OK;
+}
+#endif
diff --git a/pigeonhole/src/plugins/imapsieve/imap-sieve-plugin.c b/pigeonhole/src/plugins/imapsieve/imap-sieve-plugin.c
new file mode 100644
index 0000000..0c9b52e
--- /dev/null
+++ b/pigeonhole/src/plugins/imapsieve/imap-sieve-plugin.c
@@ -0,0 +1,60 @@
+/* Copyright (c) 2016-2018 Pigeonhole authors, see the included COPYING file */
+
+#include "imap-common.h"
+#include "str.h"
+
+#include "imap-sieve.h"
+#include "imap-sieve-storage.h"
+
+#include "imap-sieve-plugin.h"
+
+static struct module *imap_sieve_module;
+static imap_client_created_func_t *next_hook_client_created;
+
+/*
+ * Client
+ */
+
+static void imap_sieve_client_created(struct client **clientp)
+{
+ struct client *client = *clientp;
+ struct mail_user *user = client->user;
+ const char *url = NULL;
+
+ if (mail_user_is_plugin_loaded(user, imap_sieve_module)) {
+ url = mail_user_plugin_getenv(user, "imapsieve_url");
+ // FIXME: parse the URL and report error if it is bad
+ if (url != NULL && strncasecmp(url, "sieve:", 6) == 0) {
+ client_add_capability(client, t_strconcat(
+ "IMAPSIEVE=", url, NULL));
+ } else {
+ url = NULL;
+ }
+
+ imap_sieve_storage_client_created(client, (url != NULL));
+ }
+
+ if (next_hook_client_created != NULL)
+ next_hook_client_created(clientp);
+}
+
+/*
+ * Plugin
+ */
+
+const char *imap_sieve_plugin_version = DOVECOT_ABI_VERSION;
+const char imap_sieve_plugin_binary_dependency[] = "imap";
+
+void imap_sieve_plugin_init(struct module *module)
+{
+ imap_sieve_module = module;
+ next_hook_client_created =
+ imap_client_created_hook_set(imap_sieve_client_created);
+ imap_sieve_storage_init(module);
+}
+
+void imap_sieve_plugin_deinit(void)
+{
+ imap_sieve_storage_deinit();
+ imap_client_created_hook_set(next_hook_client_created);
+}
diff --git a/pigeonhole/src/plugins/imapsieve/imap-sieve-plugin.h b/pigeonhole/src/plugins/imapsieve/imap-sieve-plugin.h
new file mode 100644
index 0000000..0271710
--- /dev/null
+++ b/pigeonhole/src/plugins/imapsieve/imap-sieve-plugin.h
@@ -0,0 +1,11 @@
+#ifndef IMAP_SIEVE_PLUGIN_H
+#define IMAP_SIEVE_PLUGIN_H
+
+struct module;
+
+extern const char imap_sieve_plugin_binary_dependency[];
+
+void imap_sieve_plugin_init(struct module *module);
+void imap_sieve_plugin_deinit(void);
+
+#endif
diff --git a/pigeonhole/src/plugins/imapsieve/imap-sieve-storage.c b/pigeonhole/src/plugins/imapsieve/imap-sieve-storage.c
new file mode 100644
index 0000000..f8e5efe
--- /dev/null
+++ b/pigeonhole/src/plugins/imapsieve/imap-sieve-storage.c
@@ -0,0 +1,1273 @@
+/* Copyright (c) 2016-2018 Pigeonhole authors, see the included COPYING file */
+
+#include "imap-common.h"
+#include "array.h"
+#include "hash.h"
+#include "str.h"
+#include "istream.h"
+#include "ostream.h"
+#include "module-context.h"
+#include "mail-user.h"
+#include "mail-storage-private.h"
+#include "mailbox-attribute.h"
+#include "mailbox-list-private.h"
+#include "imap-match.h"
+#include "imap-util.h"
+
+#include "imap-sieve.h"
+#include "imap-sieve-storage.h"
+
+#define MAILBOX_ATTRIBUTE_IMAPSIEVE_SCRIPT "imapsieve/script"
+#define MAIL_SERVER_ATTRIBUTE_IMAPSIEVE_SCRIPT "imapsieve/script"
+
+#define IMAP_SIEVE_USER_CONTEXT(obj) \
+ MODULE_CONTEXT(obj, imap_sieve_user_module)
+#define IMAP_SIEVE_USER_CONTEXT_REQUIRE(obj) \
+ MODULE_CONTEXT_REQUIRE(obj, imap_sieve_user_module)
+#define IMAP_SIEVE_CONTEXT(obj) \
+ MODULE_CONTEXT(obj, imap_sieve_storage_module)
+#define IMAP_SIEVE_CONTEXT_REQUIRE(obj) \
+ MODULE_CONTEXT_REQUIRE(obj, imap_sieve_storage_module)
+#define IMAP_SIEVE_MAIL_CONTEXT(obj) \
+ MODULE_CONTEXT_REQUIRE(obj, imap_sieve_mail_module)
+
+struct imap_sieve_mailbox_rule;
+struct imap_sieve_user;
+struct imap_sieve_mailbox_event;
+struct imap_sieve_mailbox_transaction;
+struct imap_sieve_mail;
+
+enum imap_sieve_command {
+ IMAP_SIEVE_CMD_NONE = 0,
+ IMAP_SIEVE_CMD_APPEND,
+ IMAP_SIEVE_CMD_COPY,
+ IMAP_SIEVE_CMD_MOVE,
+ IMAP_SIEVE_CMD_STORE,
+ IMAP_SIEVE_CMD_OTHER
+};
+
+ARRAY_DEFINE_TYPE(imap_sieve_mailbox_rule,
+ struct imap_sieve_mailbox_rule *);
+ARRAY_DEFINE_TYPE(imap_sieve_mailbox_event,
+ struct imap_sieve_mailbox_event);
+
+HASH_TABLE_DEFINE_TYPE(imap_sieve_mailbox_rule,
+ struct imap_sieve_mailbox_rule *,
+ struct imap_sieve_mailbox_rule *);
+
+struct imap_sieve_mailbox_rule {
+ unsigned int index;
+ const char *mailbox;
+ const char *from;
+ const char *const *causes;
+ const char *before, *after;
+ const char *copy_source_after;
+};
+
+struct imap_sieve_user {
+ union mail_user_module_context module_ctx;
+ struct client *client;
+ struct imap_sieve *isieve;
+
+ enum imap_sieve_command cur_cmd;
+
+ HASH_TABLE_TYPE(imap_sieve_mailbox_rule) mbox_rules;
+ ARRAY_TYPE(imap_sieve_mailbox_rule) mbox_patterns;
+
+ bool sieve_active:1;
+ bool user_script:1;
+ bool expunge_discarded:1;
+};
+
+struct imap_sieve_mailbox_event {
+ uint32_t dest_mail_uid, src_mail_uid;
+ unsigned int save_seq;
+
+ const char *changed_flags;
+};
+
+struct imap_sieve_mailbox_transaction {
+ pool_t pool;
+
+ union mailbox_transaction_module_context module_ctx;
+
+ struct mailbox *src_box;
+ struct mailbox_transaction_context *src_mail_trans;
+
+ ARRAY_TYPE(imap_sieve_mailbox_event) events;
+};
+
+struct imap_sieve_mail {
+ union mail_module_context module_ctx;
+
+ string_t *flags;
+};
+
+static MODULE_CONTEXT_DEFINE_INIT(imap_sieve_user_module,
+ &mail_user_module_register);
+static MODULE_CONTEXT_DEFINE_INIT(imap_sieve_storage_module,
+ &mail_storage_module_register);
+static MODULE_CONTEXT_DEFINE_INIT(imap_sieve_mail_module,
+ &mail_module_register);
+
+static void
+imap_sieve_mailbox_rules_get(struct mail_user *user,
+ struct mailbox *dst_box, struct mailbox *src_box,
+ const char *cause,
+ ARRAY_TYPE(imap_sieve_mailbox_rule) *rules);
+
+/*
+ * Logging
+ */
+
+static inline void
+imap_sieve_debug(struct mail_user *user,
+ const char *format, ...) ATTR_FORMAT(2, 3);
+static inline void
+imap_sieve_debug(struct mail_user *user,
+ const char *format, ...)
+{
+ va_list args;
+
+ if (user->mail_debug) {
+ va_start(args, format);
+ i_debug("imapsieve: %s",
+ t_strdup_vprintf(format, args));
+ va_end(args);
+ }
+}
+
+static inline void
+imap_sieve_warning(struct mail_user *user ATTR_UNUSED,
+ const char *format, ...) ATTR_FORMAT(2, 3);
+static inline void
+imap_sieve_warning(struct mail_user *user ATTR_UNUSED,
+ const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ i_warning("imapsieve: %s",
+ t_strdup_vprintf(format, args));
+ va_end(args);
+}
+
+static inline void
+imap_sieve_mailbox_debug(struct mailbox *box,
+ const char *format, ...) ATTR_FORMAT(2, 3);
+static inline void
+imap_sieve_mailbox_debug(struct mailbox *box,
+ const char *format, ...)
+{
+ va_list args;
+
+ if (box->storage->user->mail_debug) {
+ va_start(args, format);
+ i_debug("imapsieve: mailbox %s: %s",
+ mailbox_get_vname(box),
+ t_strdup_vprintf(format, args));
+ va_end(args);
+ }
+}
+
+static inline void
+imap_sieve_mailbox_warning(struct mailbox *box,
+ const char *format, ...) ATTR_FORMAT(2, 3);
+static inline void
+imap_sieve_mailbox_warning(struct mailbox *box,
+ const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ i_warning("imapsieve: mailbox %s: %s",
+ mailbox_get_vname(box),
+ t_strdup_vprintf(format, args));
+ va_end(args);
+}
+
+static inline void
+imap_sieve_mailbox_error(struct mailbox *box,
+ const char *format, ...) ATTR_FORMAT(2, 3);
+static inline void
+imap_sieve_mailbox_error(struct mailbox *box,
+ const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ i_error("imapsieve: mailbox %s: %s",
+ mailbox_get_vname(box),
+ t_strdup_vprintf(format, args));
+ va_end(args);
+}
+
+/*
+ * Events
+ */
+
+static int imap_sieve_mailbox_get_script_real
+(struct mailbox *box,
+ const char **script_name_r)
+{
+ struct mail_user *user = box->storage->user;
+ struct mail_attribute_value value;
+ int ret;
+
+ *script_name_r = NULL;
+
+ /* get the name of the Sieve script from mailbox METADATA */
+ if ((ret=mailbox_attribute_get(box, MAIL_ATTRIBUTE_TYPE_SHARED,
+ MAILBOX_ATTRIBUTE_IMAPSIEVE_SCRIPT, &value)) < 0) {
+ imap_sieve_mailbox_error(box,
+ "Failed to read /shared/"
+ MAILBOX_ATTRIBUTE_IMAPSIEVE_SCRIPT" "
+ "mailbox attribute: %s",
+ mailbox_get_last_internal_error(box, NULL));
+ return -1;
+ }
+
+ if (ret > 0) {
+ imap_sieve_mailbox_debug(box,
+ "Mailbox attribute /shared/"
+ MAILBOX_ATTRIBUTE_IMAPSIEVE_SCRIPT" "
+ "points to Sieve script `%s'", value.value);
+
+ /* if not found, get the name of the Sieve script from
+ server METADATA */
+ } else {
+ struct mail_namespace *ns;
+ struct mailbox *inbox;
+
+ imap_sieve_mailbox_debug(box,
+ "Mailbox attribute /shared/"
+ MAILBOX_ATTRIBUTE_IMAPSIEVE_SCRIPT" "
+ "not found");
+
+ ns = mail_namespace_find_inbox(user->namespaces);
+ inbox = mailbox_alloc(ns->list, "INBOX",
+ MAILBOX_FLAG_READONLY);
+ ret = mailbox_attribute_get(inbox,
+ MAIL_ATTRIBUTE_TYPE_SHARED,
+ MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER
+ MAILBOX_ATTRIBUTE_IMAPSIEVE_SCRIPT, &value);
+
+ if (ret <= 0) {
+ if (ret < 0) {
+ imap_sieve_mailbox_error(box,
+ "Failed to read /shared/"
+ MAIL_SERVER_ATTRIBUTE_IMAPSIEVE_SCRIPT" "
+ "server attribute: %s",
+ mailbox_get_last_internal_error(inbox, NULL));
+ } else if (ret == 0) {
+ imap_sieve_mailbox_debug(box,
+ "Server attribute /shared/"
+ MAIL_SERVER_ATTRIBUTE_IMAPSIEVE_SCRIPT" "
+ "not found");
+ }
+ mailbox_free(&inbox);
+ return ret;
+ }
+ mailbox_free(&inbox);
+
+ imap_sieve_mailbox_debug(box,
+ "Server attribute /shared/"
+ MAIL_SERVER_ATTRIBUTE_IMAPSIEVE_SCRIPT" "
+ "points to Sieve script `%s'", value.value);
+ }
+
+ *script_name_r = value.value;
+ return 1;
+}
+
+static int imap_sieve_mailbox_get_script
+(struct mailbox *box, const char **script_name_r)
+{
+ int ret;
+
+ ret = imap_sieve_mailbox_get_script_real
+ (box, script_name_r);
+ return ret;
+}
+
+static struct imap_sieve_mailbox_event *
+imap_sieve_create_mailbox_event
+(struct mailbox_transaction_context *t, struct mail *dest_mail)
+{
+ struct imap_sieve_mailbox_transaction *ismt = IMAP_SIEVE_CONTEXT_REQUIRE(t);
+ struct imap_sieve_mailbox_event *event;
+
+ if (!array_is_created(&ismt->events))
+ i_array_init(&ismt->events, 64);
+
+ event = array_append_space(&ismt->events);
+ event->save_seq = t->save_count;
+ event->dest_mail_uid = dest_mail->uid;
+ return event;
+}
+
+static void imap_sieve_add_mailbox_event
+(struct mailbox_transaction_context *t,
+ struct mail *dest_mail, struct mailbox *src_box,
+ const char *changed_flags)
+{
+ struct imap_sieve_mailbox_transaction *ismt = IMAP_SIEVE_CONTEXT_REQUIRE(t);
+ struct imap_sieve_mailbox_event *event;
+
+ i_assert(ismt->src_box == NULL || ismt->src_box == src_box);
+ ismt->src_box = src_box;
+
+ event = imap_sieve_create_mailbox_event(t, dest_mail);
+ event->changed_flags = p_strdup(ismt->pool, changed_flags);
+}
+
+static void imap_sieve_add_mailbox_copy_event
+(struct mailbox_transaction_context *t,
+ struct mail *dest_mail, struct mail *src_mail)
+{
+ struct imap_sieve_mailbox_transaction *ismt = IMAP_SIEVE_CONTEXT_REQUIRE(t);
+ struct imap_sieve_mailbox_event *event;
+
+ i_assert(ismt->src_box == NULL || ismt->src_box == src_mail->box);
+ i_assert(ismt->src_mail_trans == NULL ||
+ ismt->src_mail_trans == src_mail->transaction);
+
+ ismt->src_box = src_mail->box;
+ ismt->src_mail_trans = src_mail->transaction;
+
+ event = imap_sieve_create_mailbox_event(t, dest_mail);
+ event->src_mail_uid = src_mail->uid;
+}
+
+/*
+ * Mail
+ */
+
+static void
+imap_sieve_mail_update_flags(struct mail *_mail,
+ enum modify_type modify_type, enum mail_flags flags)
+{
+ struct mail_private *mail = (struct mail_private *)_mail;
+ struct imap_sieve_mail *ismail = IMAP_SIEVE_MAIL_CONTEXT(mail);
+ enum mail_flags old_flags, new_flags, changed_flags;
+
+ old_flags = mail_get_flags(_mail);
+ ismail->module_ctx.super.update_flags(_mail, modify_type, flags);
+ new_flags = mail_get_flags(_mail);
+
+ changed_flags = old_flags ^ new_flags;
+ if (changed_flags == 0)
+ return;
+
+ if (ismail->flags == NULL)
+ ismail->flags = str_new(default_pool, 64);
+ imap_write_flags(ismail->flags, changed_flags, NULL);
+}
+
+static void
+imap_sieve_mail_update_keywords(struct mail *_mail,
+ enum modify_type modify_type, struct mail_keywords *keywords)
+{
+ struct mail_private *mail = (struct mail_private *)_mail;
+ struct imap_sieve_mail *ismail = IMAP_SIEVE_MAIL_CONTEXT(mail);
+ const char *const *old_keywords, *const *new_keywords;
+ unsigned int i, j;
+
+ old_keywords = mail_get_keywords(_mail);
+ ismail->module_ctx.super.update_keywords(_mail, modify_type, keywords);
+ new_keywords = mail_get_keywords(_mail);
+
+ if (ismail->flags == NULL)
+ ismail->flags = str_new(default_pool, 64);
+
+ /* Removed flags */
+ for (i = 0; old_keywords[i] != NULL; i++) {
+ for (j = 0; new_keywords[j] != NULL; j++) {
+ if (strcmp(old_keywords[i], new_keywords[j]) == 0)
+ break;
+ }
+ if (new_keywords[j] == NULL) {
+ if (str_len(ismail->flags) > 0)
+ str_append_c(ismail->flags, ' ');
+ str_append(ismail->flags, old_keywords[i]);
+ }
+ }
+
+ /* Added flags */
+ for (i = 0; new_keywords[i] != NULL; i++) {
+ for (j = 0; old_keywords[j] != NULL; j++) {
+ if (strcmp(new_keywords[i], old_keywords[j]) == 0)
+ break;
+ }
+ if (old_keywords[j] == NULL) {
+ if (str_len(ismail->flags) > 0)
+ str_append_c(ismail->flags, ' ');
+ str_append(ismail->flags, new_keywords[i]);
+ }
+ }
+}
+
+static void imap_sieve_mail_close(struct mail *_mail)
+{
+ struct mail_private *mail = (struct mail_private *)_mail;
+ struct mailbox_transaction_context *t = _mail->transaction;
+ struct imap_sieve_mail *ismail = IMAP_SIEVE_MAIL_CONTEXT(mail);
+
+ if (ismail->flags != NULL && str_len(ismail->flags) > 0) {
+ if (!_mail->expunged) {
+ imap_sieve_mailbox_debug(_mail->box,
+ "FLAG event (changed flags: %s)",
+ str_c(ismail->flags));
+
+ imap_sieve_add_mailbox_event(t,
+ _mail, _mail->box, str_c(ismail->flags));
+ }
+ str_truncate(ismail->flags, 0);
+ }
+
+ ismail->module_ctx.super.close(_mail);
+}
+
+static void imap_sieve_mail_free(struct mail *_mail)
+{
+ struct mail_private *mail = (struct mail_private *)_mail;
+ struct imap_sieve_mail *ismail = IMAP_SIEVE_MAIL_CONTEXT(mail);
+ string_t *flags = ismail->flags;
+
+ ismail->module_ctx.super.free(_mail);
+
+ if (flags != NULL)
+ str_free(&flags);
+}
+
+static void imap_sieve_mail_allocated(struct mail *_mail)
+{
+ struct mail_private *mail = (struct mail_private *)_mail;
+ struct imap_sieve_mailbox_transaction *ismt =
+ IMAP_SIEVE_CONTEXT(_mail->transaction);
+ struct mail_user *user = _mail->box->storage->user;
+ struct imap_sieve_user *isuser =
+ IMAP_SIEVE_USER_CONTEXT_REQUIRE(user);
+ struct mail_vfuncs *v = mail->vlast;
+ struct imap_sieve_mail *ismail;
+
+ if (ismt == NULL || isuser->sieve_active)
+ return;
+
+ ismail = p_new(mail->pool, struct imap_sieve_mail, 1);
+ ismail->module_ctx.super = *v;
+ mail->vlast = &ismail->module_ctx.super;
+
+ v->close = imap_sieve_mail_close;
+ v->free = imap_sieve_mail_free;
+ v->update_flags = imap_sieve_mail_update_flags;
+ v->update_keywords = imap_sieve_mail_update_keywords;
+ MODULE_CONTEXT_SET(mail, imap_sieve_mail_module, ismail);
+}
+
+/*
+ * Save/copy
+ */
+
+static int
+imap_sieve_mailbox_copy(struct mail_save_context *ctx, struct mail *mail)
+{
+ struct mailbox_transaction_context *t = ctx->transaction;
+ struct mail_storage *storage = t->box->storage;
+ struct mail_user *user = storage->user;
+ struct imap_sieve_user *isuser =
+ IMAP_SIEVE_USER_CONTEXT_REQUIRE(user);
+ union mailbox_module_context *lbox =
+ IMAP_SIEVE_CONTEXT_REQUIRE(t->box);
+ struct imap_sieve_mailbox_transaction *ismt =
+ IMAP_SIEVE_CONTEXT(t);
+
+ if (lbox->super.copy(ctx, mail) < 0)
+ return -1;
+
+ if (ismt != NULL && !isuser->sieve_active &&
+ !ctx->dest_mail->expunged &&
+ (isuser->cur_cmd == IMAP_SIEVE_CMD_COPY ||
+ isuser->cur_cmd == IMAP_SIEVE_CMD_MOVE)) {
+ imap_sieve_mailbox_debug(t->box, "%s event",
+ (isuser->cur_cmd == IMAP_SIEVE_CMD_COPY ?
+ "COPY" : "MOVE"));
+ imap_sieve_add_mailbox_copy_event(t, ctx->dest_mail,
+ ctx->copy_src_mail);
+ }
+
+ return 0;
+}
+
+static int
+imap_sieve_mailbox_save_finish(struct mail_save_context *ctx)
+{
+ struct mailbox_transaction_context *t = ctx->transaction;
+ struct mailbox *box = t->box;
+ struct imap_sieve_mailbox_transaction *ismt = IMAP_SIEVE_CONTEXT(t);
+ union mailbox_module_context *lbox = IMAP_SIEVE_CONTEXT_REQUIRE(box);
+ struct mail_user *user = box->storage->user;
+ struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user);
+ struct mail *dest_mail = ctx->copying_via_save ? NULL : ctx->dest_mail;
+
+ if (lbox->super.save_finish(ctx) < 0)
+ return -1;
+
+ if (ismt != NULL && !isuser->sieve_active &&
+ dest_mail != NULL && !dest_mail->expunged &&
+ isuser->cur_cmd == IMAP_SIEVE_CMD_APPEND) {
+
+ imap_sieve_mailbox_debug(t->box, "APPEND event");
+ imap_sieve_add_mailbox_event(t, dest_mail, box, NULL);
+ }
+ return 0;
+}
+
+/*
+ * Mailbox
+ */
+
+static struct mailbox_transaction_context *
+imap_sieve_mailbox_transaction_begin(struct mailbox *box,
+ enum mailbox_transaction_flags flags,
+ const char *reason)
+{
+ union mailbox_module_context *lbox = IMAP_SIEVE_CONTEXT_REQUIRE(box);
+ struct mail_user *user = box->storage->user;
+ struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT(user);
+ struct mailbox_transaction_context *t;
+ struct imap_sieve_mailbox_transaction *ismt;
+ pool_t pool;
+
+ /* commence parent transaction */
+ t = lbox->super.transaction_begin(box, flags, reason);
+
+ if (isuser == NULL || isuser->sieve_active ||
+ isuser->cur_cmd == IMAP_SIEVE_CMD_NONE)
+ return t;
+
+ i_assert(isuser->client != NULL);
+
+ pool = pool_alloconly_create("imap_sieve_mailbox_transaction", 1024);
+ ismt = p_new(pool, struct imap_sieve_mailbox_transaction, 1);
+ ismt->pool = pool;
+ MODULE_CONTEXT_SET(t, imap_sieve_storage_module, ismt);
+
+ return t;
+}
+
+static void
+imap_sieve_mailbox_transaction_free
+(struct imap_sieve_mailbox_transaction *ismt)
+{
+ if (array_is_created(&ismt->events))
+ array_free(&ismt->events);
+ pool_unref(&ismt->pool);
+}
+
+static void
+imap_sieve_mailbox_run_copy_source(
+ struct imap_sieve_mailbox_transaction *ismt,
+ struct imap_sieve_run *isrun,
+ const struct imap_sieve_mailbox_event *mevent,
+ struct mail **src_mail, bool *fatal_r)
+{
+ struct mailbox *src_box = ismt->src_box;
+ int ret;
+
+ *fatal_r = FALSE;
+
+ if (isrun == NULL)
+ return;
+
+ i_assert(ismt->src_mail_trans->box == src_box);
+ i_assert(mevent->src_mail_uid > 0);
+
+ if (*src_mail == NULL)
+ *src_mail = mail_alloc(ismt->src_mail_trans, 0, NULL);
+
+ /* Select source message */
+ if (!mail_set_uid(*src_mail, mevent->src_mail_uid)) {
+ imap_sieve_mailbox_warning(src_box,
+ "Failed to find source message for Sieve event "
+ "(UID=%llu)", (unsigned long long)mevent->src_mail_uid);
+ return;
+ }
+
+ imap_sieve_mailbox_debug(src_box,
+ "Running copy_source_after scripts.");
+
+ /* Run scripts for source mail */
+ ret = imap_sieve_run_mail(isrun, *src_mail, NULL, fatal_r);
+ if (ret > 0) {
+ /* Discard */
+ mail_update_flags(*src_mail, MODIFY_ADD, MAIL_DELETED);
+ }
+}
+
+static int
+imap_sieve_mailbox_transaction_run(
+ struct imap_sieve_mailbox_transaction *ismt,
+ struct mailbox *dest_box,
+ struct mail_transaction_commit_changes *changes)
+{
+ static const char *wanted_headers[] = {
+ "From", "To", "Message-ID", "Subject", "Return-Path",
+ NULL
+ };
+ struct mailbox *src_box = ismt->src_box;
+ struct mail_user *user = dest_box->storage->user;
+ struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user);
+ const struct imap_sieve_mailbox_event *mevent;
+ struct mailbox_header_lookup_ctx *headers_ctx;
+ struct mailbox_transaction_context *st;
+ struct mailbox *sbox;
+ struct imap_sieve_run *isrun, *isrun_src;
+ struct seq_range_iter siter;
+ const char *cause, *script_name = NULL;
+ bool can_discard;
+ struct mail *mail, *src_mail = NULL;
+ int ret;
+
+ if (ismt == NULL || !array_is_created(&ismt->events)) {
+ /* Nothing to do */
+ return 0;
+ }
+
+ i_assert(isuser->client != NULL);
+
+ /* Get user script for this mailbox */
+ if (isuser->user_script && imap_sieve_mailbox_get_script
+ (dest_box, &script_name) < 0) {
+ return 0; // FIXME: some errors may warrant -1
+ }
+
+ /* Make sure IMAPSIEVE is initialized for this user */
+ if (isuser->isieve == NULL)
+ isuser->isieve = imap_sieve_init(isuser->client);
+
+ can_discard = FALSE;
+ switch (isuser->cur_cmd) {
+ case IMAP_SIEVE_CMD_APPEND:
+ cause = "APPEND";
+ can_discard = TRUE;
+ break;
+ case IMAP_SIEVE_CMD_COPY:
+ case IMAP_SIEVE_CMD_MOVE:
+ cause = "COPY";
+ can_discard = TRUE;
+ break;
+ case IMAP_SIEVE_CMD_STORE:
+ case IMAP_SIEVE_CMD_OTHER:
+ cause = "FLAG";
+ break;
+ default:
+ i_unreached();
+ }
+
+ /* Initialize execution */
+ T_BEGIN {
+ ARRAY_TYPE(imap_sieve_mailbox_rule) mbrules;
+ ARRAY_TYPE(const_string) scripts_before, scripts_after;
+ ARRAY_TYPE(const_string) scripts_copy_source;
+ struct imap_sieve_mailbox_rule *rule;
+
+ /* Find matching rules */
+ t_array_init(&mbrules, 16);
+ imap_sieve_mailbox_rules_get
+ (user, dest_box, src_box, cause, &mbrules);
+
+ /* Apply all matched rules */
+ t_array_init(&scripts_before, 8);
+ t_array_init(&scripts_after, 8);
+ t_array_init(&scripts_copy_source, 4);
+ array_foreach_elem(&mbrules, rule) {
+ if (rule->before != NULL)
+ array_append(&scripts_before, &rule->before, 1);
+ if (rule->after != NULL)
+ array_append(&scripts_after, &rule->after, 1);
+ if (rule->copy_source_after != NULL)
+ array_append(&scripts_copy_source, &rule->copy_source_after, 1);
+ }
+ (void)array_append_space(&scripts_before);
+ (void)array_append_space(&scripts_after);
+
+ /* Initialize */
+ ret = imap_sieve_run_init
+ (isuser->isieve, dest_box, src_box, cause, script_name,
+ array_idx(&scripts_before, 0),
+ array_idx(&scripts_after, 0), &isrun);
+
+ /* Initialize source script execution */
+ isrun_src = NULL;
+ if (ret > 0 && ismt->src_mail_trans != NULL &&
+ isuser->cur_cmd == IMAP_SIEVE_CMD_COPY &&
+ array_count(&scripts_copy_source) > 0) {
+ const char *no_scripts = NULL;
+
+ (void)array_append_space(&scripts_copy_source);
+ if (imap_sieve_run_init(isuser->isieve,
+ dest_box, src_box, cause, NULL,
+ &no_scripts, array_idx(&scripts_copy_source, 0),
+ &isrun_src) <= 0)
+ isrun_src = NULL;
+ }
+ } T_END;
+
+ if (ret <= 0) {
+ // FIXME: temp fail should be handled properly
+ return 0;
+ }
+
+ /* Get synchronized view on the destination mailbox */
+ sbox = mailbox_alloc(dest_box->list, dest_box->vname, 0);
+ if (mailbox_sync(sbox, 0) < 0) {
+ mailbox_free(&sbox);
+ imap_sieve_run_deinit(&isrun);
+ if (isrun_src != NULL)
+ imap_sieve_run_deinit(&isrun_src);
+ return -1;
+ }
+
+ /* Create transaction for event messages */
+ st = mailbox_transaction_begin(sbox, 0, __func__);
+ headers_ctx = mailbox_header_lookup_init(sbox, wanted_headers);
+ mail = mail_alloc(st, 0, headers_ctx);
+ mailbox_header_lookup_unref(&headers_ctx);
+
+ /* Iterate through all events */
+ seq_range_array_iter_init(&siter, &changes->saved_uids);
+ array_foreach(&ismt->events, mevent) {
+ uint32_t uid;
+ bool fatal;
+
+ /* Determine UID for saved message */
+ if (mevent->dest_mail_uid > 0)
+ uid = mevent->dest_mail_uid;
+ else if (!seq_range_array_iter_nth(&siter, mevent->save_seq,
+ &uid)) {
+ /* already gone for some reason */
+ imap_sieve_mailbox_debug(
+ sbox, "Message for Sieve event gone");
+ continue;
+ }
+
+ /* Select event message */
+ i_assert(uid > 0);
+ if (!mail_set_uid(mail, uid) || mail->expunged) {
+ /* already gone for some reason */
+ imap_sieve_mailbox_debug(sbox,
+ "Message for Sieve event gone (UID=%llu)",
+ (unsigned long long)uid);
+ continue;
+ }
+
+ /* Run scripts for this mail */
+ ret = imap_sieve_run_mail(isrun, mail, mevent->changed_flags,
+ &fatal);
+ if (fatal)
+ break;
+
+ /* Handle the result */
+ if (ret < 0) {
+ /* Sieve error; keep */
+ } else {
+ if (ret <= 0 || !can_discard) {
+ /* Keep */
+ } else if (!isuser->expunge_discarded) {
+ /* Mark as \Deleted */
+ mail_update_flags(mail,
+ MODIFY_ADD, MAIL_DELETED);
+ } else {
+ /* Expunge */
+ mail_expunge(mail);
+ }
+
+ imap_sieve_mailbox_run_copy_source(
+ ismt, isrun_src, mevent, &src_mail, &fatal);
+ if (fatal)
+ break;
+ }
+ }
+
+ /* Cleanup */
+ mail_free(&mail);
+ ret = mailbox_transaction_commit(&st);
+ if (src_mail != NULL)
+ mail_free(&src_mail);
+ imap_sieve_run_deinit(&isrun);
+ if (isrun_src != NULL)
+ imap_sieve_run_deinit(&isrun_src);
+ mailbox_free(&sbox);
+ return ret;
+}
+
+static int
+imap_sieve_mailbox_transaction_commit(
+ struct mailbox_transaction_context *t,
+ struct mail_transaction_commit_changes *changes_r)
+{
+ struct mailbox *box = t->box;
+ struct mail_user *user = box->storage->user;
+ struct imap_sieve_mailbox_transaction *ismt = IMAP_SIEVE_CONTEXT(t);
+ union mailbox_module_context *lbox = IMAP_SIEVE_CONTEXT_REQUIRE(t->box);
+ struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user);
+ int ret = 0;
+
+ if ((lbox->super.transaction_commit(t, changes_r)) < 0)
+ ret = -1;
+ else if (ismt != NULL) {
+ isuser->sieve_active = TRUE;
+ if (imap_sieve_mailbox_transaction_run
+ (ismt, box, changes_r) < 0)
+ ret = -1;
+ isuser->sieve_active = FALSE;
+ }
+
+ if (ismt != NULL)
+ imap_sieve_mailbox_transaction_free(ismt);
+ return ret;
+}
+
+static void
+imap_sieve_mailbox_transaction_rollback(
+ struct mailbox_transaction_context *t)
+{
+ struct imap_sieve_mailbox_transaction *ismt = IMAP_SIEVE_CONTEXT(t);
+ union mailbox_module_context *lbox = IMAP_SIEVE_CONTEXT_REQUIRE(t->box);
+
+ lbox->super.transaction_rollback(t);
+
+ if (ismt != NULL)
+ imap_sieve_mailbox_transaction_free(ismt);
+}
+
+static void imap_sieve_mailbox_allocated(struct mailbox *box)
+{
+ struct mail_user *user = box->storage->user;
+ struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user);
+ struct mailbox_vfuncs *v = box->vlast;
+ union mailbox_module_context *lbox;
+
+ if (isuser->client == NULL || isuser->sieve_active ||
+ (box->flags & MAILBOX_FLAG_READONLY) != 0)
+ return;
+
+ lbox = p_new(box->pool, union mailbox_module_context, 1);
+ lbox->super = *v;
+ box->vlast = &lbox->super;
+
+ v->copy = imap_sieve_mailbox_copy;
+ v->save_finish = imap_sieve_mailbox_save_finish;
+ v->transaction_begin = imap_sieve_mailbox_transaction_begin;
+ v->transaction_commit = imap_sieve_mailbox_transaction_commit;
+ v->transaction_rollback = imap_sieve_mailbox_transaction_rollback;
+ MODULE_CONTEXT_SET_SELF(box, imap_sieve_storage_module, lbox);
+}
+
+/*
+ * Mailbox rules
+ */
+
+static unsigned int imap_sieve_mailbox_rule_hash
+(const struct imap_sieve_mailbox_rule *rule)
+{
+ unsigned int hash = str_hash(rule->mailbox);
+
+ if (rule->from != NULL)
+ hash += str_hash(rule->from);
+ return hash;
+}
+
+static int imap_sieve_mailbox_rule_cmp
+(const struct imap_sieve_mailbox_rule *rule1,
+ const struct imap_sieve_mailbox_rule *rule2)
+{
+ int ret;
+
+ if ((ret=strcmp(rule1->mailbox, rule2->mailbox)) != 0)
+ return ret;
+ return null_strcmp(rule1->from, rule2->from);
+}
+
+static bool rule_pattern_has_wildcards(const char *pattern)
+{
+ for (; *pattern != '\0'; pattern++) {
+ if (*pattern == '%' || *pattern == '*')
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+imap_sieve_mailbox_rules_init(struct mail_user *user)
+{
+ struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user);
+ string_t *identifier;
+ unsigned int i = 0;
+ size_t prefix_len;
+
+ if (hash_table_is_created(isuser->mbox_rules))
+ return;
+
+ hash_table_create(&isuser->mbox_rules, default_pool, 0,
+ imap_sieve_mailbox_rule_hash, imap_sieve_mailbox_rule_cmp);
+ i_array_init(&isuser->mbox_patterns, 8);
+
+ identifier = t_str_new(256);
+ str_append(identifier, "imapsieve_mailbox");
+ prefix_len = str_len(identifier);
+
+ for (i = 1; ; i++) {
+ struct imap_sieve_mailbox_rule *mbrule;
+ const char *setval;
+ size_t id_len;
+
+ str_truncate(identifier, prefix_len);
+ str_printfa(identifier, "%u", i);
+ id_len = str_len(identifier);
+
+ str_append(identifier, "_name");
+ setval = mail_user_plugin_getenv
+ (user, str_c(identifier));
+ if (setval == NULL || *setval == '\0')
+ break;
+ setval = t_str_trim(setval, "\t ");
+ if (strcasecmp(setval, "INBOX") == 0)
+ setval = t_str_ucase(setval);
+
+ mbrule = p_new(user->pool,
+ struct imap_sieve_mailbox_rule, 1);
+ mbrule->index = i;
+ mbrule->mailbox = p_strdup(user->pool, setval);
+
+ str_truncate(identifier, id_len);
+ str_append(identifier, "_from");
+ setval = mail_user_plugin_getenv(user, str_c(identifier));
+ if (setval != NULL && *setval != '\0') {
+ setval = t_str_trim(setval, "\t ");
+ if (strcasecmp(setval, "INBOX") == 0)
+ setval = t_str_ucase(setval);
+ mbrule->from = p_strdup(user->pool, setval);
+ if (strcmp(mbrule->from, "*") == 0)
+ mbrule->from = NULL;
+ }
+
+ if ((strcmp(mbrule->mailbox, "*") == 0 ||
+ !rule_pattern_has_wildcards(mbrule->mailbox)) &&
+ (mbrule->from == NULL ||
+ !rule_pattern_has_wildcards(mbrule->from)) &&
+ hash_table_lookup(isuser->mbox_rules, mbrule) != NULL) {
+ imap_sieve_warning(user,
+ "Duplicate static mailbox rule [%u] for mailbox `%s' "
+ "(skipped)", i, mbrule->mailbox);
+ continue;
+ }
+
+ str_truncate(identifier, id_len);
+ str_append(identifier, "_causes");
+ setval = mail_user_plugin_getenv(user, str_c(identifier));
+ if (setval != NULL && *setval != '\0') {
+ const char *const *cause;
+
+ mbrule->causes = (const char *const *)
+ p_strsplit_spaces(user->pool, setval, " \t,");
+
+ for (cause = mbrule->causes; *cause != NULL; cause++) {
+ if (!imap_sieve_event_cause_valid(*cause))
+ break;
+ }
+ if (*cause != NULL) {
+ imap_sieve_warning(user,
+ "Static mailbox rule [%u] has invalid event cause `%s' "
+ "(skipped)", i, *cause);
+ continue;
+ }
+ }
+
+ str_truncate(identifier, id_len);
+ str_append(identifier, "_before");
+ setval = mail_user_plugin_getenv(user, str_c(identifier));
+ mbrule->before = p_strdup_empty(user->pool, setval);
+
+ str_truncate(identifier, id_len);
+ str_append(identifier, "_after");
+ setval = mail_user_plugin_getenv(user, str_c(identifier));
+ mbrule->after = p_strdup_empty(user->pool, setval);
+
+ str_truncate(identifier, id_len);
+ str_append(identifier, "_copy_source_after");
+ setval = mail_user_plugin_getenv(user, str_c(identifier));
+ mbrule->copy_source_after = p_strdup_empty(user->pool, setval);
+
+ if (user->mail_debug) {
+ imap_sieve_debug(user, "Static mailbox rule [%u]: "
+ "mailbox=`%s' from=`%s' causes=(%s) => "
+ "before=%s after=%s%s",
+ mbrule->index, mbrule->mailbox,
+ (mbrule->from == NULL ? "*" : mbrule->from),
+ t_strarray_join(mbrule->causes, " "),
+ (mbrule->before == NULL ? "(none)" :
+ t_strconcat("`", mbrule->before, "'", NULL)),
+ (mbrule->after == NULL ? "(none)" :
+ t_strconcat("`", mbrule->after, "'", NULL)),
+ (mbrule->copy_source_after == NULL ? "":
+ t_strconcat(" copy_source_after=`",
+ mbrule->copy_source_after, "'", NULL)));
+ }
+
+ if ((strcmp(mbrule->mailbox, "*") == 0 ||
+ !rule_pattern_has_wildcards(mbrule->mailbox)) &&
+ (mbrule->from == NULL ||
+ !rule_pattern_has_wildcards(mbrule->from))) {
+ hash_table_insert(isuser->mbox_rules, mbrule, mbrule);
+ } else {
+ array_append(&isuser->mbox_patterns, &mbrule, 1);
+ }
+ }
+
+ if (i == 0)
+ imap_sieve_debug(user, "No static mailbox rules");
+}
+
+static bool
+imap_sieve_mailbox_rule_match_cause
+(struct imap_sieve_mailbox_rule *rule, const char *cause)
+{
+ const char *const *cp;
+
+ if (rule->causes == NULL || *rule->causes == NULL)
+ return TRUE;
+
+ for (cp = rule->causes; *cp != NULL; cp++) {
+ if (strcasecmp(cause, *cp) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+imap_sieve_mailbox_rules_match_patterns(struct mail_user *user,
+ struct mailbox *dst_box, struct mailbox *src_box,
+ const char *cause,
+ ARRAY_TYPE(imap_sieve_mailbox_rule) *rules)
+{
+ struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user);
+ struct imap_sieve_mailbox_rule *rule;
+ struct mail_namespace *dst_ns, *src_ns;
+
+ if (array_count(&isuser->mbox_patterns) == 0)
+ return;
+
+ dst_ns = mailbox_get_namespace(dst_box);
+ src_ns = (src_box == NULL ? NULL :
+ mailbox_get_namespace(src_box));
+
+ array_foreach_elem(&isuser->mbox_patterns, rule) {
+ struct imap_match_glob *glob;
+
+ if (src_ns == NULL && rule->from != NULL)
+ continue;
+ if (!imap_sieve_mailbox_rule_match_cause(rule, cause))
+ continue;
+
+ if (strcmp(rule->mailbox, "*") != 0) {
+ glob = imap_match_init(pool_datastack_create(),
+ rule->mailbox, TRUE, mail_namespace_get_sep(dst_ns));
+ if (imap_match(glob, mailbox_get_vname(dst_box))
+ != IMAP_MATCH_YES)
+ continue;
+ }
+ if (rule->from != NULL) {
+ glob = imap_match_init(pool_datastack_create(),
+ rule->from, TRUE, mail_namespace_get_sep(src_ns));
+ if (imap_match(glob, mailbox_get_vname(src_box))
+ != IMAP_MATCH_YES)
+ continue;
+ }
+
+ imap_sieve_debug(user,
+ "Matched static mailbox rule [%u]",
+ rule->index);
+ array_append(rules, &rule, 1);
+ }
+}
+
+static void
+imap_sieve_mailbox_rules_match(struct mail_user *user,
+ const char *dst_box, const char *src_box,
+ const char *cause,
+ ARRAY_TYPE(imap_sieve_mailbox_rule) *rules)
+{
+ struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user);
+ struct imap_sieve_mailbox_rule lookup_rule;
+ struct imap_sieve_mailbox_rule *rule;
+
+ i_zero(&lookup_rule);
+ lookup_rule.mailbox = dst_box;
+ lookup_rule.from = src_box;
+ rule = hash_table_lookup(isuser->mbox_rules, &lookup_rule);
+
+ if (rule != NULL &&
+ imap_sieve_mailbox_rule_match_cause(rule, cause)) {
+ struct imap_sieve_mailbox_rule *const *rule_idx;
+ unsigned int insert_idx = array_count(rules);
+
+ /* Insert sorted by rule index */
+ array_foreach(rules, rule_idx) {
+ if (rule->index < (*rule_idx)->index) {
+ insert_idx = array_foreach_idx(rules, rule_idx);
+ break;
+ }
+ }
+ array_insert(rules, insert_idx, &rule, 1);
+
+ imap_sieve_debug(user,
+ "Matched static mailbox rule [%u]",
+ rule->index);
+ }
+}
+
+static void
+imap_sieve_mailbox_rules_get(struct mail_user *user,
+ struct mailbox *dst_box, struct mailbox *src_box,
+ const char *cause,
+ ARRAY_TYPE(imap_sieve_mailbox_rule) *rules)
+{
+ const char *dst_name, *src_name;
+
+ imap_sieve_mailbox_rules_init(user);
+
+ imap_sieve_mailbox_rules_match_patterns
+ (user, dst_box, src_box, cause, rules);
+
+ dst_name = mailbox_get_vname(dst_box);
+ src_name = (src_box == NULL ? NULL :
+ mailbox_get_vname(src_box));
+
+ imap_sieve_mailbox_rules_match
+ (user, dst_name, src_name, cause, rules);
+ imap_sieve_mailbox_rules_match
+ (user, "*", src_name, cause, rules);
+ if (src_name != NULL) {
+ imap_sieve_mailbox_rules_match
+ (user, dst_name, NULL, cause, rules);
+ imap_sieve_mailbox_rules_match
+ (user, "*", NULL, cause, rules);
+ }
+}
+
+/*
+ * User
+ */
+
+static void imap_sieve_user_deinit(struct mail_user *user)
+{
+ struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user);
+
+ if (isuser->isieve != NULL)
+ imap_sieve_deinit(&isuser->isieve);
+
+ hash_table_destroy(&isuser->mbox_rules);
+ if (array_is_created(&isuser->mbox_patterns))
+ array_free(&isuser->mbox_patterns);
+
+ isuser->module_ctx.super.deinit(user);
+}
+
+static void imap_sieve_user_created(struct mail_user *user)
+{
+ struct imap_sieve_user *isuser;
+ struct mail_user_vfuncs *v = user->vlast;
+
+ isuser = p_new(user->pool, struct imap_sieve_user, 1);
+ isuser->module_ctx.super = *v;
+ user->vlast = &isuser->module_ctx.super;
+ v->deinit = imap_sieve_user_deinit;
+ MODULE_CONTEXT_SET(user, imap_sieve_user_module, isuser);
+}
+
+/*
+ * Hooks
+ */
+
+static struct mail_storage_hooks imap_sieve_mail_storage_hooks = {
+ .mail_user_created = imap_sieve_user_created,
+ .mailbox_allocated = imap_sieve_mailbox_allocated,
+ .mail_allocated = imap_sieve_mail_allocated
+};
+
+/*
+ * Commands
+ */
+
+static void imap_sieve_command_pre(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ struct mail_user *user = client->user;
+ struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT(user);
+
+ if (isuser == NULL)
+ return;
+
+ if (strcasecmp(cmd->name, "APPEND") == 0) {
+ isuser->cur_cmd = IMAP_SIEVE_CMD_APPEND;
+ } else if (strcasecmp(cmd->name, "COPY") == 0 ||
+ strcasecmp(cmd->name, "UID COPY") == 0) {
+ isuser->cur_cmd = IMAP_SIEVE_CMD_COPY;
+ } else if (strcasecmp(cmd->name, "MOVE") == 0 ||
+ strcasecmp(cmd->name, "UID MOVE") == 0) {
+ isuser->cur_cmd = IMAP_SIEVE_CMD_MOVE;
+ } else if (strcasecmp(cmd->name, "STORE") == 0 ||
+ strcasecmp(cmd->name, "UID STORE") == 0) {
+ isuser->cur_cmd = IMAP_SIEVE_CMD_STORE;
+ } else {
+ isuser->cur_cmd = IMAP_SIEVE_CMD_OTHER;
+ }
+}
+
+static void imap_sieve_command_post(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ struct mail_user *user = client->user;
+ struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT(user);
+
+ if (isuser == NULL)
+ return;
+ isuser->cur_cmd = IMAP_SIEVE_CMD_NONE;
+}
+
+/*
+ * Client
+ */
+
+void imap_sieve_storage_client_created(struct client *client,
+ bool user_script)
+{
+ struct mail_user *user = client->user;
+ struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user);
+ const char *set;
+
+ isuser->client = client;
+ isuser->user_script = user_script;
+
+ set = mail_user_plugin_getenv(user, "imapsieve_expunge_discarded");
+ isuser->expunge_discarded =
+ (set != NULL && strcasecmp(set, "yes") == 0);
+}
+
+/*
+ *
+ */
+
+void imap_sieve_storage_init(struct module *module)
+{
+ command_hook_register(imap_sieve_command_pre, imap_sieve_command_post);
+ mail_storage_hooks_add(module, &imap_sieve_mail_storage_hooks);
+}
+
+void imap_sieve_storage_deinit(void)
+{
+ mail_storage_hooks_remove(&imap_sieve_mail_storage_hooks);
+ command_hook_unregister(imap_sieve_command_pre, imap_sieve_command_post);
+}
diff --git a/pigeonhole/src/plugins/imapsieve/imap-sieve-storage.h b/pigeonhole/src/plugins/imapsieve/imap-sieve-storage.h
new file mode 100644
index 0000000..f96860f
--- /dev/null
+++ b/pigeonhole/src/plugins/imapsieve/imap-sieve-storage.h
@@ -0,0 +1,10 @@
+#ifndef IMAP_SIEVE_STORAGE_H
+#define IMAP_SIEVE_STORAGE_H
+
+void imap_sieve_storage_init(struct module *module);
+void imap_sieve_storage_deinit(void);
+
+void imap_sieve_storage_client_created(struct client *client,
+ bool user_script);
+
+#endif
diff --git a/pigeonhole/src/plugins/imapsieve/imap-sieve.c b/pigeonhole/src/plugins/imapsieve/imap-sieve.c
new file mode 100644
index 0000000..e6cc24a
--- /dev/null
+++ b/pigeonhole/src/plugins/imapsieve/imap-sieve.c
@@ -0,0 +1,940 @@
+/* Copyright (c) 2016-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "home-expand.h"
+#include "smtp-address.h"
+#include "smtp-submit.h"
+#include "mail-storage.h"
+#include "mail-user.h"
+#include "mail-duplicate.h"
+#include "iostream-ssl.h"
+#include "imap-client.h"
+#include "imap-settings.h"
+
+#include "sieve.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+
+#include "ext-imapsieve-common.h"
+
+#include "imap-sieve.h"
+
+/*
+ * Configuration
+ */
+
+#define DUPLICATE_DB_NAME "lda-dupes"
+#define IMAP_SIEVE_MAX_USER_ERRORS 30
+
+/*
+ * IMAP Sieve
+ */
+
+struct imap_sieve {
+ pool_t pool;
+ struct client *client;
+ const char *home_dir;
+
+ struct sieve_instance *svinst;
+ struct sieve_storage *storage;
+
+ const struct sieve_extension *ext_imapsieve;
+ const struct sieve_extension *ext_vnd_imapsieve;
+
+ struct mail_duplicate_db *dup_db;
+
+ struct sieve_error_handler *master_ehandler;
+};
+
+static const char *
+mail_sieve_get_setting(void *context, const char *identifier)
+{
+ struct imap_sieve *isieve = context;
+ struct mail_user *user = isieve->client->user;
+
+ return mail_user_plugin_getenv(user, identifier);
+}
+
+static const struct sieve_callbacks mail_sieve_callbacks = {
+ NULL,
+ mail_sieve_get_setting
+};
+
+struct imap_sieve *imap_sieve_init(struct client *client)
+{
+ struct sieve_environment svenv;
+ struct imap_sieve *isieve;
+ struct mail_user *user = client->user;
+ const struct mail_storage_settings *mail_set =
+ mail_user_set_get_storage_set(user);
+ bool debug = user->mail_debug;
+ pool_t pool;
+
+ pool = pool_alloconly_create("imap_sieve", 256);
+ isieve = p_new(pool, struct imap_sieve, 1);
+ isieve->pool = pool;
+ isieve->client = client;
+
+ isieve->dup_db = mail_duplicate_db_init(user, DUPLICATE_DB_NAME);
+
+ i_zero(&svenv);
+ svenv.username = user->username;
+ (void)mail_user_get_home(user, &svenv.home_dir);
+ svenv.hostname = mail_set->hostname;
+ svenv.base_dir = user->set->base_dir;
+ svenv.event_parent = client->event;
+ svenv.flags = SIEVE_FLAG_HOME_RELATIVE;
+ svenv.location = SIEVE_ENV_LOCATION_MS;
+ svenv.delivery_phase = SIEVE_DELIVERY_PHASE_POST;
+
+ isieve->home_dir = p_strdup(pool, svenv.home_dir);
+
+ isieve->svinst = sieve_init(&svenv, &mail_sieve_callbacks, isieve,
+ debug);
+
+ isieve->ext_imapsieve = sieve_extension_replace(
+ isieve->svinst, &imapsieve_extension, TRUE);
+ isieve->ext_vnd_imapsieve = sieve_extension_replace(
+ isieve->svinst, &vnd_imapsieve_extension, TRUE);
+
+ isieve->master_ehandler =
+ sieve_master_ehandler_create(isieve->svinst, 0);
+ sieve_error_handler_accept_infolog(isieve->master_ehandler, TRUE);
+ sieve_error_handler_accept_debuglog(isieve->master_ehandler, debug);
+
+ return isieve;
+}
+
+void imap_sieve_deinit(struct imap_sieve **_isieve)
+{
+ struct imap_sieve *isieve = *_isieve;
+
+ *_isieve = NULL;
+
+ sieve_error_handler_unref(&isieve->master_ehandler);
+
+ if (isieve->storage != NULL)
+ sieve_storage_unref(&isieve->storage);
+ sieve_extension_unregister(isieve->ext_imapsieve);
+ sieve_extension_unregister(isieve->ext_vnd_imapsieve);
+ sieve_deinit(&isieve->svinst);
+
+ mail_duplicate_db_deinit(&isieve->dup_db);
+
+ pool_unref(&isieve->pool);
+}
+
+static int
+imap_sieve_get_storage(struct imap_sieve *isieve,
+ struct sieve_storage **storage_r)
+{
+ enum sieve_storage_flags storage_flags = 0;
+ struct mail_user *user = isieve->client->user;
+ enum sieve_error error;
+
+ if (isieve->storage != NULL) {
+ *storage_r = isieve->storage;
+ return 1;
+ }
+
+ // FIXME: limit interval between retries
+
+ isieve->storage = sieve_storage_create_main(isieve->svinst, user,
+ storage_flags, &error);
+ if (isieve->storage == NULL) {
+ if (error == SIEVE_ERROR_TEMP_FAILURE)
+ return -1;
+ return 0;
+ }
+ *storage_r = isieve->storage;
+ return 1;
+}
+
+/*
+ * Mail transmission
+ */
+
+static void *
+imap_sieve_smtp_start(const struct sieve_script_env *senv,
+ const struct smtp_address *mail_from)
+{
+ struct imap_sieve_context *isctx = senv->script_context;
+ struct imap_sieve *isieve = isctx->isieve;
+ struct mail_user *user = isieve->client->user;
+ const struct smtp_submit_settings *smtp_set = isieve->client->smtp_set;
+ struct ssl_iostream_settings ssl_set;
+ struct smtp_submit_input submit_input;
+
+ i_zero(&ssl_set);
+ mail_user_init_ssl_client_settings(user, &ssl_set);
+
+ i_zero(&submit_input);
+ submit_input.ssl = &ssl_set;
+
+ return smtp_submit_init_simple(&submit_input, smtp_set, mail_from);
+}
+
+static void
+imap_sieve_smtp_add_rcpt(const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle, const struct smtp_address *rcpt_to)
+{
+ struct smtp_submit *smtp_submit = handle;
+
+ smtp_submit_add_rcpt(smtp_submit, rcpt_to);
+}
+
+static struct ostream *
+imap_sieve_smtp_send(const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle)
+{
+ struct smtp_submit *smtp_submit = handle;
+
+ return smtp_submit_send(smtp_submit);
+}
+
+static void
+imap_sieve_smtp_abort(const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle)
+{
+ struct smtp_submit *smtp_submit = handle;
+
+ smtp_submit_deinit(&smtp_submit);
+}
+
+static int
+imap_sieve_smtp_finish(const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle, const char **error_r)
+{
+ struct smtp_submit *smtp_submit = handle;
+ int ret;
+
+ ret = smtp_submit_run(smtp_submit, error_r);
+ smtp_submit_deinit(&smtp_submit);
+ return ret;
+}
+
+/*
+ * Duplicate checking
+ */
+
+static void *
+imap_sieve_duplicate_transaction_begin(const struct sieve_script_env *senv)
+{
+ struct imap_sieve_context *isctx = senv->script_context;
+
+ return mail_duplicate_transaction_begin(isctx->isieve->dup_db);
+}
+
+static void imap_sieve_duplicate_transaction_commit(void **_dup_trans)
+{
+ struct mail_duplicate_transaction *dup_trans = *_dup_trans;
+
+ *_dup_trans = NULL;
+ mail_duplicate_transaction_commit(&dup_trans);
+}
+
+static void imap_sieve_duplicate_transaction_rollback(void **_dup_trans)
+{
+ struct mail_duplicate_transaction *dup_trans = *_dup_trans;
+
+ *_dup_trans = NULL;
+ mail_duplicate_transaction_rollback(&dup_trans);
+}
+
+static enum sieve_duplicate_check_result
+imap_sieve_duplicate_check(void *_dup_trans,
+ const struct sieve_script_env *senv,
+ const void *id, size_t id_size)
+{
+ struct mail_duplicate_transaction *dup_trans = _dup_trans;
+
+ switch (mail_duplicate_check(dup_trans, id, id_size,
+ senv->user->username)) {
+ case MAIL_DUPLICATE_CHECK_RESULT_EXISTS:
+ return SIEVE_DUPLICATE_CHECK_RESULT_EXISTS;
+ case MAIL_DUPLICATE_CHECK_RESULT_NOT_FOUND:
+ return SIEVE_DUPLICATE_CHECK_RESULT_NOT_FOUND;
+ case MAIL_DUPLICATE_CHECK_RESULT_DEADLOCK:
+ case MAIL_DUPLICATE_CHECK_RESULT_LOCK_TIMEOUT:
+ return SIEVE_DUPLICATE_CHECK_RESULT_TEMP_FAILURE;
+ case MAIL_DUPLICATE_CHECK_RESULT_IO_ERROR:
+ case MAIL_DUPLICATE_CHECK_RESULT_TOO_MANY_LOCKS:
+ break;
+ }
+ return SIEVE_DUPLICATE_CHECK_RESULT_FAILURE;
+}
+
+static void
+imap_sieve_duplicate_mark(void *_dup_trans, const struct sieve_script_env *senv,
+ const void *id, size_t id_size, time_t time)
+{
+ struct mail_duplicate_transaction *dup_trans = _dup_trans;
+
+ mail_duplicate_mark(dup_trans, id, id_size, senv->user->username, time);
+}
+
+/*
+ * Result logging
+ */
+
+static const char *
+imap_sieve_result_amend_log_message(const struct sieve_script_env *senv,
+ enum log_type log_type ATTR_UNUSED,
+ const char *message)
+{
+ struct imap_sieve_context *isctx = senv->script_context;
+ string_t *str;
+
+ if (isctx->mail == NULL)
+ return message;
+
+ str = t_str_new(256);
+ str_printfa(str, "uid=%u: ", isctx->mail->uid);
+ str_append(str, message);
+ return str_c(str);
+}
+
+/*
+ * IMAP Sieve run
+ */
+
+struct imap_sieve_run_script {
+ struct sieve_script *script;
+ struct sieve_binary *binary;
+
+ /* Compile failed once with this error;
+ don't try again for this transaction */
+ enum sieve_error compile_error;
+
+ /* Binary corrupt after recompile; don't recompile again */
+ bool binary_corrupt:1;
+ /* Resource usage exceeded */
+ bool rusage_exceeded:1;
+};
+
+struct imap_sieve_run {
+ pool_t pool;
+ struct imap_sieve *isieve;
+ struct mailbox *dest_mailbox, *src_mailbox;
+ char *cause;
+
+ struct sieve_error_handler *user_ehandler;
+ char *userlog;
+
+ struct sieve_trace_config trace_config;
+ struct sieve_trace_log *trace_log;
+
+ struct sieve_script *user_script;
+ struct imap_sieve_run_script *scripts;
+ unsigned int scripts_count;
+
+ bool trace_log_initialized:1;
+};
+
+static void
+imap_sieve_run_init_user_log(struct imap_sieve_run *isrun)
+{
+ struct imap_sieve *isieve = isrun->isieve;
+ struct sieve_instance *svinst = isieve->svinst;
+ const char *log_path;
+
+ log_path = sieve_user_get_log_path(svinst, isrun->user_script);
+ if (log_path != NULL) {
+ isrun->userlog = p_strdup(isrun->pool, log_path);
+ isrun->user_ehandler = sieve_logfile_ehandler_create(
+ svinst, log_path, IMAP_SIEVE_MAX_USER_ERRORS);
+ }
+}
+
+static void
+imap_sieve_run_init_trace_log(struct imap_sieve_run *isrun,
+ struct sieve_trace_config *trace_config_r,
+ struct sieve_trace_log **trace_log_r)
+{
+ struct imap_sieve *isieve = isrun->isieve;
+ struct sieve_instance *svinst = isieve->svinst;
+ struct mail_user *user = isieve->client->user;
+
+ if (isrun->trace_log_initialized) {
+ *trace_config_r = isrun->trace_config;
+ *trace_log_r = isrun->trace_log;
+ return;
+ }
+ isrun->trace_log_initialized = TRUE;
+
+ if (sieve_trace_config_get(svinst, &isrun->trace_config) < 0 ||
+ sieve_trace_log_open(svinst, &isrun->trace_log) < 0) {
+ i_zero(&isrun->trace_config);
+ isrun->trace_log = NULL;
+
+ i_zero(trace_config_r);
+ *trace_log_r = NULL;
+ return;
+ }
+
+ /* Write header for trace file */
+ sieve_trace_log_printf(isrun->trace_log,
+ "Sieve trace log for IMAPSIEVE:\n"
+ "\n"
+ " Username: %s\n", user->username);
+ if (user->session_id != NULL) {
+ sieve_trace_log_printf(isrun->trace_log,
+ " Session ID: %s\n", user->session_id);
+ }
+ if (isrun->src_mailbox != NULL) {
+ sieve_trace_log_printf(isrun->trace_log,
+ " Source mailbox: %s\n",
+ mailbox_get_vname(isrun->src_mailbox));
+ }
+
+ sieve_trace_log_printf(isrun->trace_log,
+ " Destination mailbox: %s\n"
+ " Cause: %s\n\n",
+ mailbox_get_vname(isrun->dest_mailbox),
+ isrun->cause);
+
+ *trace_config_r = isrun->trace_config;
+ *trace_log_r = isrun->trace_log;
+}
+
+int imap_sieve_run_init(struct imap_sieve *isieve,
+ struct mailbox *dest_mailbox,
+ struct mailbox *src_mailbox,
+ const char *cause, const char *script_name,
+ const char *const *scripts_before,
+ const char *const *scripts_after,
+ struct imap_sieve_run **isrun_r)
+{
+ struct sieve_instance *svinst = isieve->svinst;
+ struct imap_sieve_run *isrun;
+ struct sieve_storage *storage;
+ struct imap_sieve_run_script *scripts;
+ struct sieve_script *user_script;
+ const char *const *sp;
+ enum sieve_error error;
+ pool_t pool;
+ unsigned int max_len, count;
+ int ret;
+
+ /* Determine how many scripts we may run for this event */
+ max_len = 0;
+ if (scripts_before != NULL)
+ max_len += str_array_length(scripts_before);
+ if (script_name != NULL)
+ max_len++;
+ if (scripts_after != NULL)
+ max_len += str_array_length(scripts_after);
+ if (max_len == 0)
+ return 0;
+
+ /* Get storage for user script */
+ storage = NULL;
+ if (script_name != NULL && *script_name != '\0' &&
+ (ret = imap_sieve_get_storage(isieve, &storage)) < 0)
+ return ret;
+
+ /* Open all scripts */
+ count = 0;
+ pool = pool_alloconly_create("imap_sieve_run", 256);
+ scripts = p_new(pool, struct imap_sieve_run_script, max_len);
+
+ /* Admin scripts before user script */
+ if (scripts_before != NULL) {
+ for (sp = scripts_before; *sp != NULL; sp++) {
+ i_assert(count < max_len);
+ scripts[count].script =
+ sieve_script_create_open(svinst, *sp, NULL,
+ &error);
+ if (scripts[count].script != NULL)
+ count++;
+ else if (error == SIEVE_ERROR_TEMP_FAILURE)
+ return -1;
+ }
+ }
+
+ /* The user script */
+ user_script = NULL;
+ if (storage != NULL) {
+ i_assert(count < max_len);
+ scripts[count].script =
+ sieve_storage_open_script(storage, script_name, &error);
+ if (scripts[count].script != NULL) {
+ user_script = scripts[count].script;
+ count++;
+ } else if (error == SIEVE_ERROR_TEMP_FAILURE) {
+ return -1;
+ }
+ }
+
+ /* Admin scripts after user script */
+ if (scripts_after != NULL) {
+ for (sp = scripts_after; *sp != NULL; sp++) {
+ i_assert(count < max_len);
+ scripts[count].script =
+ sieve_script_create_open(svinst, *sp, NULL,
+ &error);
+ if (scripts[count].script != NULL)
+ count++;
+ else if (error == SIEVE_ERROR_TEMP_FAILURE)
+ return -1;
+ }
+ }
+
+ if (count == 0) {
+ /* None of the scripts could be opened */
+ pool_unref(&pool);
+ return 0;
+ }
+
+ /* Initialize */
+ isrun = p_new(pool, struct imap_sieve_run, 1);
+ isrun->pool = pool;
+ isrun->isieve = isieve;
+ isrun->dest_mailbox = dest_mailbox;
+ isrun->src_mailbox = src_mailbox;
+ isrun->cause = p_strdup(pool, cause);
+ isrun->user_script = user_script;
+ isrun->scripts = scripts;
+ isrun->scripts_count = count;
+
+ imap_sieve_run_init_user_log(isrun);
+
+ *isrun_r = isrun;
+ return 1;
+}
+
+void imap_sieve_run_deinit(struct imap_sieve_run **_isrun)
+{
+ struct imap_sieve_run *isrun = *_isrun;
+ unsigned int i;
+
+ *_isrun = NULL;
+
+ for (i = 0; i < isrun->scripts_count; i++) {
+ if (isrun->scripts[i].binary != NULL)
+ sieve_close(&isrun->scripts[i].binary);
+ if (isrun->scripts[i].script != NULL)
+ sieve_script_unref(&isrun->scripts[i].script);
+ }
+ if (isrun->user_ehandler != NULL)
+ sieve_error_handler_unref(&isrun->user_ehandler);
+ if (isrun->trace_log != NULL)
+ sieve_trace_log_free(&isrun->trace_log);
+
+ pool_unref(&isrun->pool);
+}
+
+static struct sieve_binary *
+imap_sieve_run_open_script(struct imap_sieve_run *isrun,
+ struct sieve_script *script,
+ enum sieve_compile_flags cpflags,
+ bool recompile, enum sieve_error *error_r)
+{
+ struct imap_sieve *isieve = isrun->isieve;
+ struct sieve_instance *svinst = isieve->svinst;
+ struct sieve_error_handler *ehandler;
+ struct sieve_binary *sbin;
+ const char *compile_name = "compile";
+
+ if (recompile) {
+ /* Warn */
+ e_warning(sieve_get_event(svinst),
+ "Encountered corrupt binary: re-compiling script %s",
+ sieve_script_location(script));
+ compile_name = "re-compile";
+ } else {
+ e_debug(sieve_get_event(svinst),
+ "Loading script %s", sieve_script_location(script));
+ }
+
+ if (script == isrun->user_script)
+ ehandler = isrun->user_ehandler;
+ else
+ ehandler = isieve->master_ehandler;
+ sieve_error_handler_reset(ehandler);
+
+ /* Load or compile the sieve script */
+ if (recompile) {
+ sbin = sieve_compile_script(script, ehandler, cpflags, error_r);
+ } else {
+ sbin = sieve_open_script(script, ehandler, cpflags, error_r);
+ }
+
+ /* Handle error */
+ if (sbin == NULL) {
+ switch (*error_r) {
+ /* Script not found */
+ case SIEVE_ERROR_NOT_FOUND:
+ e_debug(sieve_get_event(svinst),
+ "Script `%s' is missing for %s",
+ sieve_script_location(script), compile_name);
+ break;
+ /* Temporary failure */
+ case SIEVE_ERROR_TEMP_FAILURE:
+ e_error(sieve_get_event(svinst),
+ "Failed to open script `%s' for %s "
+ "(temporary failure)",
+ sieve_script_location(script), compile_name);
+ break;
+ /* Compile failed */
+ case SIEVE_ERROR_NOT_VALID:
+ if (script == isrun->user_script &&
+ isrun->userlog != NULL ) {
+ e_info(sieve_get_event(svinst),
+ "Failed to %s script `%s' "
+ "(view user logfile `%s' for more information)",
+ compile_name, sieve_script_location(script),
+ isrun->userlog);
+ break;
+ }
+ e_error(sieve_get_event(svinst),
+ "Failed to %s script `%s'",
+ compile_name, sieve_script_location(script));
+ break;
+ /* Cumulative resource limit exceeded */
+ case SIEVE_ERROR_RESOURCE_LIMIT:
+ e_error(sieve_get_event(svinst),
+ "Failed to open script `%s' for %s "
+ "(cumulative resource limit exceeded)",
+ sieve_script_location(script), compile_name);
+ break;
+ /* Something else */
+ default:
+ e_error(sieve_get_event(svinst),
+ "Failed to open script `%s' for %s",
+ sieve_script_location(script), compile_name);
+ break;
+ }
+
+ return NULL;
+ }
+
+ if (!recompile)
+ (void)sieve_save(sbin, FALSE, NULL);
+ return sbin;
+}
+
+static int
+imap_sieve_handle_exec_status(struct imap_sieve_run *isrun,
+ struct sieve_script *script, int status,
+ struct sieve_exec_status *estatus, bool *fatal_r)
+ ATTR_NULL(2)
+{
+ struct imap_sieve *isieve = isrun->isieve;
+ struct sieve_instance *svinst = isieve->svinst;
+ const char *userlog_notice = "";
+ enum log_type log_level, user_log_level;
+ enum mail_error mail_error = MAIL_ERROR_NONE;
+ int ret = -1;
+
+ *fatal_r = FALSE;
+
+ log_level = user_log_level = LOG_TYPE_ERROR;
+
+ if (estatus->last_storage != NULL && estatus->store_failed) {
+ mail_storage_get_last_error(estatus->last_storage, &mail_error);
+
+ /* Don't bother administrator too much with benign errors */
+ if (mail_error == MAIL_ERROR_NOQUOTA) {
+ log_level = LOG_TYPE_INFO;
+ user_log_level = LOG_TYPE_INFO;
+ }
+ }
+
+ if (script == isrun->user_script && isrun->userlog != NULL) {
+ userlog_notice = t_strdup_printf(
+ " (user logfile %s may reveal additional details)",
+ isrun->userlog);
+ user_log_level = LOG_TYPE_INFO;
+ }
+
+ switch (status) {
+ case SIEVE_EXEC_FAILURE:
+ e_log(sieve_get_event(svinst), user_log_level,
+ "Execution of script %s failed%s",
+ sieve_script_location(script), userlog_notice);
+ ret = 0;
+ break;
+ case SIEVE_EXEC_TEMP_FAILURE:
+ e_log(sieve_get_event(svinst), log_level,
+ "Execution of script %s was aborted "
+ "due to temporary failure%s",
+ sieve_script_location(script), userlog_notice);
+ *fatal_r = TRUE;
+ ret = -1;
+ break;
+ case SIEVE_EXEC_BIN_CORRUPT:
+ e_error(sieve_get_event(svinst),
+ "!!BUG!!: Binary compiled from %s is still corrupt; "
+ "bailing out and reverting to default action",
+ sieve_script_location(script));
+ *fatal_r = TRUE;
+ ret = -1;
+ break;
+ case SIEVE_EXEC_RESOURCE_LIMIT:
+ e_error(sieve_get_event(svinst),
+ "Execution of script %s was aborted "
+ "due to excessive resource usage",
+ sieve_script_location(script));
+ *fatal_r = TRUE;
+ ret = -1;
+ break;
+ case SIEVE_EXEC_KEEP_FAILED:
+ e_log(sieve_get_event(svinst), log_level,
+ "Execution of script %s failed "
+ "with unsuccessful implicit keep%s",
+ sieve_script_location(script), userlog_notice);
+ ret = 0;
+ break;
+ case SIEVE_EXEC_OK:
+ ret = (estatus->keep_original ? 0 : 1);
+ break;
+ }
+
+ return ret;
+}
+
+static int
+imap_sieve_run_scripts(struct imap_sieve_run *isrun,
+ const struct sieve_message_data *msgdata,
+ const struct sieve_script_env *scriptenv, bool *fatal_r)
+{
+ struct imap_sieve *isieve = isrun->isieve;
+ struct sieve_instance *svinst = isieve->svinst;
+ struct imap_sieve_run_script *scripts = isrun->scripts;
+ unsigned int count = isrun->scripts_count;
+ struct sieve_resource_usage *rusage =
+ &scriptenv->exec_status->resource_usage;
+ struct sieve_multiscript *mscript;
+ struct sieve_error_handler *ehandler;
+ struct sieve_script *last_script = NULL;
+ bool user_script = FALSE, more = TRUE, rusage_exceeded = FALSE;
+ enum sieve_compile_flags cpflags;
+ enum sieve_execute_flags exflags;
+ enum sieve_error compile_error = SIEVE_ERROR_NONE;
+ unsigned int i;
+ int ret;
+
+ *fatal_r = FALSE;
+
+ /* Start execution */
+ mscript = sieve_multiscript_start_execute(svinst, msgdata, scriptenv);
+
+ /* Execute scripts */
+ for (i = 0; i < count && more; i++) {
+ struct sieve_script *script = scripts[i].script;
+ struct sieve_binary *sbin = scripts[i].binary;
+ int mstatus;
+
+ cpflags = 0;
+ exflags = SIEVE_EXECUTE_FLAG_NO_ENVELOPE |
+ SIEVE_EXECUTE_FLAG_SKIP_RESPONSES;
+
+ user_script = (script == isrun->user_script);
+ last_script = script;
+
+ if (scripts[i].rusage_exceeded) {
+ rusage_exceeded = TRUE;
+ break;
+ }
+
+ sieve_resource_usage_init(rusage);
+ if (user_script) {
+ cpflags |= SIEVE_COMPILE_FLAG_NOGLOBAL;
+ exflags |= SIEVE_EXECUTE_FLAG_NOGLOBAL;
+ ehandler = isrun->user_ehandler;
+ } else {
+ cpflags |= SIEVE_COMPILE_FLAG_NO_ENVELOPE;
+ ehandler = isieve->master_ehandler;
+ }
+
+ /* Open */
+ if (sbin == NULL) {
+ e_debug(sieve_get_event(svinst),
+ "Opening script %d of %d from `%s'",
+ i+1, count, sieve_script_location(script));
+
+ /* Already known to fail */
+ if (scripts[i].compile_error != SIEVE_ERROR_NONE) {
+ compile_error = scripts[i].compile_error;
+ break;
+ }
+
+ /* Try to open/compile binary */
+ scripts[i].binary = sbin = imap_sieve_run_open_script(
+ isrun, script, cpflags, FALSE, &compile_error);
+ if (sbin == NULL) {
+ scripts[i].compile_error = compile_error;
+ break;
+ }
+ }
+
+ /* Execute */
+ e_debug(sieve_get_event(svinst),
+ "Executing script from `%s'",
+ sieve_get_source(sbin));
+ more = sieve_multiscript_run(mscript, sbin, ehandler, ehandler,
+ exflags);
+
+ mstatus = sieve_multiscript_status(mscript);
+ if (!more && mstatus == SIEVE_EXEC_BIN_CORRUPT &&
+ !scripts[i].binary_corrupt && sieve_is_loaded(sbin)) {
+ /* Close corrupt script */
+ sieve_close(&sbin);
+
+ /* Recompile */
+ scripts[i].binary = sbin =
+ imap_sieve_run_open_script(
+ isrun, script, cpflags, FALSE,
+ &compile_error);
+ if (sbin == NULL) {
+ scripts[i].compile_error = compile_error;
+ break;
+ }
+
+ /* Execute again */
+ more = sieve_multiscript_run(mscript, sbin,
+ ehandler, ehandler,
+ exflags);
+
+ /* Save new version */
+
+ mstatus = sieve_multiscript_status(mscript);
+ if (mstatus == SIEVE_EXEC_BIN_CORRUPT)
+ scripts[i].binary_corrupt = TRUE;
+ else if (more)
+ (void)sieve_save(sbin, FALSE, NULL);
+ }
+
+ if (user_script && !sieve_record_resource_usage(sbin, rusage)) {
+ rusage_exceeded = ((i + 1) < count && more);
+ scripts[i].rusage_exceeded = TRUE;
+ break;
+ }
+ }
+
+ /* Finish execution */
+ exflags = SIEVE_EXECUTE_FLAG_NO_ENVELOPE |
+ SIEVE_EXECUTE_FLAG_SKIP_RESPONSES;
+ ehandler = (isrun->user_ehandler != NULL ?
+ isrun->user_ehandler : isieve->master_ehandler);
+ if (compile_error == SIEVE_ERROR_TEMP_FAILURE) {
+ ret = sieve_multiscript_finish(&mscript, ehandler, exflags,
+ SIEVE_EXEC_TEMP_FAILURE);
+ } else if (rusage_exceeded) {
+ i_assert(last_script != NULL);
+ (void)sieve_multiscript_finish(&mscript, ehandler, exflags,
+ SIEVE_EXEC_TEMP_FAILURE);
+ sieve_error(ehandler, sieve_script_name(last_script),
+ "cumulative resource usage limit exceeded");
+ ret = SIEVE_EXEC_RESOURCE_LIMIT;
+ } else {
+ ret = sieve_multiscript_finish(&mscript, ehandler, exflags,
+ SIEVE_EXEC_OK);
+ }
+
+ /* Don't log additional messages about compile failure */
+ if (compile_error != SIEVE_ERROR_NONE && ret == SIEVE_EXEC_FAILURE) {
+ e_info(sieve_get_event(svinst),
+ "Aborted script execution sequence "
+ "with successful implicit keep");
+ return 1;
+ }
+
+ if (last_script == NULL && ret == SIEVE_EXEC_OK)
+ return 0;
+ return imap_sieve_handle_exec_status(isrun, last_script, ret,
+ scriptenv->exec_status, fatal_r);
+}
+
+int imap_sieve_run_mail(struct imap_sieve_run *isrun, struct mail *mail,
+ const char *changed_flags, bool *fatal_r)
+{
+ struct imap_sieve *isieve = isrun->isieve;
+ struct sieve_instance *svinst = isieve->svinst;
+ struct mail_user *user = isieve->client->user;
+ struct sieve_message_data msgdata;
+ struct sieve_script_env scriptenv;
+ struct sieve_exec_status estatus;
+ struct imap_sieve_context context;
+ struct sieve_trace_config trace_config;
+ struct sieve_trace_log *trace_log;
+ const char *error;
+ int ret;
+
+ *fatal_r = FALSE;
+
+ i_zero(&context);
+ context.event.dest_mailbox = isrun->dest_mailbox;
+ context.event.src_mailbox = isrun->src_mailbox;
+ context.event.cause = isrun->cause;
+ context.event.changed_flags = changed_flags;
+ context.mail = mail;
+ context.isieve = isieve;
+
+ /* Initialize trace logging */
+ imap_sieve_run_init_trace_log(isrun, &trace_config, &trace_log);
+
+ T_BEGIN {
+ if (trace_log != NULL) {
+ /* Write trace header for message */
+ sieve_trace_log_printf(trace_log,
+ "Filtering message:\n"
+ "\n"
+ " UID: %u\n", mail->uid);
+ if (changed_flags != NULL && *changed_flags != '\0') {
+ sieve_trace_log_printf(trace_log,
+ " Changed flags: %s\n", changed_flags);
+ }
+ }
+
+ /* Collect necessary message data */
+
+ i_zero(&msgdata);
+ msgdata.mail = mail;
+ msgdata.auth_user = user->username;
+ (void)mail_get_message_id(msgdata.mail, &msgdata.id);
+
+ /* Compose script execution environment */
+
+ if (sieve_script_env_init(&scriptenv, user, &error) < 0) {
+ e_error(sieve_get_event(svinst),
+ "Failed to initialize script execution: %s",
+ error);
+ ret = -1;
+ } else {
+ scriptenv.default_mailbox =
+ mailbox_get_vname(mail->box);
+ scriptenv.smtp_start = imap_sieve_smtp_start;
+ scriptenv.smtp_add_rcpt = imap_sieve_smtp_add_rcpt;
+ scriptenv.smtp_send = imap_sieve_smtp_send;
+ scriptenv.smtp_abort = imap_sieve_smtp_abort;
+ scriptenv.smtp_finish = imap_sieve_smtp_finish;
+ scriptenv.duplicate_transaction_begin =
+ imap_sieve_duplicate_transaction_begin;
+ scriptenv.duplicate_transaction_commit =
+ imap_sieve_duplicate_transaction_commit;
+ scriptenv.duplicate_transaction_rollback =
+ imap_sieve_duplicate_transaction_rollback;
+ scriptenv.duplicate_mark = imap_sieve_duplicate_mark;
+ scriptenv.duplicate_check = imap_sieve_duplicate_check;
+ scriptenv.result_amend_log_message =
+ imap_sieve_result_amend_log_message;
+ scriptenv.trace_log = trace_log;
+ scriptenv.trace_config = trace_config;
+ scriptenv.script_context = &context;
+
+ i_zero(&estatus);
+ scriptenv.exec_status = &estatus;
+
+ /* Execute script(s) */
+
+ ret = imap_sieve_run_scripts(isrun, &msgdata,
+ &scriptenv, fatal_r);
+ }
+ } T_END;
+
+ return ret;
+}
diff --git a/pigeonhole/src/plugins/imapsieve/imap-sieve.h b/pigeonhole/src/plugins/imapsieve/imap-sieve.h
new file mode 100644
index 0000000..12d0ac7
--- /dev/null
+++ b/pigeonhole/src/plugins/imapsieve/imap-sieve.h
@@ -0,0 +1,59 @@
+#ifndef IMAP_SIEVE_H
+#define IMAP_SIEVE_H
+
+struct client;
+
+/*
+ * IMAP event
+ */
+
+struct imap_sieve_event {
+ struct mailbox *dest_mailbox, *src_mailbox;
+ const char *cause;
+ const char *changed_flags;
+};
+
+struct imap_sieve_context {
+ struct imap_sieve_event event;
+ struct mail *mail;
+
+ struct imap_sieve *isieve;
+};
+
+static inline bool
+imap_sieve_event_cause_valid(const char *cause)
+{
+ return (strcasecmp(cause, "APPEND") == 0 ||
+ strcasecmp(cause, "COPY") == 0 ||
+ strcasecmp(cause, "FLAG") == 0);
+}
+
+/*
+ * IMAP Sieve
+ */
+
+struct imap_sieve;
+
+struct imap_sieve *imap_sieve_init(struct client *client);
+void imap_sieve_deinit(struct imap_sieve **_isieve);
+
+/*
+ * IMAP Sieve run
+ */
+
+struct imap_sieve_run;
+
+int imap_sieve_run_init(struct imap_sieve *isieve, struct mailbox *dest_mailbox,
+ struct mailbox *src_mailbox, const char *cause,
+ const char *script_name,
+ const char *const *scripts_before,
+ const char *const *scripts_after,
+ struct imap_sieve_run **isrun_r)
+ ATTR_NULL(4, 5, 6);
+
+int imap_sieve_run_mail(struct imap_sieve_run *isrun, struct mail *mail,
+ const char *changed_flags, bool *fatal_r);
+
+void imap_sieve_run_deinit(struct imap_sieve_run **_isrun);
+
+#endif
diff --git a/pigeonhole/src/plugins/imapsieve/sieve-imapsieve-plugin.c b/pigeonhole/src/plugins/imapsieve/sieve-imapsieve-plugin.c
new file mode 100644
index 0000000..12611b3
--- /dev/null
+++ b/pigeonhole/src/plugins/imapsieve/sieve-imapsieve-plugin.c
@@ -0,0 +1,62 @@
+/* Copyright (c) 2016-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve.h"
+#include "sieve-error.h"
+#include "sieve-extensions.h"
+
+#include "ext-imapsieve-common.h"
+
+#include "sieve-imapsieve-plugin.h"
+
+/*
+ * Sieve plugin interface
+ */
+
+struct _plugin_context {
+ const struct sieve_extension *ext_imapsieve;
+ const struct sieve_extension *ext_vnd_imapsieve;
+};
+
+const char *sieve_imapsieve_plugin_version = PIGEONHOLE_ABI_VERSION;
+
+void sieve_imapsieve_plugin_load
+(struct sieve_instance *svinst, void **context)
+{
+ struct _plugin_context *pctx = i_new(struct _plugin_context, 1);
+
+ pctx->ext_imapsieve = sieve_extension_register
+ (svinst, &imapsieve_extension_dummy, TRUE);
+ pctx->ext_vnd_imapsieve = sieve_extension_register
+ (svinst, &vnd_imapsieve_extension_dummy, TRUE);
+
+ e_debug(sieve_get_event(svinst),
+ "Sieve imapsieve plugin for %s version %s loaded",
+ PIGEONHOLE_NAME, PIGEONHOLE_VERSION_FULL);
+
+ *context = (void *)pctx;
+}
+
+void sieve_imapsieve_plugin_unload
+(struct sieve_instance *svinst ATTR_UNUSED, void *context)
+{
+ struct _plugin_context *pctx = (struct _plugin_context *)context;
+
+ sieve_extension_unregister(pctx->ext_imapsieve);
+ sieve_extension_unregister(pctx->ext_vnd_imapsieve);
+
+ i_free(pctx);}
+
+/*
+ * Module interface
+ */
+
+void sieve_imapsieve_plugin_init(void)
+{
+ /* Nothing */
+}
+
+void sieve_imapsieve_plugin_deinit(void)
+{
+ /* Nothing */
+}
diff --git a/pigeonhole/src/plugins/imapsieve/sieve-imapsieve-plugin.h b/pigeonhole/src/plugins/imapsieve/sieve-imapsieve-plugin.h
new file mode 100644
index 0000000..fcf9777
--- /dev/null
+++ b/pigeonhole/src/plugins/imapsieve/sieve-imapsieve-plugin.h
@@ -0,0 +1,20 @@
+#ifndef SIEVE_IMAPSIEVE_PLUGIN_H
+#define SIEVE_IMAPSIEVE_PLUGIN_H
+
+/*
+ * Plugin interface
+ */
+
+void sieve_imapsieve_plugin_load
+ (struct sieve_instance *svinst, void **context);
+void sieve_imapsieve_plugin_unload
+ (struct sieve_instance *svinst, void *context);
+
+/*
+ * Module interface
+ */
+
+void sieve_imapsieve_plugin_init(void);
+void sieve_imapsieve_plugin_deinit(void);
+
+#endif
diff --git a/pigeonhole/src/plugins/lda-sieve/Makefile.am b/pigeonhole/src/plugins/lda-sieve/Makefile.am
new file mode 100644
index 0000000..7c2797a
--- /dev/null
+++ b/pigeonhole/src/plugins/lda-sieve/Makefile.am
@@ -0,0 +1,19 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib-sieve \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_DICT_INCLUDE) \
+ $(LIBDOVECOT_SMTP_INCLUDE) \
+ $(LIBDOVECOT_LDA_INCLUDE)
+
+lib90_sieve_plugin_la_LDFLAGS = -module -avoid-version
+
+dovecot_module_LTLIBRARIES = lib90_sieve_plugin.la
+
+lib90_sieve_plugin_la_LIBADD = \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la
+
+lib90_sieve_plugin_la_SOURCES = \
+ lda-sieve-plugin.c
+
+noinst_HEADERS = \
+ lda-sieve-plugin.h
diff --git a/pigeonhole/src/plugins/lda-sieve/Makefile.in b/pigeonhole/src/plugins/lda-sieve/Makefile.in
new file mode 100644
index 0000000..6f0fba0
--- /dev/null
+++ b/pigeonhole/src/plugins/lda-sieve/Makefile.in
@@ -0,0 +1,746 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/plugins/lda-sieve
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(dovecot_moduledir)"
+LTLIBRARIES = $(dovecot_module_LTLIBRARIES)
+lib90_sieve_plugin_la_DEPENDENCIES = \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la
+am_lib90_sieve_plugin_la_OBJECTS = lda-sieve-plugin.lo
+lib90_sieve_plugin_la_OBJECTS = $(am_lib90_sieve_plugin_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+lib90_sieve_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(lib90_sieve_plugin_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/lda-sieve-plugin.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(lib90_sieve_plugin_la_SOURCES)
+DIST_SOURCES = $(lib90_sieve_plugin_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib-sieve \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_DICT_INCLUDE) \
+ $(LIBDOVECOT_SMTP_INCLUDE) \
+ $(LIBDOVECOT_LDA_INCLUDE)
+
+lib90_sieve_plugin_la_LDFLAGS = -module -avoid-version
+dovecot_module_LTLIBRARIES = lib90_sieve_plugin.la
+lib90_sieve_plugin_la_LIBADD = \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la
+
+lib90_sieve_plugin_la_SOURCES = \
+ lda-sieve-plugin.c
+
+noinst_HEADERS = \
+ lda-sieve-plugin.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/lda-sieve/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/plugins/lda-sieve/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-dovecot_moduleLTLIBRARIES: $(dovecot_module_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(dovecot_module_LTLIBRARIES)'; test -n "$(dovecot_moduledir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(dovecot_moduledir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(dovecot_moduledir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(dovecot_moduledir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(dovecot_moduledir)"; \
+ }
+
+uninstall-dovecot_moduleLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dovecot_module_LTLIBRARIES)'; test -n "$(dovecot_moduledir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(dovecot_moduledir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(dovecot_moduledir)/$$f"; \
+ done
+
+clean-dovecot_moduleLTLIBRARIES:
+ -test -z "$(dovecot_module_LTLIBRARIES)" || rm -f $(dovecot_module_LTLIBRARIES)
+ @list='$(dovecot_module_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+lib90_sieve_plugin.la: $(lib90_sieve_plugin_la_OBJECTS) $(lib90_sieve_plugin_la_DEPENDENCIES) $(EXTRA_lib90_sieve_plugin_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(lib90_sieve_plugin_la_LINK) -rpath $(dovecot_moduledir) $(lib90_sieve_plugin_la_OBJECTS) $(lib90_sieve_plugin_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lda-sieve-plugin.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(dovecot_moduledir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-dovecot_moduleLTLIBRARIES clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/lda-sieve-plugin.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dovecot_moduleLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/lda-sieve-plugin.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dovecot_moduleLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-dovecot_moduleLTLIBRARIES clean-generic clean-libtool \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dovecot_moduleLTLIBRARIES \
+ install-dvi install-dvi-am install-exec install-exec-am \
+ install-html install-html-am install-info install-info-am \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-dovecot_moduleLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/plugins/lda-sieve/lda-sieve-plugin.c b/pigeonhole/src/plugins/lda-sieve/lda-sieve-plugin.c
new file mode 100644
index 0000000..4e79c1f
--- /dev/null
+++ b/pigeonhole/src/plugins/lda-sieve/lda-sieve-plugin.c
@@ -0,0 +1,1128 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "array.h"
+#include "home-expand.h"
+#include "var-expand.h"
+#include "eacces-error.h"
+#include "smtp-address.h"
+#include "smtp-submit.h"
+#include "mail-storage.h"
+#include "mail-deliver.h"
+#include "mail-user.h"
+#include "mail-duplicate.h"
+#include "smtp-submit.h"
+#include "mail-send.h"
+#include "iostream-ssl.h"
+#include "lda-settings.h"
+
+#include "sieve.h"
+#include "sieve-script.h"
+#include "sieve-storage.h"
+
+#include "lda-sieve-plugin.h"
+
+#include <sys/stat.h>
+#include <dirent.h>
+
+/*
+ * Configuration
+ */
+
+#define LDA_SIEVE_DEFAULT_LOCATION "~/.dovecot.sieve"
+
+#define LDA_SIEVE_MAX_USER_ERRORS 30
+
+/*
+ * Global variables
+ */
+
+static deliver_mail_func_t *next_deliver_mail;
+
+/*
+ * Settings handling
+ */
+
+static const char *
+lda_sieve_get_setting(void *context, const char *identifier)
+{
+ struct mail_deliver_context *mdctx =
+ (struct mail_deliver_context *)context;
+ const char *value = NULL;
+
+ if (mdctx == NULL)
+ return NULL;
+
+ if (mdctx->rcpt_user == NULL ||
+ (value = mail_user_plugin_getenv(
+ mdctx->rcpt_user, identifier)) == NULL) {
+ if (strcmp(identifier, "recipient_delimiter") == 0)
+ value = mdctx->set->recipient_delimiter;
+ }
+
+ return value;
+}
+
+static const struct sieve_callbacks lda_sieve_callbacks = {
+ NULL,
+ lda_sieve_get_setting
+};
+
+/*
+ * Mail transmission
+ */
+
+static void *
+lda_sieve_smtp_start(const struct sieve_script_env *senv,
+ const struct smtp_address *mail_from)
+{
+ struct mail_deliver_context *dctx =
+ (struct mail_deliver_context *)senv->script_context;
+ struct mail_user *user = dctx->rcpt_user;
+ struct ssl_iostream_settings ssl_set;
+ struct smtp_submit_input submit_input;
+
+ i_zero(&ssl_set);
+ mail_user_init_ssl_client_settings(user, &ssl_set);
+
+ i_zero(&submit_input);
+ submit_input.ssl = &ssl_set;
+
+ return (void *)smtp_submit_init_simple(&submit_input, dctx->smtp_set,
+ mail_from);
+}
+
+static void
+lda_sieve_smtp_add_rcpt(const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle, const struct smtp_address *rcpt_to)
+{
+ struct smtp_submit *smtp_submit = (struct smtp_submit *) handle;
+
+ smtp_submit_add_rcpt(smtp_submit, rcpt_to);
+}
+
+static struct ostream *
+lda_sieve_smtp_send(const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle)
+{
+ struct smtp_submit *smtp_submit = (struct smtp_submit *) handle;
+
+ return smtp_submit_send(smtp_submit);
+}
+
+static void
+lda_sieve_smtp_abort(const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle)
+{
+ struct smtp_submit *smtp_submit = (struct smtp_submit *) handle;
+
+ smtp_submit_deinit(&smtp_submit);
+}
+
+static int
+lda_sieve_smtp_finish(const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle, const char **error_r)
+{
+ struct smtp_submit *smtp_submit = (struct smtp_submit *) handle;
+ int ret;
+
+ ret = smtp_submit_run(smtp_submit, error_r);
+ smtp_submit_deinit(&smtp_submit);
+ return ret;
+}
+
+static int
+lda_sieve_reject_mail(const struct sieve_script_env *senv,
+ const struct smtp_address *recipient,
+ const char *reason)
+{
+ struct mail_deliver_context *dctx =
+ (struct mail_deliver_context *)senv->script_context;
+
+ return mail_send_rejection(dctx, recipient, reason);
+}
+
+/*
+ * Duplicate checking
+ */
+
+static void *
+lda_sieve_duplicate_transaction_begin(const struct sieve_script_env *senv)
+{
+ struct mail_deliver_context *dctx =
+ (struct mail_deliver_context *)senv->script_context;
+
+ return mail_duplicate_transaction_begin(dctx->dup_db);
+}
+
+static void lda_sieve_duplicate_transaction_commit(void **_dup_trans)
+{
+ struct mail_duplicate_transaction *dup_trans = *_dup_trans;
+
+ *_dup_trans = NULL;
+ mail_duplicate_transaction_commit(&dup_trans);
+}
+
+static void lda_sieve_duplicate_transaction_rollback(void **_dup_trans)
+{
+ struct mail_duplicate_transaction *dup_trans = *_dup_trans;
+
+ *_dup_trans = NULL;
+ mail_duplicate_transaction_rollback(&dup_trans);
+}
+
+static enum sieve_duplicate_check_result
+lda_sieve_duplicate_check(void *_dup_trans, const struct sieve_script_env *senv,
+ const void *id, size_t id_size)
+{
+ struct mail_duplicate_transaction *dup_trans = _dup_trans;
+
+ switch (mail_duplicate_check(dup_trans, id, id_size,
+ senv->user->username)) {
+ case MAIL_DUPLICATE_CHECK_RESULT_EXISTS:
+ return SIEVE_DUPLICATE_CHECK_RESULT_EXISTS;
+ case MAIL_DUPLICATE_CHECK_RESULT_NOT_FOUND:
+ return SIEVE_DUPLICATE_CHECK_RESULT_NOT_FOUND;
+ case MAIL_DUPLICATE_CHECK_RESULT_DEADLOCK:
+ case MAIL_DUPLICATE_CHECK_RESULT_LOCK_TIMEOUT:
+ return SIEVE_DUPLICATE_CHECK_RESULT_TEMP_FAILURE;
+ case MAIL_DUPLICATE_CHECK_RESULT_IO_ERROR:
+ case MAIL_DUPLICATE_CHECK_RESULT_TOO_MANY_LOCKS:
+ break;
+ }
+ return SIEVE_DUPLICATE_CHECK_RESULT_FAILURE;
+}
+
+static void
+lda_sieve_duplicate_mark(void *_dup_trans, const struct sieve_script_env *senv,
+ const void *id, size_t id_size, time_t time)
+{
+ struct mail_duplicate_transaction *dup_trans = _dup_trans;
+
+ mail_duplicate_mark(dup_trans, id, id_size, senv->user->username, time);
+}
+
+/*
+ * Result logging
+ */
+
+static const char *
+lda_sieve_result_amend_log_message(const struct sieve_script_env *senv,
+ enum log_type log_type ATTR_UNUSED,
+ const char *message)
+{
+ struct mail_deliver_context *mdctx = senv->script_context;
+ const struct var_expand_table *table;
+ string_t *str;
+ const char *error;
+
+ table = mail_deliver_ctx_get_log_var_expand_table(mdctx, message);
+
+ str = t_str_new(256);
+ if (var_expand(str, mdctx->set->deliver_log_format,
+ table, &error) <= 0) {
+ e_error(mdctx->event,
+ "Failed to expand deliver_log_format=%s: %s",
+ mdctx->set->deliver_log_format, error);
+ }
+ return str_c(str);
+}
+
+/*
+ * Plugin implementation
+ */
+
+struct lda_sieve_run_context {
+ struct sieve_instance *svinst;
+
+ struct mail_deliver_context *mdctx;
+ const char *home_dir;
+
+ struct sieve_script **scripts;
+ unsigned int script_count;
+
+ struct sieve_script *user_script;
+ struct sieve_script *main_script;
+ struct sieve_script *discard_script;
+
+ const struct sieve_message_data *msgdata;
+ const struct sieve_script_env *scriptenv;
+
+ struct sieve_error_handler *user_ehandler;
+ struct sieve_error_handler *master_ehandler;
+ struct sieve_error_handler *action_ehandler;
+ const char *userlog;
+};
+
+static int
+lda_sieve_get_personal_storage(struct sieve_instance *svinst,
+ struct mail_user *user,
+ struct sieve_storage **storage_r,
+ enum sieve_error *error_r)
+{
+ *storage_r = sieve_storage_create_main(svinst, user, 0, error_r);
+ if (*storage_r == NULL) {
+ switch (*error_r) {
+ case SIEVE_ERROR_NOT_POSSIBLE:
+ case SIEVE_ERROR_NOT_FOUND:
+ break;
+ case SIEVE_ERROR_TEMP_FAILURE:
+ e_error(sieve_get_event(svinst),
+ "Failed to access user's personal storage "
+ "(temporary failure)");
+ return -1;
+ default:
+ e_error(sieve_get_event(svinst),
+ "Failed to access user's personal storage");
+ break;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+static int
+lda_sieve_multiscript_get_scripts(struct sieve_instance *svinst,
+ const char *label, const char *location,
+ ARRAY_TYPE(sieve_script) *scripts,
+ enum sieve_error *error_r)
+{
+ struct sieve_script_sequence *seq;
+ struct sieve_script *script;
+ bool finished = FALSE;
+ int ret = 1;
+
+ seq = sieve_script_sequence_create(svinst, location, error_r);
+ if (seq == NULL)
+ return (*error_r == SIEVE_ERROR_NOT_FOUND ? 0 : -1);
+
+ while (ret > 0 && !finished) {
+ script = sieve_script_sequence_next(seq, error_r);
+ if (script == NULL) {
+ switch (*error_r) {
+ case SIEVE_ERROR_NONE:
+ finished = TRUE;
+ break;
+ case SIEVE_ERROR_TEMP_FAILURE:
+ e_error(sieve_get_event(svinst),
+ "Failed to access %s script from `%s' "
+ "(temporary failure)",
+ label, location);
+ ret = -1;
+ default:
+ break;
+ }
+ continue;
+ }
+
+ array_append(scripts, &script, 1);
+ }
+
+ sieve_script_sequence_free(&seq);
+ return ret;
+}
+
+static void
+lda_sieve_binary_save(struct lda_sieve_run_context *srctx,
+ struct sieve_binary *sbin, struct sieve_script *script)
+{
+ enum sieve_error error;
+
+ /* Save binary when compiled */
+ if (sieve_save(sbin, FALSE, &error) < 0 &&
+ error == SIEVE_ERROR_NO_PERMISSION &&
+ script != srctx->user_script) {
+ /* Cannot save binary for global script */
+ e_error(sieve_get_event(srctx->svinst),
+ "The LDA Sieve plugin does not have permission "
+ "to save global Sieve script binaries; "
+ "global Sieve scripts like `%s' need to be "
+ "pre-compiled using the sievec tool",
+ sieve_script_location(script));
+ }
+}
+
+static struct
+sieve_binary *lda_sieve_open(struct lda_sieve_run_context *srctx,
+ struct sieve_script *script,
+ enum sieve_compile_flags cpflags, bool recompile,
+ enum sieve_error *error_r)
+{
+ struct sieve_instance *svinst = srctx->svinst;
+ struct sieve_error_handler *ehandler;
+ struct sieve_binary *sbin;
+ const char *compile_name = "compile";
+
+ if (recompile) {
+ /* Warn */
+ e_warning(sieve_get_event(svinst),
+ "Encountered corrupt binary: re-compiling script %s",
+ sieve_script_location(script));
+ compile_name = "re-compile";
+ } else {
+ e_debug(sieve_get_event(svinst),
+ "Loading script %s", sieve_script_location(script));
+ }
+
+ if (script == srctx->user_script)
+ ehandler = srctx->user_ehandler;
+ else
+ ehandler = srctx->master_ehandler;
+
+ sieve_error_handler_reset(ehandler);
+
+ if (recompile)
+ sbin = sieve_compile_script(script, ehandler, cpflags, error_r);
+ else
+ sbin = sieve_open_script(script, ehandler, cpflags, error_r);
+
+ /* Load or compile the sieve script */
+ if (sbin == NULL) {
+ switch (*error_r) {
+ /* Script not found */
+ case SIEVE_ERROR_NOT_FOUND:
+ e_debug(sieve_get_event(svinst),
+ "Script `%s' is missing for %s",
+ sieve_script_location(script),
+ compile_name);
+ break;
+ /* Temporary failure */
+ case SIEVE_ERROR_TEMP_FAILURE:
+ e_error(sieve_get_event(svinst),
+ "Failed to open script `%s' for %s "
+ "(temporary failure)",
+ sieve_script_location(script), compile_name);
+ break;
+ /* Compile failed */
+ case SIEVE_ERROR_NOT_VALID:
+ if (script == srctx->user_script &&
+ srctx->userlog != NULL ) {
+ e_info(sieve_get_event(svinst),
+ "Failed to %s script `%s' "
+ "(view user logfile `%s' for more information)",
+ compile_name,
+ sieve_script_location(script),
+ srctx->userlog);
+ break;
+ }
+ e_error(sieve_get_event(svinst),
+ "Failed to %s script `%s'",
+ compile_name, sieve_script_location(script));
+ break;
+ /* Cumulative resource limit exceeded */
+ case SIEVE_ERROR_RESOURCE_LIMIT:
+ e_error(sieve_get_event(svinst),
+ "Failed to open script `%s' for %s "
+ "(cumulative resource limit exceeded)",
+ sieve_script_location(script), compile_name);
+ break;
+ /* Something else */
+ default:
+ e_error(sieve_get_event(svinst),
+ "Failed to open script `%s' for %s",
+ sieve_script_location(script), compile_name);
+ break;
+ }
+
+ return NULL;
+ }
+
+ if (!recompile)
+ lda_sieve_binary_save(srctx, sbin, script);
+ return sbin;
+}
+
+static int
+lda_sieve_handle_exec_status(struct lda_sieve_run_context *srctx,
+ struct sieve_script *script, int status)
+{
+ struct sieve_instance *svinst = srctx->svinst;
+ struct mail_deliver_context *mdctx = srctx->mdctx;
+ struct sieve_exec_status *estatus = srctx->scriptenv->exec_status;
+ const char *userlog_notice = "";
+ enum log_type log_level, user_log_level;
+ enum mail_error mail_error = MAIL_ERROR_NONE;
+ int ret;
+
+ log_level = user_log_level = LOG_TYPE_ERROR;
+
+ if (estatus != NULL && estatus->last_storage != NULL &&
+ estatus->store_failed) {
+ mail_storage_get_last_error(estatus->last_storage, &mail_error);
+
+ /* Don't bother administrator too much with benign errors */
+ if (mail_error == MAIL_ERROR_NOQUOTA) {
+ log_level = LOG_TYPE_INFO;
+ user_log_level = LOG_TYPE_INFO;
+ }
+ }
+
+ if (script == srctx->user_script && srctx->userlog != NULL) {
+ userlog_notice = t_strdup_printf(
+ " (user logfile %s may reveal additional details)",
+ srctx->userlog);
+ user_log_level = LOG_TYPE_INFO;
+ }
+
+ switch (status) {
+ case SIEVE_EXEC_FAILURE:
+ e_log(sieve_get_event(svinst), user_log_level,
+ "Execution of script %s failed, "
+ "but implicit keep was successful%s",
+ sieve_script_location(script), userlog_notice);
+ ret = 1;
+ break;
+ case SIEVE_EXEC_TEMP_FAILURE:
+ e_log(sieve_get_event(svinst), log_level,
+ "Execution of script %s was aborted due to temporary failure%s",
+ sieve_script_location(script), userlog_notice);
+ if (mail_error != MAIL_ERROR_TEMP &&
+ mdctx->tempfail_error == NULL) {
+ mdctx->tempfail_error =
+ "Execution of Sieve filters was aborted due to temporary failure";
+ }
+ ret = -1;
+ break;
+ case SIEVE_EXEC_BIN_CORRUPT:
+ e_error(sieve_get_event(svinst),
+ "!!BUG!!: Binary compiled from %s is still corrupt; "
+ "bailing out and reverting to default delivery",
+ sieve_script_location(script));
+ ret = -1;
+ break;
+ case SIEVE_EXEC_RESOURCE_LIMIT:
+ e_error(sieve_get_event(svinst),
+ "Execution of script %s was aborted "
+ "due to excessive resource usage",
+ sieve_script_location(script));
+ ret = -1;
+ break;
+ case SIEVE_EXEC_KEEP_FAILED:
+ e_log(sieve_get_event(svinst), log_level,
+ "Execution of script %s failed with unsuccessful implicit keep%s",
+ sieve_script_location(script), userlog_notice);
+ ret = -1;
+ break;
+ default:
+ ret = status > 0 ? 1 : -1;
+ break;
+ }
+
+ return ret;
+}
+
+static int
+lda_sieve_execute_script(struct lda_sieve_run_context *srctx,
+ struct sieve_multiscript *mscript,
+ struct sieve_script *script,
+ unsigned int index, bool discard_script,
+ enum sieve_error *error_r)
+{
+ struct sieve_instance *svinst = srctx->svinst;
+ struct sieve_error_handler *exec_ehandler;
+ struct sieve_binary *sbin = NULL;
+ enum sieve_compile_flags cpflags = 0;
+ enum sieve_execute_flags exflags = SIEVE_EXECUTE_FLAG_LOG_RESULT;
+ struct sieve_resource_usage *rusage =
+ &srctx->scriptenv->exec_status->resource_usage;
+ bool user_script;
+ int mstatus, ret;
+
+ *error_r = SIEVE_ERROR_NONE;
+
+ user_script = (script == srctx->user_script);
+
+ sieve_resource_usage_init(rusage);
+ if (user_script) {
+ cpflags |= SIEVE_COMPILE_FLAG_NOGLOBAL;
+ exflags |= SIEVE_EXECUTE_FLAG_NOGLOBAL;
+ exec_ehandler = srctx->user_ehandler;
+ } else {
+ exec_ehandler = srctx->master_ehandler;
+ }
+
+ /* Open */
+
+ if (!discard_script) {
+ e_debug(sieve_get_event(svinst),
+ "Opening script %d of %d from `%s'",
+ index, srctx->script_count,
+ sieve_script_location(script));
+ } else {
+ e_debug(sieve_get_event(svinst),
+ "Opening discard script from `%s'",
+ sieve_script_location(script));
+ }
+
+ sbin = lda_sieve_open(srctx, script, cpflags, FALSE, error_r);
+ if (sbin == NULL)
+ return 0;
+
+ /* Execute */
+
+ e_debug(sieve_get_event(svinst),
+ "Executing script from `%s'",
+ sieve_get_source(sbin));
+
+ if (!discard_script) {
+ ret = (sieve_multiscript_run(mscript, sbin, exec_ehandler,
+ exec_ehandler, exflags) ? 1 : 0);
+ } else {
+ sieve_multiscript_run_discard(mscript, sbin, exec_ehandler,
+ exec_ehandler, exflags);
+ ret = 0;
+ }
+
+ mstatus = sieve_multiscript_status(mscript);
+ if (ret == 0 && mstatus == SIEVE_EXEC_BIN_CORRUPT &&
+ sieve_is_loaded(sbin)) {
+ /* Close corrupt script */
+
+ sieve_close(&sbin);
+
+ /* Recompile */
+
+ sbin = lda_sieve_open(srctx, script, cpflags, TRUE,
+ error_r);
+ if (sbin == NULL)
+ return 0;
+
+ /* Execute again */
+
+ if (!discard_script) {
+ ret = (sieve_multiscript_run(
+ mscript, sbin, exec_ehandler,
+ exec_ehandler, exflags) ? 1 : 0);
+ } else {
+ sieve_multiscript_run_discard(
+ mscript, sbin, exec_ehandler,
+ exec_ehandler, exflags);
+ }
+
+ /* Save new version */
+
+ mstatus = sieve_multiscript_status(mscript);
+ if (mstatus != SIEVE_EXEC_BIN_CORRUPT)
+ lda_sieve_binary_save(srctx, sbin, script);
+ }
+ if (ret == 0 && mstatus == SIEVE_EXEC_RESOURCE_LIMIT)
+ ret = -1;
+
+ if (user_script)
+ (void)sieve_record_resource_usage(sbin, rusage);
+
+ sieve_close(&sbin);
+
+ return ret;
+}
+
+static int lda_sieve_execute_scripts(struct lda_sieve_run_context *srctx)
+{
+ struct sieve_instance *svinst = srctx->svinst;
+ struct sieve_multiscript *mscript;
+ struct sieve_error_handler *exec_ehandler;
+ struct sieve_script *script, *last_script = NULL;
+ enum sieve_execute_flags exflags = SIEVE_EXECUTE_FLAG_LOG_RESULT;
+ bool discard_script;
+ enum sieve_error error;
+ unsigned int i;
+ int ret;
+
+ i_assert(srctx->script_count > 0);
+
+ /* Start execution */
+
+ mscript = sieve_multiscript_start_execute(svinst, srctx->msgdata,
+ srctx->scriptenv);
+
+ /* Execute scripts */
+
+ i = 0;
+ discard_script = FALSE;
+ error = SIEVE_ERROR_NONE;
+ for (;;) {
+ if (!discard_script) {
+ /* normal script sequence */
+ i_assert(i < srctx->script_count);
+ script = srctx->scripts[i];
+ i++;
+ } else {
+ /* discard script */
+ script = srctx->discard_script;
+ }
+
+ i_assert(script != NULL);
+ last_script = script;
+
+ ret = lda_sieve_execute_script(srctx, mscript, script, i,
+ discard_script, &error);
+ if (ret < 0)
+ break;
+ if (error == SIEVE_ERROR_NOT_FOUND) {
+ /* skip scripts which finally turn out not to exist */
+ ret = 1;
+ }
+
+ if (discard_script) {
+ /* Executed discard script, which is always final */
+ break;
+ } else if (ret > 0) {
+ /* The "keep" action is applied; execute next script */
+ i_assert(i <= srctx->script_count);
+ if (i == srctx->script_count) {
+ /* End of normal script sequence */
+ break;
+ }
+ } else if (error != SIEVE_ERROR_NONE) {
+ break;
+ } else if (sieve_multiscript_will_discard(mscript) &&
+ srctx->discard_script != NULL) {
+ /* Mail is set to be discarded, but we have a discard script. */
+ discard_script = TRUE;
+ } else {
+ break;
+ }
+ }
+
+ /* Finish execution */
+ exec_ehandler = (srctx->user_ehandler != NULL ?
+ srctx->user_ehandler : srctx->master_ehandler);
+ ret = sieve_multiscript_finish(&mscript, exec_ehandler, exflags,
+ (error == SIEVE_ERROR_TEMP_FAILURE ?
+ SIEVE_EXEC_TEMP_FAILURE :
+ SIEVE_EXEC_OK));
+
+ /* Don't log additional messages about compile failure */
+ if (error != SIEVE_ERROR_NONE && ret == SIEVE_EXEC_FAILURE) {
+ e_info(sieve_get_event(svinst),
+ "Aborted script execution sequence with successful implicit keep");
+ return 1;
+ }
+
+ return lda_sieve_handle_exec_status(srctx, last_script, ret);
+}
+
+static int lda_sieve_find_scripts(struct lda_sieve_run_context *srctx)
+{
+ struct mail_deliver_context *mdctx = srctx->mdctx;
+ struct sieve_instance *svinst = srctx->svinst;
+ struct sieve_storage *main_storage;
+ const char *sieve_before, *sieve_after, *sieve_discard;
+ const char *setting_name;
+ enum sieve_error error;
+ ARRAY_TYPE(sieve_script) script_sequence;
+ struct sieve_script *const *scripts;
+ unsigned int after_index, count, i;
+ int ret = 1;
+
+ /* Find the personal script to execute */
+
+ ret = lda_sieve_get_personal_storage(svinst, mdctx->rcpt_user,
+ &main_storage, &error);
+ if (ret == 0 && error == SIEVE_ERROR_NOT_POSSIBLE)
+ return 0;
+ if (ret > 0) {
+ srctx->main_script =
+ sieve_storage_active_script_open(main_storage, &error);
+
+ if (srctx->main_script == NULL) {
+ switch (error) {
+ case SIEVE_ERROR_NOT_FOUND:
+ e_debug(sieve_get_event(svinst),
+ "User has no active script in storage `%s'",
+ sieve_storage_location(main_storage));
+ break;
+ case SIEVE_ERROR_TEMP_FAILURE:
+ e_error(sieve_get_event(svinst),
+ "Failed to access active Sieve script in user storage `%s' "
+ "(temporary failure)",
+ sieve_storage_location(main_storage));
+ ret = -1;
+ break;
+ default:
+ e_error(sieve_get_event(svinst),
+ "Failed to access active Sieve script in user storage `%s'",
+ sieve_storage_location(main_storage));
+ break;
+ }
+ } else if (!sieve_script_is_default(srctx->main_script)) {
+ srctx->user_script = srctx->main_script;
+ }
+ sieve_storage_unref(&main_storage);
+ }
+
+ if (ret >= 0 && srctx->main_script == NULL) {
+ e_debug(sieve_get_event(svinst),
+ "User has no personal script");
+ }
+
+ /* Compose script array */
+
+ t_array_init(&script_sequence, 16);
+
+ /* before */
+ if (ret >= 0) {
+ i = 2;
+ setting_name = "sieve_before";
+ sieve_before = mail_user_plugin_getenv(
+ mdctx->rcpt_user, setting_name);
+ while (ret >= 0 &&
+ sieve_before != NULL && *sieve_before != '\0') {
+ ret = lda_sieve_multiscript_get_scripts(
+ svinst, setting_name, sieve_before,
+ &script_sequence, &error);
+ if (ret < 0 && error == SIEVE_ERROR_TEMP_FAILURE) {
+ ret = -1;
+ break;
+ } else if (ret == 0) {
+ e_debug(sieve_get_event(svinst),
+ "Location for %s not found: %s",
+ setting_name, sieve_before);
+ }
+ ret = 0;
+ setting_name = t_strdup_printf("sieve_before%u", i++);
+ sieve_before = mail_user_plugin_getenv(
+ mdctx->rcpt_user, setting_name);
+ }
+
+ if (ret >= 0) {
+ scripts = array_get(&script_sequence, &count);
+ for (i = 0; i < count; i ++) {
+ e_debug(sieve_get_event(svinst),
+ "Executed before user's personal Sieve script(%d): %s",
+ i+1, sieve_script_location(scripts[i]));
+ }
+ }
+ }
+
+ /* main */
+ if (srctx->main_script != NULL) {
+ array_append(&script_sequence, &srctx->main_script, 1);
+
+ if (ret >= 0) {
+ e_debug(sieve_get_event(svinst),
+ "Using the following location for user's Sieve script: %s",
+ sieve_script_location(srctx->main_script));
+ }
+ }
+
+ after_index = array_count(&script_sequence);
+
+ /* after */
+ if (ret >= 0) {
+ i = 2;
+ setting_name = "sieve_after";
+ sieve_after = mail_user_plugin_getenv(mdctx->rcpt_user, setting_name);
+ while (sieve_after != NULL && *sieve_after != '\0') {
+ ret = lda_sieve_multiscript_get_scripts(
+ svinst, setting_name, sieve_after,
+ &script_sequence, &error);
+ if (ret < 0 && error == SIEVE_ERROR_TEMP_FAILURE) {
+ ret = -1;
+ break;
+ } else if (ret == 0) {
+ e_debug(sieve_get_event(svinst),
+ "Location for %s not found: %s",
+ setting_name, sieve_after);
+ }
+ ret = 0;
+ setting_name = t_strdup_printf("sieve_after%u", i++);
+ sieve_after = mail_user_plugin_getenv(
+ mdctx->rcpt_user, setting_name);
+ }
+
+ if (ret >= 0) {
+ scripts = array_get(&script_sequence, &count);
+ for ( i = after_index; i < count; i ++ ) {
+ e_debug(sieve_get_event(svinst),
+ "executed after user's Sieve script(%d): %s",
+ i+1, sieve_script_location(scripts[i]));
+ }
+ }
+ }
+
+ /* discard */
+ sieve_discard = mail_user_plugin_getenv(
+ mdctx->rcpt_user, "sieve_discard");
+ if (sieve_discard != NULL && *sieve_discard != '\0') {
+ srctx->discard_script = sieve_script_create_open(
+ svinst, sieve_discard, NULL, &error);
+ if (srctx->discard_script == NULL) {
+ switch (error) {
+ case SIEVE_ERROR_NOT_FOUND:
+ e_debug(sieve_get_event(svinst),
+ "Location for sieve_discard not found: %s",
+ sieve_discard);
+ break;
+ case SIEVE_ERROR_TEMP_FAILURE:
+ ret = -1;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (ret < 0) {
+ mdctx->tempfail_error =
+ "Temporarily unable to access necessary Sieve scripts";
+ }
+ srctx->scripts =
+ array_get_modifiable(&script_sequence, &srctx->script_count);
+ return ret;
+}
+
+static void
+lda_sieve_free_scripts(struct lda_sieve_run_context *srctx)
+{
+ unsigned int i;
+
+ for (i = 0; i < srctx->script_count; i++)
+ sieve_script_unref(&srctx->scripts[i]);
+ if (srctx->discard_script != NULL)
+ sieve_script_unref(&srctx->discard_script);
+}
+
+static void
+lda_sieve_init_trace_log(struct lda_sieve_run_context *srctx,
+ const struct smtp_address *mail_from,
+ struct sieve_trace_config *trace_config_r,
+ struct sieve_trace_log **trace_log_r)
+{
+ struct mail_deliver_context *mdctx = srctx->mdctx;
+ struct sieve_instance *svinst = srctx->svinst;
+ struct sieve_trace_log *trace_log = NULL;
+
+ if (sieve_trace_config_get(svinst, trace_config_r) < 0 ||
+ sieve_trace_log_open(svinst, &trace_log) < 0) {
+ i_zero(trace_config_r);
+ *trace_log_r = NULL;
+ return;
+ }
+
+ /* Write header for trace file */
+ sieve_trace_log_printf(trace_log,
+ "Sieve trace log for message delivery:\n"
+ "\n"
+ " Username: %s\n", mdctx->rcpt_user->username);
+ if (mdctx->rcpt_user->session_id != NULL) {
+ sieve_trace_log_printf(trace_log,
+ " Session ID: %s\n",
+ mdctx->rcpt_user->session_id);
+ }
+ sieve_trace_log_printf(trace_log,
+ " Sender: %s\n"
+ " Final recipient: %s\n"
+ " Default mailbox: %s\n\n",
+ smtp_address_encode_path(mail_from),
+ smtp_address_encode_path(mdctx->rcpt_to),
+ (mdctx->rcpt_default_mailbox != NULL ?
+ mdctx->rcpt_default_mailbox : "INBOX"));
+
+ *trace_log_r = trace_log;
+}
+
+static int
+lda_sieve_execute(struct lda_sieve_run_context *srctx,
+ struct mail_storage **storage_r)
+{
+ struct mail_deliver_context *mdctx = srctx->mdctx;
+ struct sieve_instance *svinst = srctx->svinst;
+ struct sieve_message_data msgdata;
+ struct sieve_script_env scriptenv;
+ struct sieve_exec_status estatus;
+ struct sieve_trace_config trace_config;
+ const struct smtp_address *mail_from;
+ struct sieve_trace_log *trace_log;
+ const char *error;
+ int ret;
+
+ /* Check whether there are any scripts to execute at all */
+
+ if (srctx->script_count == 0) {
+ e_debug(sieve_get_event(svinst),
+ "No scripts to execute: "
+ "reverting to default delivery.");
+
+ /* No error, but no delivery by this plugin either. A return
+ value of <= 0 for a deliver plugin is is considered a
+ failure. In deliver itself, saved_mail and tried_default_save
+ remain unset, meaning that deliver will then attempt the
+ default delivery. We return 0 to signify the lack of a real
+ error.
+ */
+ return 0;
+ }
+
+ /* Initialize user error handler */
+
+ if (srctx->user_script != NULL) {
+ const char *log_path =
+ sieve_user_get_log_path(svinst, srctx->user_script);
+
+ if (log_path != NULL) {
+ srctx->userlog = log_path;
+ srctx->user_ehandler = sieve_logfile_ehandler_create(
+ svinst, srctx->userlog,
+ LDA_SIEVE_MAX_USER_ERRORS);
+ }
+ }
+
+ /* Determine return address */
+
+ mail_from = mail_deliver_get_return_address(mdctx);
+
+ /* Initialize trace logging */
+
+ lda_sieve_init_trace_log(srctx, mail_from, &trace_config, &trace_log);
+
+ /* Collect necessary message data */
+
+ i_zero(&msgdata);
+
+ msgdata.mail = mdctx->src_mail;
+ msgdata.auth_user = mdctx->rcpt_user->username;
+ msgdata.envelope.mail_from = mail_from;
+ msgdata.envelope.mail_params = &mdctx->mail_params;
+ msgdata.envelope.rcpt_to = mdctx->rcpt_to;
+ msgdata.envelope.rcpt_params = &mdctx->rcpt_params;
+ (void)mail_get_message_id(msgdata.mail, &msgdata.id);
+
+ srctx->msgdata = &msgdata;
+
+ /* Compose script execution environment */
+
+ if (sieve_script_env_init(&scriptenv, mdctx->rcpt_user, &error) < 0) {
+ e_error(sieve_get_event(svinst),
+ "Failed to initialize script execution: %s", error);
+ if (trace_log != NULL)
+ sieve_trace_log_free(&trace_log);
+ return -1;
+ }
+
+ scriptenv.default_mailbox = mdctx->rcpt_default_mailbox;
+ scriptenv.mailbox_autocreate = mdctx->set->lda_mailbox_autocreate;
+ scriptenv.mailbox_autosubscribe = mdctx->set->lda_mailbox_autosubscribe;
+ scriptenv.smtp_start = lda_sieve_smtp_start;
+ scriptenv.smtp_add_rcpt = lda_sieve_smtp_add_rcpt;
+ scriptenv.smtp_send = lda_sieve_smtp_send;
+ scriptenv.smtp_abort = lda_sieve_smtp_abort;
+ scriptenv.smtp_finish = lda_sieve_smtp_finish;
+ scriptenv.duplicate_transaction_begin =
+ lda_sieve_duplicate_transaction_begin;
+ scriptenv.duplicate_transaction_commit =
+ lda_sieve_duplicate_transaction_commit;
+ scriptenv.duplicate_transaction_rollback =
+ lda_sieve_duplicate_transaction_rollback;
+ scriptenv.duplicate_mark = lda_sieve_duplicate_mark;
+ scriptenv.duplicate_check = lda_sieve_duplicate_check;
+ scriptenv.reject_mail = lda_sieve_reject_mail;
+ scriptenv.result_amend_log_message = lda_sieve_result_amend_log_message;
+ scriptenv.script_context = (void *) mdctx;
+ scriptenv.trace_log = trace_log;
+ scriptenv.trace_config = trace_config;
+
+ i_zero(&estatus);
+ scriptenv.exec_status = &estatus;
+
+ srctx->scriptenv = &scriptenv;
+
+ /* Execute script(s) */
+
+ ret = lda_sieve_execute_scripts(srctx);
+
+ /* Record status */
+
+ mdctx->tried_default_save = estatus.tried_default_save;
+ *storage_r = estatus.last_storage;
+
+ if (trace_log != NULL)
+ sieve_trace_log_free(&trace_log);
+
+ return ret;
+}
+
+static int
+lda_sieve_deliver_mail(struct mail_deliver_context *mdctx,
+ struct mail_storage **storage_r)
+{
+ struct lda_sieve_run_context srctx;
+ const struct mail_storage_settings *mail_set =
+ mail_user_set_get_storage_set(mdctx->rcpt_user);
+ bool debug = mdctx->rcpt_user->mail_debug;
+ struct sieve_environment svenv;
+ int ret = 0;
+
+ /* Initialize run context */
+
+ i_zero(&srctx);
+ srctx.mdctx = mdctx;
+ (void)mail_user_get_home(mdctx->rcpt_user, &srctx.home_dir);
+
+ /* Initialize Sieve engine */
+
+ memset((void*)&svenv, 0, sizeof(svenv));
+ svenv.username = mdctx->rcpt_user->username;
+ svenv.home_dir = srctx.home_dir;
+ svenv.hostname = mail_set->hostname;
+ svenv.base_dir = mdctx->rcpt_user->set->base_dir;
+ svenv.temp_dir = mdctx->rcpt_user->set->mail_temp_dir;
+ svenv.event_parent = mdctx->event;
+ svenv.flags = SIEVE_FLAG_HOME_RELATIVE;
+ svenv.location = SIEVE_ENV_LOCATION_MDA;
+ svenv.delivery_phase = SIEVE_DELIVERY_PHASE_DURING;
+
+ srctx.svinst = sieve_init(&svenv, &lda_sieve_callbacks, mdctx, debug);
+
+ /* Initialize master error handler */
+
+ srctx.master_ehandler = sieve_master_ehandler_create(srctx.svinst, 0);
+
+ sieve_error_handler_accept_infolog(srctx.master_ehandler, TRUE);
+ sieve_error_handler_accept_debuglog(srctx.master_ehandler, debug);
+
+ *storage_r = NULL;
+
+ /* Find Sieve scripts and run them */
+
+ T_BEGIN {
+ if (lda_sieve_find_scripts(&srctx) < 0)
+ ret = -1;
+ else if (srctx.scripts == NULL)
+ ret = 0;
+ else
+ ret = lda_sieve_execute(&srctx, storage_r);
+
+ lda_sieve_free_scripts(&srctx);
+ } T_END;
+
+ /* Clean up */
+
+ if (srctx.user_ehandler != NULL)
+ sieve_error_handler_unref(&srctx.user_ehandler);
+ sieve_error_handler_unref(&srctx.master_ehandler);
+ sieve_deinit(&srctx.svinst);
+
+ return ret;
+}
+
+/*
+ * Plugin interface
+ */
+
+const char *sieve_plugin_version = DOVECOT_ABI_VERSION;
+const char sieve_plugin_binary_dependency[] = "lda lmtp";
+
+void sieve_plugin_init(void)
+{
+ /* Hook into the delivery process */
+ next_deliver_mail = mail_deliver_hook_set(lda_sieve_deliver_mail);
+}
+
+void sieve_plugin_deinit(void)
+{
+ /* Remove hook */
+ mail_deliver_hook_set(next_deliver_mail);
+}
diff --git a/pigeonhole/src/plugins/lda-sieve/lda-sieve-plugin.h b/pigeonhole/src/plugins/lda-sieve/lda-sieve-plugin.h
new file mode 100644
index 0000000..2357097
--- /dev/null
+++ b/pigeonhole/src/plugins/lda-sieve/lda-sieve-plugin.h
@@ -0,0 +1,11 @@
+#ifndef LDA_SIEVE_PLUGIN_H
+#define LDA_SIEVE_PLUGIN_H
+
+/*
+ * Plugin interface
+ */
+
+void sieve_plugin_init(void);
+void sieve_plugin_deinit(void);
+
+#endif
diff --git a/pigeonhole/src/plugins/settings/Makefile.am b/pigeonhole/src/plugins/settings/Makefile.am
new file mode 100644
index 0000000..49537e1
--- /dev/null
+++ b/pigeonhole/src/plugins/settings/Makefile.am
@@ -0,0 +1,12 @@
+settingsdir = $(dovecot_moduledir)/settings
+
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE)
+
+libpigeonhole_settings_la_LDFLAGS = -module -avoid-version
+
+settings_LTLIBRARIES = \
+ libpigeonhole_settings.la
+
+libpigeonhole_settings_la_SOURCES = \
+ pigeonhole-settings.c
diff --git a/pigeonhole/src/plugins/settings/Makefile.in b/pigeonhole/src/plugins/settings/Makefile.in
new file mode 100644
index 0000000..ee34c03
--- /dev/null
+++ b/pigeonhole/src/plugins/settings/Makefile.in
@@ -0,0 +1,737 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/plugins/settings
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(settingsdir)"
+LTLIBRARIES = $(settings_LTLIBRARIES)
+libpigeonhole_settings_la_LIBADD =
+am_libpigeonhole_settings_la_OBJECTS = pigeonhole-settings.lo
+libpigeonhole_settings_la_OBJECTS = \
+ $(am_libpigeonhole_settings_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libpigeonhole_settings_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libpigeonhole_settings_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/pigeonhole-settings.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libpigeonhole_settings_la_SOURCES)
+DIST_SOURCES = $(libpigeonhole_settings_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+settingsdir = $(dovecot_moduledir)/settings
+AM_CPPFLAGS = \
+ $(LIBDOVECOT_INCLUDE)
+
+libpigeonhole_settings_la_LDFLAGS = -module -avoid-version
+settings_LTLIBRARIES = \
+ libpigeonhole_settings.la
+
+libpigeonhole_settings_la_SOURCES = \
+ pigeonhole-settings.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/settings/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/plugins/settings/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-settingsLTLIBRARIES: $(settings_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(settings_LTLIBRARIES)'; test -n "$(settingsdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(settingsdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(settingsdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(settingsdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(settingsdir)"; \
+ }
+
+uninstall-settingsLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(settings_LTLIBRARIES)'; test -n "$(settingsdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(settingsdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(settingsdir)/$$f"; \
+ done
+
+clean-settingsLTLIBRARIES:
+ -test -z "$(settings_LTLIBRARIES)" || rm -f $(settings_LTLIBRARIES)
+ @list='$(settings_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libpigeonhole_settings.la: $(libpigeonhole_settings_la_OBJECTS) $(libpigeonhole_settings_la_DEPENDENCIES) $(EXTRA_libpigeonhole_settings_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libpigeonhole_settings_la_LINK) -rpath $(settingsdir) $(libpigeonhole_settings_la_OBJECTS) $(libpigeonhole_settings_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pigeonhole-settings.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(settingsdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-settingsLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/pigeonhole-settings.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-settingsLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/pigeonhole-settings.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-settingsLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-settingsLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am \
+ install-settingsLTLIBRARIES install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am \
+ uninstall-settingsLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/plugins/settings/pigeonhole-settings.c b/pigeonhole/src/plugins/settings/pigeonhole-settings.c
new file mode 100644
index 0000000..21f8e85
--- /dev/null
+++ b/pigeonhole/src/plugins/settings/pigeonhole-settings.c
@@ -0,0 +1,13 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "pigeonhole-config.h"
+#include "pigeonhole-version.h"
+
+/* This is currently just a dummy plugin that adds a Pigeonhole
+ * version banner the doveconf output.
+ */
+
+const char *pigeonhole_settings_version = DOVECOT_ABI_VERSION;
+const char *pigeonhole_settings_doveconf_banner = "Pigeonhole version "PIGEONHOLE_VERSION_FULL;
diff --git a/pigeonhole/src/plugins/sieve-extprograms/Makefile.am b/pigeonhole/src/plugins/sieve-extprograms/Makefile.am
new file mode 100644
index 0000000..ab7844f
--- /dev/null
+++ b/pigeonhole/src/plugins/sieve-extprograms/Makefile.am
@@ -0,0 +1,34 @@
+sieve_plugindir = $(dovecot_moduledir)/sieve
+
+sieve_plugin_LTLIBRARIES = lib90_sieve_extprograms_plugin.la
+
+lib90_sieve_extprograms_plugin_la_LDFLAGS = -module -avoid-version
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib-sieve \
+ -I$(top_srcdir)/src/lib-sieve/util \
+ -I$(top_srcdir)/src/lib-sieve/plugins/copy \
+ -I$(top_srcdir)/src/lib-sieve/plugins/variables \
+ $(LIBDOVECOT_INCLUDE) \
+ -DPKG_RUNDIR=\""$(rundir)"\"
+
+commands = \
+ cmd-pipe.c \
+ cmd-filter.c \
+ cmd-execute.c
+
+extensions = \
+ ext-pipe.c \
+ ext-filter.c \
+ ext-execute.c
+
+lib90_sieve_extprograms_plugin_la_SOURCES = \
+ $(commands) \
+ $(extensions) \
+ sieve-extprograms-common.c \
+ sieve-extprograms-plugin.c
+
+noinst_HEADERS = \
+ sieve-extprograms-common.h \
+ sieve-extprograms-plugin.h
+
diff --git a/pigeonhole/src/plugins/sieve-extprograms/Makefile.in b/pigeonhole/src/plugins/sieve-extprograms/Makefile.in
new file mode 100644
index 0000000..e35da7b
--- /dev/null
+++ b/pigeonhole/src/plugins/sieve-extprograms/Makefile.in
@@ -0,0 +1,790 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/plugins/sieve-extprograms
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(sieve_plugindir)"
+LTLIBRARIES = $(sieve_plugin_LTLIBRARIES)
+lib90_sieve_extprograms_plugin_la_LIBADD =
+am__objects_1 = cmd-pipe.lo cmd-filter.lo cmd-execute.lo
+am__objects_2 = ext-pipe.lo ext-filter.lo ext-execute.lo
+am_lib90_sieve_extprograms_plugin_la_OBJECTS = $(am__objects_1) \
+ $(am__objects_2) sieve-extprograms-common.lo \
+ sieve-extprograms-plugin.lo
+lib90_sieve_extprograms_plugin_la_OBJECTS = \
+ $(am_lib90_sieve_extprograms_plugin_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+lib90_sieve_extprograms_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(lib90_sieve_extprograms_plugin_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cmd-execute.Plo \
+ ./$(DEPDIR)/cmd-filter.Plo ./$(DEPDIR)/cmd-pipe.Plo \
+ ./$(DEPDIR)/ext-execute.Plo ./$(DEPDIR)/ext-filter.Plo \
+ ./$(DEPDIR)/ext-pipe.Plo \
+ ./$(DEPDIR)/sieve-extprograms-common.Plo \
+ ./$(DEPDIR)/sieve-extprograms-plugin.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(lib90_sieve_extprograms_plugin_la_SOURCES)
+DIST_SOURCES = $(lib90_sieve_extprograms_plugin_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+sieve_plugindir = $(dovecot_moduledir)/sieve
+sieve_plugin_LTLIBRARIES = lib90_sieve_extprograms_plugin.la
+lib90_sieve_extprograms_plugin_la_LDFLAGS = -module -avoid-version
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib-sieve \
+ -I$(top_srcdir)/src/lib-sieve/util \
+ -I$(top_srcdir)/src/lib-sieve/plugins/copy \
+ -I$(top_srcdir)/src/lib-sieve/plugins/variables \
+ $(LIBDOVECOT_INCLUDE) \
+ -DPKG_RUNDIR=\""$(rundir)"\"
+
+commands = \
+ cmd-pipe.c \
+ cmd-filter.c \
+ cmd-execute.c
+
+extensions = \
+ ext-pipe.c \
+ ext-filter.c \
+ ext-execute.c
+
+lib90_sieve_extprograms_plugin_la_SOURCES = \
+ $(commands) \
+ $(extensions) \
+ sieve-extprograms-common.c \
+ sieve-extprograms-plugin.c
+
+noinst_HEADERS = \
+ sieve-extprograms-common.h \
+ sieve-extprograms-plugin.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/sieve-extprograms/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/plugins/sieve-extprograms/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-sieve_pluginLTLIBRARIES: $(sieve_plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(sieve_plugin_LTLIBRARIES)'; test -n "$(sieve_plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sieve_plugindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sieve_plugindir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(sieve_plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(sieve_plugindir)"; \
+ }
+
+uninstall-sieve_pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sieve_plugin_LTLIBRARIES)'; test -n "$(sieve_plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(sieve_plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(sieve_plugindir)/$$f"; \
+ done
+
+clean-sieve_pluginLTLIBRARIES:
+ -test -z "$(sieve_plugin_LTLIBRARIES)" || rm -f $(sieve_plugin_LTLIBRARIES)
+ @list='$(sieve_plugin_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+lib90_sieve_extprograms_plugin.la: $(lib90_sieve_extprograms_plugin_la_OBJECTS) $(lib90_sieve_extprograms_plugin_la_DEPENDENCIES) $(EXTRA_lib90_sieve_extprograms_plugin_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(lib90_sieve_extprograms_plugin_la_LINK) -rpath $(sieve_plugindir) $(lib90_sieve_extprograms_plugin_la_OBJECTS) $(lib90_sieve_extprograms_plugin_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-execute.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-filter.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-pipe.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-execute.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-filter.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-pipe.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-extprograms-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-extprograms-plugin.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(sieve_plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-sieve_pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/cmd-execute.Plo
+ -rm -f ./$(DEPDIR)/cmd-filter.Plo
+ -rm -f ./$(DEPDIR)/cmd-pipe.Plo
+ -rm -f ./$(DEPDIR)/ext-execute.Plo
+ -rm -f ./$(DEPDIR)/ext-filter.Plo
+ -rm -f ./$(DEPDIR)/ext-pipe.Plo
+ -rm -f ./$(DEPDIR)/sieve-extprograms-common.Plo
+ -rm -f ./$(DEPDIR)/sieve-extprograms-plugin.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-sieve_pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/cmd-execute.Plo
+ -rm -f ./$(DEPDIR)/cmd-filter.Plo
+ -rm -f ./$(DEPDIR)/cmd-pipe.Plo
+ -rm -f ./$(DEPDIR)/ext-execute.Plo
+ -rm -f ./$(DEPDIR)/ext-filter.Plo
+ -rm -f ./$(DEPDIR)/ext-pipe.Plo
+ -rm -f ./$(DEPDIR)/sieve-extprograms-common.Plo
+ -rm -f ./$(DEPDIR)/sieve-extprograms-plugin.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-sieve_pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-sieve_pluginLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am \
+ install-sieve_pluginLTLIBRARIES install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am \
+ uninstall-sieve_pluginLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/plugins/sieve-extprograms/cmd-execute.c b/pigeonhole/src/plugins/sieve-extprograms/cmd-execute.c
new file mode 100644
index 0000000..79f6663
--- /dev/null
+++ b/pigeonhole/src/plugins/sieve-extprograms/cmd-execute.c
@@ -0,0 +1,488 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "buffer.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "istream.h"
+#include "ostream.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+#include "sieve-binary.h"
+#include "sieve-code.h"
+#include "sieve-message.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-result.h"
+
+#include "sieve-ext-variables.h"
+
+#include "sieve-extprograms-common.h"
+
+/* Execute command
+ *
+ * Syntax:
+ * "execute" [":input" <input-data: string> / ":pipe"]
+ * [":output" <varname: string>]
+ * <program-name: string> [<arguments: string-list>]
+ *
+ */
+
+static bool
+cmd_execute_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool
+cmd_execute_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+const struct sieve_command_def sieve_cmd_execute = {
+ .identifier = "execute",
+ .type = SCT_HYBRID,
+ .positional_args = -1, /* We check positional arguments ourselves */
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = cmd_execute_registered,
+ .validate = sieve_extprogram_command_validate,
+ .generate = cmd_execute_generate,
+};
+
+/*
+ * Tagged arguments
+ */
+
+static bool
+cmd_execute_validate_input_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool
+cmd_execute_generate_input_tag(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_argument *arg,
+ struct sieve_command *cmd);
+
+static bool
+cmd_execute_validate_output_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+static const struct sieve_argument_def execute_input_tag = {
+ .identifier = "input",
+ .validate = cmd_execute_validate_input_tag,
+ .generate = cmd_execute_generate_input_tag
+};
+
+static const struct sieve_argument_def execute_pipe_tag = {
+ .identifier = "pipe",
+ .validate = cmd_execute_validate_input_tag,
+ .generate = cmd_execute_generate_input_tag
+};
+
+static const struct sieve_argument_def execute_output_tag = {
+ .identifier = "output",
+ .validate = cmd_execute_validate_output_tag,
+};
+
+
+/*
+ * Execute operation
+ */
+
+static bool
+cmd_execute_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_execute_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def sieve_opr_execute = {
+ .mnemonic = "EXECUTE",
+ .ext_def = &sieve_ext_vnd_execute,
+ .dump = cmd_execute_operation_dump,
+ .execute = cmd_execute_operation_execute
+};
+
+/* Codes for optional operands */
+
+enum cmd_execute_optional {
+ OPT_END,
+ OPT_INPUT,
+ OPT_OUTPUT
+};
+
+/*
+ * Tag validation
+ */
+
+static bool
+cmd_execute_validate_input_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+
+ if ((bool)cmd->data) {
+ sieve_argument_validate_error(
+ valdtr, *arg,
+ "multiple :input or :pipe arguments specified for the %s %s",
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd));
+ return FALSE;
+ }
+
+ cmd->data = (void *)TRUE;
+
+ /* Skip tag */
+ *arg = sieve_ast_argument_next(*arg);
+
+ if (sieve_argument_is(tag, execute_input_tag)) {
+ /* Check syntax:
+ * :input <input-data: string>
+ */
+ if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL,
+ 0, SAAT_STRING, FALSE))
+ return FALSE;
+
+ /* Assign tag parameters */
+ tag->parameters = *arg;
+ *arg = sieve_ast_arguments_detach(*arg,1);
+ }
+
+ return TRUE;
+}
+
+static bool
+cmd_execute_validate_output_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+ struct sieve_extprograms_config *ext_config =
+ (struct sieve_extprograms_config *)cmd->ext->context;
+
+ if (ext_config == NULL || ext_config->var_ext == NULL ||
+ !sieve_ext_variables_is_active(ext_config->var_ext, valdtr)) {
+ sieve_argument_validate_error(
+ valdtr,*arg,
+ "the %s %s only allows for the specification of an "
+ ":output argument when the variables extension is active",
+ sieve_command_identifier(cmd),
+ sieve_command_type_name(cmd));
+ return FALSE;
+ }
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg, 1);
+
+ if (!sieve_variable_argument_activate(ext_config->var_ext,
+ ext_config->var_ext, valdtr,
+ cmd, *arg, TRUE))
+ return FALSE;
+
+ (*arg)->argument->id_code = tag->argument->id_code;
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+/*
+ * Command registration
+ */
+
+static bool
+cmd_execute_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &execute_input_tag, OPT_INPUT);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &execute_pipe_tag, OPT_INPUT);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &execute_output_tag, OPT_OUTPUT);
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+cmd_execute_generate_input_tag(const struct sieve_codegen_env *cgenv,
+ struct sieve_ast_argument *arg,
+ struct sieve_command *cmd)
+{
+ if (arg->parameters == NULL) {
+ sieve_opr_omitted_emit(cgenv->sblock);
+ return TRUE;
+ }
+
+ return sieve_generate_argument_parameters(cgenv, cmd, arg);
+}
+
+static bool
+cmd_execute_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &sieve_opr_execute);
+
+ /* Emit is_test flag */
+ sieve_binary_emit_byte(cgenv->sblock,
+ (uint8_t)(cmd->ast_node->type == SAT_TEST ?
+ 1 : 0));
+
+ /* Generate arguments */
+ if (!sieve_generate_arguments(cgenv, cmd, NULL))
+ return FALSE;
+
+ /* Emit a placeholder when the <arguments> argument is missing */
+ if (sieve_ast_argument_next(cmd->first_positional) == NULL)
+ sieve_opr_omitted_emit(cgenv->sblock);
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+cmd_execute_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ int opt_code = 0;
+ unsigned int is_test = 0;
+
+ /* Read is_test flag */
+ if (!sieve_binary_read_byte(denv->sblock, address, &is_test))
+ return FALSE;
+
+ sieve_code_dumpf(denv, "EXECUTE (%s)",
+ (is_test > 0 ? "test" : "command"));
+ sieve_code_descend(denv);
+
+ /* Dump optional operands */
+ for (;;) {
+ int opt;
+ bool opok = TRUE;
+
+ if ((opt = sieve_action_opr_optional_dump(denv, address,
+ &opt_code)) < 0)
+ return FALSE;
+
+ if (opt == 0)
+ break;
+
+ switch (opt_code) {
+ case OPT_INPUT:
+ opok = sieve_opr_string_dump_ex(denv, address,
+ "input", "PIPE");
+ break;
+ case OPT_OUTPUT:
+ opok = sieve_opr_string_dump(denv, address, "output");
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (!opok)
+ return FALSE;
+ }
+
+ if (!sieve_opr_string_dump(denv, address, "program-name"))
+ return FALSE;
+
+ return sieve_opr_stringlist_dump_ex(denv, address, "arguments", "");
+}
+
+/*
+ * Code execution
+ */
+
+static int
+cmd_execute_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ struct sieve_side_effects_list *slist = NULL;
+ int opt_code = 0;
+ unsigned int is_test = 0;
+ struct sieve_stringlist *args_list = NULL;
+ string_t *pname = NULL, *input = NULL;
+ struct sieve_variable_storage *var_storage = NULL;
+ unsigned int var_index;
+ bool have_input = FALSE;
+ const char *program_name = NULL;
+ const char *const *args = NULL;
+ enum sieve_error error = SIEVE_ERROR_NONE;
+ buffer_t *outbuf = NULL;
+ struct sieve_extprogram *sprog = NULL;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* The is_test flag */
+ if (!sieve_binary_read_byte(renv->sblock, address, &is_test)) {
+ sieve_runtime_trace_error(renv, "invalid is_test flag");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ /* Optional operands */
+
+ for (;;) {
+ int opt;
+
+ if ((opt = sieve_action_opr_optional_read(
+ renv, address, &opt_code, &ret, &slist)) < 0)
+ return ret;
+
+ if (opt == 0)
+ break;
+
+ switch (opt_code) {
+ case OPT_INPUT:
+ ret = sieve_opr_string_read_ex(renv, address, "input",
+ TRUE, &input, NULL);
+ have_input = TRUE;
+ break;
+ case OPT_OUTPUT:
+ ret = sieve_variable_operand_read(
+ renv, address, "output", &var_storage,
+ &var_index);
+ break;
+ default:
+ sieve_runtime_trace_error(
+ renv, "unknown optional operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if (ret <= 0)
+ return ret;
+ }
+
+ /* Fixed operands */
+
+ if ((ret = sieve_extprogram_command_read_operands(
+ renv, address, &pname, &args_list)) <= 0)
+ return ret;
+
+ program_name = str_c(pname);
+ if (args_list != NULL &&
+ sieve_stringlist_read_all(args_list, pool_datastack_create(),
+ &args) < 0) {
+ sieve_runtime_trace_error(renv, "failed to read args operand");
+ return args_list->exec_status;
+ }
+
+ /*
+ * Perform operation
+ */
+
+ /* Trace */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "execute action");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS,
+ "execute program `%s'",
+ str_sanitize(program_name, 128));
+
+ sprog = sieve_extprogram_create(this_ext, eenv->scriptenv,
+ eenv->msgdata, "execute",
+ program_name, args, &error);
+ if (sprog != NULL) {
+ if (var_storage != NULL) {
+ // FIXME: limit output size
+ struct ostream *outdata;
+
+ outbuf = buffer_create_dynamic(default_pool, 1024);
+ outdata = o_stream_create_buffer(outbuf);
+ sieve_extprogram_set_output(sprog, outdata);
+ o_stream_unref(&outdata);
+ }
+
+ if (input == NULL && have_input) {
+ struct mail *mail = sieve_message_get_mail(renv->msgctx);
+
+ if (sieve_extprogram_set_input_mail(sprog, mail) < 0) {
+ sieve_extprogram_destroy(&sprog);
+ if (outbuf != NULL)
+ buffer_free(&outbuf);
+ return sieve_runtime_mail_error(
+ renv, mail, "execute action: "
+ "failed to read input message");
+ }
+ ret = 1;
+ } else if (input != NULL) {
+ struct istream *indata =
+ i_stream_create_from_data(str_data(input),
+ str_len(input));
+ sieve_extprogram_set_input(sprog, indata);
+ i_stream_unref(&indata);
+ ret = 1;
+ }
+
+ if (ret >= 0)
+ ret = sieve_extprogram_run(sprog);
+ sieve_extprogram_destroy(&sprog);
+ } else {
+ ret = -1;
+ }
+
+ if (ret > 0) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS,
+ "executed program successfully");
+
+ if (var_storage != NULL) {
+ string_t *var;
+
+ if (sieve_variable_get_modifiable(var_storage,
+ var_index, &var)) {
+ str_truncate(var, 0);
+ str_append_str(var, outbuf);
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS,
+ "assigned output variable");
+ } // FIXME: handle failure
+ }
+
+ } else if (ret < 0) {
+ if (error == SIEVE_ERROR_NOT_FOUND) {
+ sieve_runtime_error(
+ renv, NULL,
+ "execute action: program `%s' not found",
+ str_sanitize(program_name, 80));
+ } else {
+ sieve_extprogram_exec_error(
+ renv->ehandler,
+ sieve_runtime_get_full_command_location(renv),
+ "execute action: failed to execute to program `%s'",
+ str_sanitize(program_name, 80));
+ }
+ } else {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS,
+ "execute action: "
+ "program indicated false result");
+ }
+
+ if (outbuf != NULL)
+ buffer_free(&outbuf);
+
+ if (is_test > 0) {
+ sieve_interpreter_set_test_result(renv->interp, (ret > 0));
+ return SIEVE_EXEC_OK;
+ }
+ return (ret >= 0 ? SIEVE_EXEC_OK : SIEVE_EXEC_FAILURE);
+}
diff --git a/pigeonhole/src/plugins/sieve-extprograms/cmd-filter.c b/pigeonhole/src/plugins/sieve-extprograms/cmd-filter.c
new file mode 100644
index 0000000..7118ff1
--- /dev/null
+++ b/pigeonhole/src/plugins/sieve-extprograms/cmd-filter.c
@@ -0,0 +1,254 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "buffer.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "istream.h"
+#include "ostream.h"
+#include "safe-mkstemp.h"
+#include "mail-user.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+#include "sieve-binary.h"
+#include "sieve-code.h"
+#include "sieve-message.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-result.h"
+
+#include "sieve-ext-variables.h"
+
+#include "sieve-extprograms-common.h"
+
+/* Filter command
+ *
+ * Syntax:
+ * "filter" <program-name: string> [<arguments: string-list>]
+ *
+ */
+
+static bool
+cmd_filter_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+const struct sieve_command_def sieve_cmd_filter = {
+ .identifier = "filter",
+ .type = SCT_HYBRID,
+ .positional_args = -1, /* We check positional arguments ourselves */
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = sieve_extprogram_command_validate,
+ .generate = cmd_filter_generate
+};
+
+/*
+ * Filter operation
+ */
+
+static bool
+cmd_filter_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_filter_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def sieve_opr_filter = {
+ .mnemonic = "FILTER",
+ .ext_def = &sieve_ext_vnd_filter,
+ .dump = cmd_filter_operation_dump,
+ .execute = cmd_filter_operation_execute
+};
+
+/*
+ * Code generation
+ */
+
+static bool
+cmd_filter_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &sieve_opr_filter);
+
+ /* Emit is_test flag */
+ sieve_binary_emit_byte(cgenv->sblock,
+ (uint8_t)(cmd->ast_node->type == SAT_TEST ?
+ 1 : 0));
+
+ /* Generate arguments */
+ if (!sieve_generate_arguments(cgenv, cmd, NULL))
+ return FALSE;
+
+ /* Emit a placeholder when the <arguments> argument is missing */
+ if (sieve_ast_argument_next(cmd->first_positional) == NULL)
+ sieve_opr_omitted_emit(cgenv->sblock);
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+cmd_filter_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ unsigned int is_test = 0;
+
+ /* Read is_test flag */
+ if (!sieve_binary_read_byte(denv->sblock, address, &is_test))
+ return FALSE;
+
+ sieve_code_dumpf(denv, "FILTER (%s)",
+ (is_test > 0 ? "test" : "command"));
+ sieve_code_descend(denv);
+
+ /* Dump optional operands */
+ if (sieve_action_opr_optional_dump(denv, address, NULL) != 0)
+ return FALSE;
+
+ if (!sieve_opr_string_dump(denv, address, "program-name"))
+ return FALSE;
+
+ return sieve_opr_stringlist_dump_ex(denv, address, "arguments", "");
+}
+
+/*
+ * Code execution
+ */
+
+static int
+cmd_filter_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ unsigned int is_test = 0;
+ struct sieve_stringlist *args_list = NULL;
+ enum sieve_error error = SIEVE_ERROR_NONE;
+ string_t *pname = NULL;
+ const char *program_name = NULL;
+ const char *const *args = NULL;
+ struct istream *newmsg = NULL;
+ struct sieve_extprogram *sprog;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* The is_test flag */
+
+ if (!sieve_binary_read_byte(renv->sblock, address, &is_test)) {
+ sieve_runtime_trace_error(renv, "invalid is_test flag");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ /* Optional operands */
+
+ if (sieve_action_opr_optional_read(renv, address, NULL,
+ &ret, NULL) != 0)
+ return ret;
+
+ /* Fixed operands */
+
+ if ((ret = sieve_extprogram_command_read_operands(renv, address, &pname,
+ &args_list)) <= 0)
+ return ret;
+
+ program_name = str_c(pname);
+ if (args_list != NULL &&
+ sieve_stringlist_read_all(args_list, pool_datastack_create(),
+ &args) < 0) {
+ sieve_runtime_trace_error(renv, "failed to read args operand");
+ return args_list->exec_status;
+ }
+
+ /*
+ * Perform operation
+ */
+
+ /* Trace */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "filter action");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS,
+ "execute program `%s'", str_sanitize(program_name, 128));
+
+ sprog = sieve_extprogram_create(this_ext, eenv->scriptenv,
+ eenv->msgdata, "filter",
+ program_name, args, &error);
+ if (sprog != NULL) {
+ struct mail *mail = sieve_message_get_mail(renv->msgctx);
+
+ if (sieve_extprogram_set_input_mail(sprog, mail) < 0) {
+ sieve_extprogram_destroy(&sprog);
+ return sieve_runtime_mail_error(
+ renv, mail,
+ "filter action: failed to read input message");
+ }
+ sieve_extprogram_set_output_seekable(sprog);
+ ret = sieve_extprogram_run(sprog);
+ } else {
+ ret = -1;
+ }
+
+ if (ret > 0)
+ newmsg = sieve_extprogram_get_output_seekable(sprog);
+ if (sprog != NULL)
+ sieve_extprogram_destroy(&sprog);
+
+ if (ret > 0 && newmsg != NULL) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS,
+ "executed program successfully");
+
+ i_stream_set_name(newmsg, t_strdup_printf("filter %s output",
+ program_name));
+ newmsg->blocking = TRUE;
+ if ((ret = sieve_message_substitute(renv->msgctx,
+ newmsg)) >= 0) {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS,
+ "changed message");
+ } else {
+ sieve_runtime_critical(renv, NULL, "filter action",
+ "filter action: "
+ "failed to substitute message");
+ }
+
+ i_stream_unref(&newmsg);
+ } else if (ret < 0) {
+ if (error == SIEVE_ERROR_NOT_FOUND) {
+ sieve_runtime_error(renv, NULL, "filter action: "
+ "program `%s' not found",
+ str_sanitize(program_name, 80));
+ } else {
+ sieve_extprogram_exec_error(
+ renv->ehandler,
+ sieve_runtime_get_full_command_location(renv),
+ "filter action: "
+ "failed to execute to program `%s'",
+ str_sanitize(program_name, 80));
+ }
+
+ } else {
+ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "filter action: "
+ "program indicated false result");
+ }
+
+ if (is_test > 0) {
+ sieve_interpreter_set_test_result(renv->interp, (ret > 0));
+
+ return SIEVE_EXEC_OK;
+ }
+
+ return (ret >= 0 ? SIEVE_EXEC_OK : SIEVE_EXEC_FAILURE);
+}
diff --git a/pigeonhole/src/plugins/sieve-extprograms/cmd-pipe.c b/pigeonhole/src/plugins/sieve-extprograms/cmd-pipe.c
new file mode 100644
index 0000000..f5a5c34
--- /dev/null
+++ b/pigeonhole/src/plugins/sieve-extprograms/cmd-pipe.c
@@ -0,0 +1,457 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "str-sanitize.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-message.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-result.h"
+
+#include "sieve-extprograms-common.h"
+
+/* Pipe command
+ *
+ * Syntax:
+ * pipe [":copy"] [":try"] <program-name: string> [<arguments: string-list>]
+ *
+ */
+
+static bool
+cmd_pipe_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool
+cmd_pipe_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+const struct sieve_command_def sieve_cmd_pipe = {
+ .identifier = "pipe",
+ .type = SCT_COMMAND,
+ .positional_args = -1, /* We check positional arguments ourselves */
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = cmd_pipe_registered,
+ .validate = sieve_extprogram_command_validate,
+ .generate = cmd_pipe_generate,
+};
+
+/*
+ * Tagged arguments
+ */
+
+static const struct sieve_argument_def pipe_try_tag = {
+ .identifier = "try",
+};
+
+/*
+ * Pipe operation
+ */
+
+static bool
+cmd_pipe_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_pipe_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def sieve_opr_pipe = {
+ .mnemonic = "PIPE",
+ .ext_def = &sieve_ext_vnd_pipe,
+ .dump = cmd_pipe_operation_dump,
+ .execute = cmd_pipe_operation_execute,
+};
+
+/* Codes for optional operands */
+
+enum cmd_pipe_optional {
+ OPT_END,
+ OPT_TRY,
+};
+
+/*
+ * Pipe action
+ */
+
+/* Forward declarations */
+
+static int
+act_pipe_check_duplicate(const struct sieve_runtime_env *renv,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other);
+static void
+act_pipe_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv,
+ bool *keep);
+static int
+act_pipe_start(const struct sieve_action_exec_env *aenv, void **tr_context);
+static int
+act_pipe_execute(const struct sieve_action_exec_env *aenv,
+ void *tr_context, bool *keep);
+static int
+act_pipe_commit(const struct sieve_action_exec_env *aenv,
+ void *tr_context);
+static void
+act_pipe_rollback(const struct sieve_action_exec_env *aenv,
+ void *tr_context, bool success);
+
+/* Action object */
+
+const struct sieve_action_def act_pipe = {
+ .name = "pipe",
+ .flags = SIEVE_ACTFLAG_TRIES_DELIVER,
+ .check_duplicate = act_pipe_check_duplicate,
+ .print = act_pipe_print,
+ .start = act_pipe_start,
+ .execute = act_pipe_execute,
+ .commit = act_pipe_commit,
+ .rollback = act_pipe_rollback,
+};
+
+/* Action context information */
+
+struct ext_pipe_action {
+ const char *program_name;
+ const char * const *args;
+ bool try;
+};
+
+/*
+ * Command registration
+ */
+
+static bool
+cmd_pipe_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &pipe_try_tag, OPT_TRY);
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+cmd_pipe_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &sieve_opr_pipe);
+
+ /* Generate arguments */
+ if (!sieve_generate_arguments(cgenv, cmd, NULL))
+ return FALSE;
+
+ /* Emit a placeholder when the <arguments> argument is missing */
+ if (sieve_ast_argument_next(cmd->first_positional) == NULL)
+ sieve_opr_omitted_emit(cgenv->sblock);
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+cmd_pipe_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "PIPE");
+ sieve_code_descend(denv);
+
+ /* Dump optional operands */
+ for (;;) {
+ int opt;
+
+ if ((opt = sieve_action_opr_optional_dump(denv, address,
+ &opt_code)) < 0)
+ return FALSE;
+
+ if (opt == 0)
+ break;
+
+ switch (opt_code) {
+ case OPT_TRY:
+ sieve_code_dumpf(denv, "try");
+ break;
+ default:
+ return FALSE;
+ }
+ }
+
+ if (!sieve_opr_string_dump(denv, address, "program-name"))
+ return FALSE;
+
+ return sieve_opr_stringlist_dump_ex(denv, address, "arguments", "");
+}
+
+/*
+ * Code execution
+ */
+
+static int
+cmd_pipe_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ const struct sieve_extension *this_ext = renv->oprtn->ext;
+ struct sieve_side_effects_list *slist = NULL;
+ struct ext_pipe_action *act;
+ pool_t pool;
+ int opt_code = 0;
+ struct sieve_stringlist *args_list = NULL;
+ string_t *pname = NULL;
+ bool try = FALSE;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Optional operands */
+
+ for (;;) {
+ int opt;
+
+ if ((opt = sieve_action_opr_optional_read(renv, address,
+ &opt_code, &ret,
+ &slist)) < 0)
+ return ret;
+
+ if (opt == 0)
+ break;
+
+ switch (opt_code) {
+ case OPT_TRY:
+ try = TRUE;
+ break;
+ default:
+ sieve_runtime_trace_error(
+ renv, "unknown optional operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ }
+
+ /* Fixed operands */
+
+ if ((ret = sieve_extprogram_command_read_operands(renv, address, &pname,
+ &args_list)) <= 0)
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ /* Trace */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "pipe action");
+
+ /* Compose action */
+
+ pool = sieve_result_pool(renv->result);
+ act = p_new(pool, struct ext_pipe_action, 1);
+
+ if (args_list != NULL &&
+ sieve_stringlist_read_all(args_list, pool, &act->args) < 0) {
+ sieve_runtime_trace_error(renv, "failed to read args operand");
+ return args_list->exec_status;
+ }
+
+ act->program_name = p_strdup(pool, str_c(pname));
+ act->try = try;
+
+ if (sieve_result_add_action(renv, this_ext, "pipe", &act_pipe, slist,
+ (void *)act, 0, TRUE) < 0)
+ return SIEVE_EXEC_FAILURE;
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Action
+ */
+
+/* Runtime verification */
+
+static int
+act_pipe_check_duplicate(const struct sieve_runtime_env *renv ATTR_UNUSED,
+ const struct sieve_action *act,
+ const struct sieve_action *act_other)
+{
+ struct ext_pipe_action *new_act, *old_act;
+
+ if (act->context == NULL || act_other->context == NULL)
+ return 0;
+
+ new_act = (struct ext_pipe_action *) act->context;
+ old_act = (struct ext_pipe_action *) act_other->context;
+
+ if (strcmp(new_act->program_name, old_act->program_name) == 0) {
+ sieve_runtime_error(renv, act->location,
+ "duplicate pipe \"%s\" action not allowed "
+ "(previously triggered one was here: %s)",
+ new_act->program_name, act_other->location);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Result printing */
+
+static void
+act_pipe_print(const struct sieve_action *action,
+ const struct sieve_result_print_env *rpenv,
+ bool *keep ATTR_UNUSED)
+{
+ const struct ext_pipe_action *act =
+ (const struct ext_pipe_action *)action->context;
+
+ sieve_result_action_printf(
+ rpenv, "pipe message to external program '%s':",
+ act->program_name);
+
+ /* Print main method parameters */
+
+ sieve_result_printf(
+ rpenv, " => try : %s\n",
+ (act->try ? "yes" : "no"));
+
+ /* FIXME: print args */
+
+ /* Finish output with an empty line */
+ sieve_result_printf(rpenv, "\n");
+}
+
+/* Result execution */
+
+struct act_pipe_transaction {
+ struct sieve_extprogram *sprog;
+};
+
+static int
+act_pipe_start(const struct sieve_action_exec_env *aenv, void **tr_context)
+{
+ struct act_pipe_transaction *trans;
+ pool_t pool = sieve_result_pool(aenv->result);
+
+ /* Create transaction context */
+ trans = p_new(pool, struct act_pipe_transaction, 1);
+ *tr_context = (void *)trans;
+
+ return SIEVE_EXEC_OK;
+}
+
+static int
+act_pipe_execute(const struct sieve_action_exec_env *aenv,
+ void *tr_context, bool *keep)
+{
+ const struct sieve_action *action = aenv->action;
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ const struct ext_pipe_action *act =
+ (const struct ext_pipe_action *)action->context;
+ struct act_pipe_transaction *trans = tr_context;
+ struct mail *mail = (action->mail != NULL ?
+ action->mail :
+ sieve_message_get_mail(aenv->msgctx));
+ enum sieve_error error = SIEVE_ERROR_NONE;
+
+ trans->sprog = sieve_extprogram_create(action->ext, eenv->scriptenv,
+ eenv->msgdata, "pipe",
+ act->program_name, act->args,
+ &error);
+ if (trans->sprog != NULL) {
+ if (sieve_extprogram_set_input_mail(trans->sprog, mail) < 0) {
+ sieve_extprogram_destroy(&trans->sprog);
+ return sieve_result_mail_error(
+ aenv, mail, "failed to read input message");
+ }
+ }
+
+ *keep = FALSE;
+ return SIEVE_EXEC_OK;
+}
+
+static int
+act_pipe_commit(const struct sieve_action_exec_env *aenv,
+ void *tr_context ATTR_UNUSED)
+{
+ const struct sieve_action *action = aenv->action;
+ const struct sieve_execute_env *eenv = aenv->exec_env;
+ const struct ext_pipe_action *act =
+ (const struct ext_pipe_action *)action->context;
+ struct act_pipe_transaction *trans = tr_context;
+ enum sieve_error error = SIEVE_ERROR_NONE;
+ int ret;
+
+ if (trans->sprog != NULL) {
+ ret = sieve_extprogram_run(trans->sprog);
+ sieve_extprogram_destroy(&trans->sprog);
+ } else {
+ ret = -1;
+ }
+
+ if (ret > 0) {
+ struct event_passthrough *e =
+ sieve_action_create_finish_event(aenv)->
+ add_str("pipe_program",
+ str_sanitize(act->program_name, 256));
+
+ sieve_result_event_log(aenv, e->event(),
+ "piped message to program `%s'",
+ str_sanitize(act->program_name, 128));
+
+ /* Indicate that message was successfully 'forwarded' */
+ eenv->exec_status->message_forwarded = TRUE;
+ } else {
+ if (ret < 0) {
+ if (error == SIEVE_ERROR_NOT_FOUND) {
+ sieve_result_error(
+ aenv,
+ "failed to pipe message to program: "
+ "program `%s' not found",
+ str_sanitize(act->program_name, 80));
+ } else {
+ sieve_extprogram_exec_error(
+ aenv->ehandler, NULL,
+ "failed to pipe message to program `%s'",
+ str_sanitize(act->program_name, 80));
+ }
+ } else {
+ sieve_extprogram_exec_error(
+ aenv->ehandler, NULL,
+ "failed to execute to program `%s'",
+ str_sanitize(act->program_name, 80));
+ }
+
+ if (act->try)
+ return SIEVE_EXEC_OK;
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+static void
+act_pipe_rollback(const struct sieve_action_exec_env *aenv ATTR_UNUSED,
+ void *tr_context, bool success ATTR_UNUSED)
+{
+ struct act_pipe_transaction *trans = tr_context;
+
+ if (trans->sprog != NULL)
+ sieve_extprogram_destroy(&trans->sprog);
+}
diff --git a/pigeonhole/src/plugins/sieve-extprograms/ext-execute.c b/pigeonhole/src/plugins/sieve-extprograms/ext-execute.c
new file mode 100644
index 0000000..055ee88
--- /dev/null
+++ b/pigeonhole/src/plugins/sieve-extprograms/ext-execute.c
@@ -0,0 +1,80 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension vnd.dovecot.execute
+ * -----------------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: vendor-defined; spec-bosch-sieve-extprograms
+ * Implementation: full
+ * Status: experimental
+ *
+ */
+
+#include "lib.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-binary.h"
+
+#include "sieve-validator.h"
+#include "sieve-interpreter.h"
+
+#include "sieve-ext-copy.h"
+
+#include "sieve-extprograms-common.h"
+
+/*
+ * Extension
+ */
+
+static bool ext_execute_load(const struct sieve_extension *ext, void **context);
+static void ext_execute_unload(const struct sieve_extension *ext);
+static bool ext_execute_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def sieve_ext_vnd_execute = {
+ .name = "vnd.dovecot.execute",
+ .load = ext_execute_load,
+ .unload = ext_execute_unload,
+ .validator_load = ext_execute_validator_load,
+ SIEVE_EXT_DEFINE_OPERATION(sieve_opr_execute)
+};
+
+/*
+ * Context
+ */
+
+static bool ext_execute_load(const struct sieve_extension *ext, void **context)
+{
+ if ( *context != NULL ) {
+ ext_execute_unload(ext);
+ *context = NULL;
+ }
+
+ *context = (void *)sieve_extprograms_config_init(ext);
+ return TRUE;
+}
+
+static void ext_execute_unload(const struct sieve_extension *ext)
+{
+ struct sieve_extprograms_config *ext_config =
+ (struct sieve_extprograms_config *)ext->context;
+
+ if ( ext_config == NULL ) return;
+
+ sieve_extprograms_config_deinit(&ext_config);
+}
+
+/*
+ * Validation
+ */
+
+static bool ext_execute_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Register commands */
+ sieve_validator_register_command(valdtr, ext, &sieve_cmd_execute);
+
+ return TRUE;
+}
diff --git a/pigeonhole/src/plugins/sieve-extprograms/ext-filter.c b/pigeonhole/src/plugins/sieve-extprograms/ext-filter.c
new file mode 100644
index 0000000..af1f8f1
--- /dev/null
+++ b/pigeonhole/src/plugins/sieve-extprograms/ext-filter.c
@@ -0,0 +1,80 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension vnd.dovecot.filter
+ * -----------------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: vendor-defined; spec-bosch-sieve-extprograms
+ * Implementation: full
+ * Status: experimental
+ *
+ */
+
+#include "lib.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-binary.h"
+
+#include "sieve-validator.h"
+#include "sieve-interpreter.h"
+
+#include "sieve-ext-copy.h"
+
+#include "sieve-extprograms-common.h"
+
+/*
+ * Extension
+ */
+
+static bool ext_filter_load(const struct sieve_extension *ext, void **context);
+static void ext_filter_unload(const struct sieve_extension *ext);
+static bool ext_filter_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def sieve_ext_vnd_filter = {
+ .name = "vnd.dovecot.filter",
+ .load = ext_filter_load,
+ .unload = ext_filter_unload,
+ .validator_load = ext_filter_validator_load,
+ SIEVE_EXT_DEFINE_OPERATION(sieve_opr_filter),
+};
+
+/*
+ * Context
+ */
+
+static bool ext_filter_load(const struct sieve_extension *ext, void **context)
+{
+ if ( *context != NULL ) {
+ ext_filter_unload(ext);
+ *context = NULL;
+ }
+
+ *context = (void *)sieve_extprograms_config_init(ext);
+ return TRUE;
+}
+
+static void ext_filter_unload(const struct sieve_extension *ext)
+{
+ struct sieve_extprograms_config *ext_config =
+ (struct sieve_extprograms_config *)ext->context;
+
+ if ( ext_config == NULL ) return;
+
+ sieve_extprograms_config_deinit(&ext_config);
+}
+
+/*
+ * Validation
+ */
+
+static bool ext_filter_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Register commands */
+ sieve_validator_register_command(valdtr, ext, &sieve_cmd_filter);
+
+ return TRUE;
+}
diff --git a/pigeonhole/src/plugins/sieve-extprograms/ext-pipe.c b/pigeonhole/src/plugins/sieve-extprograms/ext-pipe.c
new file mode 100644
index 0000000..5da7d36
--- /dev/null
+++ b/pigeonhole/src/plugins/sieve-extprograms/ext-pipe.c
@@ -0,0 +1,114 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension vnd.dovecot.pipe
+ * -----------------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: vendor-define; spec-bosch-sieve-extprograms
+ * Implementation: full
+ * Status: experimental
+ *
+ */
+
+#include "lib.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-binary.h"
+
+#include "sieve-validator.h"
+#include "sieve-interpreter.h"
+
+#include "sieve-ext-copy.h"
+
+#include "sieve-extprograms-common.h"
+
+/*
+ * Extension
+ */
+
+static bool ext_pipe_load(const struct sieve_extension *ext, void **context);
+static void ext_pipe_unload(const struct sieve_extension *ext);
+static bool ext_pipe_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+
+const struct sieve_extension_def sieve_ext_vnd_pipe = {
+ .name = "vnd.dovecot.pipe",
+ .load = ext_pipe_load,
+ .unload = ext_pipe_unload,
+ .validator_load = ext_pipe_validator_load,
+ SIEVE_EXT_DEFINE_OPERATION(sieve_opr_pipe),
+};
+
+/*
+ * Context
+ */
+
+static bool ext_pipe_load(const struct sieve_extension *ext, void **context)
+{
+ if ( *context != NULL ) {
+ ext_pipe_unload(ext);
+ *context = NULL;
+ }
+
+ *context = (void *)sieve_extprograms_config_init(ext);
+ return TRUE;
+}
+
+static void ext_pipe_unload(const struct sieve_extension *ext)
+{
+ struct sieve_extprograms_config *ext_config =
+ (struct sieve_extprograms_config *)ext->context;
+
+ if ( ext_config == NULL ) return;
+
+ sieve_extprograms_config_deinit(&ext_config);
+}
+
+/*
+ * Validation
+ */
+
+static bool ext_pipe_validator_validate
+ (const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context,
+ struct sieve_ast_argument *require_arg,
+ bool required);
+
+static const struct sieve_validator_extension pipe_validator_extension = {
+ .ext = &sieve_ext_vnd_pipe,
+ .validate = ext_pipe_validator_validate
+};
+
+static bool ext_pipe_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ /* Register commands */
+ sieve_validator_register_command(valdtr, ext, &sieve_cmd_pipe);
+
+ /* Register extension to validator */
+ sieve_validator_extension_register
+ (valdtr, ext, &pipe_validator_extension, NULL);
+
+ return TRUE;
+}
+
+static bool ext_pipe_validator_validate
+(const struct sieve_extension *ext,
+ struct sieve_validator *valdtr, void *context ATTR_UNUSED,
+ struct sieve_ast_argument *require_arg ATTR_UNUSED,
+ bool required ATTR_UNUSED)
+{
+ struct sieve_extprograms_config *ext_config =
+ (struct sieve_extprograms_config *) ext->context;
+
+ if ( ext_config != NULL && ext_config->copy_ext != NULL ) {
+ /* Register :copy command tag */
+ sieve_ext_copy_register_tag(valdtr,
+ ext_config->copy_ext, sieve_cmd_pipe.identifier);
+ }
+ return TRUE;
+}
+
+
diff --git a/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-common.c b/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-common.c
new file mode 100644
index 0000000..3c9ff23
--- /dev/null
+++ b/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-common.c
@@ -0,0 +1,648 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "lib-signals.h"
+#include "str.h"
+#include "strfuncs.h"
+#include "str-sanitize.h"
+#include "unichar.h"
+#include "array.h"
+#include "eacces-error.h"
+#include "smtp-params.h"
+#include "istream.h"
+#include "istream-crlf.h"
+#include "istream-header-filter.h"
+#include "ostream.h"
+#include "mail-user.h"
+#include "mail-storage.h"
+
+#include "program-client.h"
+
+#include "sieve-common.h"
+#include "sieve-settings.h"
+#include "sieve-error.h"
+#include "sieve-extensions.h"
+#include "sieve-ast.h"
+#include "sieve-commands.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-runtime.h"
+#include "sieve-interpreter.h"
+
+#include "sieve-ext-copy.h"
+#include "sieve-ext-variables.h"
+
+#include "sieve-extprograms-common.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+
+/*
+ * Limits
+ */
+
+#define SIEVE_EXTPROGRAMS_MAX_PROGRAM_NAME_LEN 128
+#define SIEVE_EXTPROGRAMS_MAX_PROGRAM_ARG_LEN 1024
+
+#define SIEVE_EXTPROGRAMS_DEFAULT_EXEC_TIMEOUT_SECS 10
+#define SIEVE_EXTPROGRAMS_CONNECT_TIMEOUT_MSECS 5
+
+/*
+ * Pipe Extension Context
+ */
+
+struct sieve_extprograms_config *sieve_extprograms_config_init
+(const struct sieve_extension *ext)
+{
+ struct sieve_instance *svinst = ext->svinst;
+ struct sieve_extprograms_config *ext_config;
+ const char *extname = sieve_extension_name(ext);
+ const char *bin_dir, *socket_dir, *input_eol;
+ sieve_number_t execute_timeout;
+
+ extname = strrchr(extname, '.');
+ i_assert(extname != NULL);
+ extname++;
+
+ bin_dir = sieve_setting_get
+ (svinst, t_strdup_printf("sieve_%s_bin_dir", extname));
+ socket_dir = sieve_setting_get
+ (svinst, t_strdup_printf("sieve_%s_socket_dir", extname));
+ input_eol = sieve_setting_get
+ (svinst, t_strdup_printf("sieve_%s_input_eol", extname));
+
+ ext_config = i_new(struct sieve_extprograms_config, 1);
+ ext_config->execute_timeout =
+ SIEVE_EXTPROGRAMS_DEFAULT_EXEC_TIMEOUT_SECS;
+
+ if ( bin_dir == NULL && socket_dir == NULL ) {
+ e_debug(svinst->event, "%s extension: "
+ "no bin or socket directory specified; extension is unconfigured "
+ "(both sieve_%s_bin_dir and sieve_%s_socket_dir are not set)",
+ sieve_extension_name(ext), extname, extname);
+ } else {
+ ext_config->bin_dir = i_strdup(bin_dir);
+ ext_config->socket_dir = i_strdup(socket_dir);
+
+ if (sieve_setting_get_duration_value
+ (svinst, t_strdup_printf("sieve_%s_exec_timeout", extname),
+ &execute_timeout)) {
+ ext_config->execute_timeout = execute_timeout;
+ }
+
+ ext_config->default_input_eol = SIEVE_EXTPROGRAMS_EOL_CRLF;
+ if (input_eol != NULL && strcasecmp(input_eol, "lf") == 0)
+ ext_config->default_input_eol = SIEVE_EXTPROGRAMS_EOL_LF;
+ }
+
+ if ( sieve_extension_is(ext, sieve_ext_vnd_pipe) )
+ ext_config->copy_ext = sieve_ext_copy_get_extension(ext->svinst);
+ if ( sieve_extension_is(ext, sieve_ext_vnd_execute) )
+ ext_config->var_ext = sieve_ext_variables_get_extension(ext->svinst);
+ return ext_config;
+}
+
+void sieve_extprograms_config_deinit
+(struct sieve_extprograms_config **ext_config)
+{
+ if ( *ext_config == NULL )
+ return;
+
+ i_free((*ext_config)->bin_dir);
+ i_free((*ext_config)->socket_dir);
+ i_free((*ext_config));
+
+ *ext_config = NULL;
+}
+
+/*
+ * Program name and arguments
+ */
+
+bool sieve_extprogram_name_is_valid(string_t *name)
+{
+ ARRAY_TYPE(unichars) uni_name;
+ unsigned int count, i;
+ const unichar_t *name_chars;
+ size_t namelen = str_len(name);
+
+ /* Check minimum length */
+ if ( namelen == 0 )
+ return FALSE;
+
+ /* Check worst-case maximum length */
+ if ( namelen > SIEVE_EXTPROGRAMS_MAX_PROGRAM_NAME_LEN * 4 )
+ return FALSE;
+
+ /* Intialize array for unicode characters */
+ t_array_init(&uni_name, namelen * 4);
+
+ /* Convert UTF-8 to UCS4/UTF-32 */
+ if ( uni_utf8_to_ucs4_n(str_data(name), namelen, &uni_name) < 0 )
+ return FALSE;
+ name_chars = array_get(&uni_name, &count);
+
+ /* Check true maximum length */
+ if ( count > SIEVE_EXTPROGRAMS_MAX_PROGRAM_NAME_LEN )
+ return FALSE;
+
+ /* Scan name for invalid characters
+ * FIXME: compliance with Net-Unicode Definition (Section 2 of
+ * RFC 5198) is not checked fully and no normalization
+ * is performed.
+ */
+ for ( i = 0; i < count; i++ ) {
+
+ /* 0000-001F; [CONTROL CHARACTERS] */
+ if ( name_chars[i] <= 0x001f )
+ return FALSE;
+
+ /* 002F; SLASH */
+ if ( name_chars[i] == 0x002f )
+ return FALSE;
+
+ /* 007F; DELETE */
+ if ( name_chars[i] == 0x007f )
+ return FALSE;
+
+ /* 0080-009F; [CONTROL CHARACTERS] */
+ if ( name_chars[i] >= 0x0080 && name_chars[i] <= 0x009f )
+ return FALSE;
+
+ /* 00FF */
+ if ( name_chars[i] == 0x00ff )
+ return FALSE;
+
+ /* 2028; LINE SEPARATOR */
+ /* 2029; PARAGRAPH SEPARATOR */
+ if ( name_chars[i] == 0x2028 || name_chars[i] == 0x2029 )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+bool sieve_extprogram_arg_is_valid(string_t *arg)
+{
+ const unsigned char *chars;
+ unsigned int i;
+
+ /* Check maximum length */
+ if ( str_len(arg) > SIEVE_EXTPROGRAMS_MAX_PROGRAM_ARG_LEN )
+ return FALSE;
+
+ /* Check invalid characters */
+ chars = str_data(arg);
+ for ( i = 0; i < str_len(arg); i++ ) {
+ /* 0010; CR */
+ if ( chars[i] == 0x0D )
+ return FALSE;
+
+ /* 0010; LF */
+ if ( chars[i] == 0x0A )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Command validation
+ */
+
+struct _arg_validate_context {
+ struct sieve_validator *valdtr;
+ struct sieve_command *cmd;
+};
+
+static int _arg_validate
+(void *context, struct sieve_ast_argument *item)
+{
+ struct _arg_validate_context *actx = (struct _arg_validate_context *) context;
+
+ if ( sieve_argument_is_string_literal(item) ) {
+ string_t *arg = sieve_ast_argument_str(item);
+
+ if ( !sieve_extprogram_arg_is_valid(arg) ) {
+ sieve_argument_validate_error(actx->valdtr, item,
+ "%s %s: specified external program argument `%s' is invalid",
+ sieve_command_identifier(actx->cmd), sieve_command_type_name(actx->cmd),
+ str_sanitize(str_c(arg), 128));
+
+ return -1;
+ }
+ }
+
+ return 1;
+}
+
+bool sieve_extprogram_command_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+ struct sieve_ast_argument *stritem;
+ struct _arg_validate_context actx;
+ string_t *program_name;
+
+ if ( arg == NULL ) {
+ sieve_command_validate_error(valdtr, cmd,
+ "the %s %s expects at least one positional argument, but none was found",
+ sieve_command_identifier(cmd), sieve_command_type_name(cmd));
+ return FALSE;
+ }
+
+ /* <program-name: string> argument */
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, cmd, arg, "program-name", 1, SAAT_STRING) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, cmd, arg, FALSE) )
+ return FALSE;
+
+ /* Variables are not allowed */
+ if ( !sieve_argument_is_string_literal(arg) ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "the %s %s requires a constant string "
+ "for its program-name argument",
+ sieve_command_identifier(cmd), sieve_command_type_name(cmd));
+ return FALSE;
+ }
+
+ /* Check program name */
+ program_name = sieve_ast_argument_str(arg);
+ if ( !sieve_extprogram_name_is_valid(program_name) ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "%s %s: invalid program name '%s'",
+ sieve_command_identifier(cmd), sieve_command_type_name(cmd),
+ str_sanitize(str_c(program_name), 80));
+ return FALSE;
+ }
+
+ /* Optional <arguments: string-list> argument */
+
+ arg = sieve_ast_argument_next(arg);
+ if ( arg == NULL )
+ return TRUE;
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, cmd, arg, "arguments", 2, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, cmd, arg, FALSE) )
+ return FALSE;
+
+ /* Check arguments */
+ actx.valdtr = valdtr;
+ actx.cmd = cmd;
+ stritem = arg;
+ if ( sieve_ast_stringlist_map
+ (&stritem, (void *)&actx, _arg_validate) <= 0 ) {
+ return FALSE;
+ }
+
+ if ( sieve_ast_argument_next(arg) != NULL ) {
+ sieve_command_validate_error(valdtr, cmd,
+ "the %s %s expects at most two positional arguments, but more were found",
+ sieve_command_identifier(cmd), sieve_command_type_name(cmd));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Common command operands
+ */
+
+int sieve_extprogram_command_read_operands
+(const struct sieve_runtime_env *renv, sieve_size_t *address,
+ string_t **pname_r, struct sieve_stringlist **args_list_r)
+{
+ string_t *arg;
+ int ret;
+
+ /*
+ * Read fixed operands
+ */
+
+ if ( (ret=sieve_opr_string_read
+ (renv, address, "program-name", pname_r)) <= 0 )
+ return ret;
+
+ if ( (ret=sieve_opr_stringlist_read_ex
+ (renv, address, "arguments", TRUE, args_list_r)) <= 0 )
+ return ret;
+
+ /*
+ * Check operands
+ */
+
+ arg = NULL;
+ while ( *args_list_r != NULL &&
+ (ret=sieve_stringlist_next_item(*args_list_r, &arg)) > 0 ) {
+ if ( !sieve_extprogram_arg_is_valid(arg) ) {
+ sieve_runtime_error(renv, NULL,
+ "specified :args item `%s' is invalid",
+ str_sanitize(str_c(arg), 128));
+ return SIEVE_EXEC_FAILURE;
+ }
+ }
+
+ if ( ret < 0 ) {
+ sieve_runtime_trace_error(renv, "invalid args-list item");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Running external programs
+ */
+
+struct sieve_extprogram {
+ struct sieve_instance *svinst;
+ const struct sieve_extprograms_config *ext_config;
+
+ const struct sieve_script_env *scriptenv;
+ struct program_client_settings set;
+ struct program_client *program_client;
+};
+
+void sieve_extprogram_exec_error
+(struct sieve_error_handler *ehandler, const char *location,
+ const char *fmt, ...)
+{
+ char str[256];
+ struct tm *tm;
+ const char *timestamp;
+
+ tm = localtime(&ioloop_time);
+
+ timestamp =
+ ( strftime(str, sizeof(str), " [%Y-%m-%d %H:%M:%S]", tm) > 0 ? str : "" );
+
+ va_list args;
+ va_start(args, fmt);
+
+ T_BEGIN {
+ sieve_error(ehandler, location,
+ "%s: refer to server log for more information.%s",
+ t_strdup_vprintf(fmt, args), timestamp);
+ } T_END;
+
+ va_end(args);
+}
+
+/* API */
+
+struct sieve_extprogram *sieve_extprogram_create
+(const struct sieve_extension *ext, const struct sieve_script_env *senv,
+ const struct sieve_message_data *msgdata, const char *action,
+ const char *program_name, const char * const *args,
+ enum sieve_error *error_r)
+{
+ struct sieve_instance *svinst = ext->svinst;
+ struct sieve_extprograms_config *ext_config =
+ (struct sieve_extprograms_config *) ext->context;
+ const struct smtp_address *sender, *recipient, *orig_recipient;
+ struct sieve_extprogram *sprog;
+ const char *path = NULL;
+ struct stat st;
+ bool fork = FALSE;
+
+ e_debug(svinst->event, "action %s: "
+ "running program: %s", action, program_name);
+
+ if ( ext_config == NULL ||
+ (ext_config->bin_dir == NULL && ext_config->socket_dir == NULL) ) {
+ e_error(svinst->event, "action %s: "
+ "failed to execute program `%s': "
+ "vnd.dovecot.%s extension is unconfigured",
+ action, program_name, action);
+ *error_r = SIEVE_ERROR_NOT_FOUND;
+ return NULL;
+ }
+
+ /* Try socket first */
+ if ( ext_config->socket_dir != NULL ) {
+ path = t_strconcat(senv->user->set->base_dir, "/",
+ ext_config->socket_dir, "/", program_name, NULL);
+ if ( stat(path, &st) < 0 ) {
+ switch ( errno ) {
+ case ENOENT:
+ e_debug(svinst->event, "action %s: "
+ "socket path `%s' for program `%s' not found",
+ action, path, program_name);
+ break;
+ case EACCES:
+ e_error(svinst->event, "action %s: "
+ "failed to stat socket: %s",
+ action, eacces_error_get("stat", path));
+ *error_r = SIEVE_ERROR_NO_PERMISSION;
+ return NULL;
+ default:
+ e_error(svinst->event, "action %s: "
+ "failed to stat socket `%s': %m",
+ action, path);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return NULL;
+ }
+ path = NULL;
+ } else if ( !S_ISSOCK(st.st_mode) ) {
+ e_error(svinst->event, "action %s: "
+ "socket path `%s' for program `%s' is not a socket",
+ action, path, program_name);
+ *error_r = SIEVE_ERROR_NOT_POSSIBLE;
+ return NULL;
+ }
+ }
+
+ /* Try executable next */
+ if ( path == NULL && ext_config->bin_dir != NULL ) {
+ fork = TRUE;
+ path = t_strconcat(ext_config->bin_dir, "/", program_name, NULL);
+ if ( stat(path, &st) < 0 ) {
+ switch ( errno ) {
+ case ENOENT:
+ e_debug(svinst->event, "action %s: "
+ "executable path `%s' for program `%s' not found",
+ action, path, program_name);
+ *error_r = SIEVE_ERROR_NOT_FOUND;
+ break;
+ case EACCES:
+ e_error(svinst->event, "action %s: "
+ "failed to stat program: %s",
+ action, eacces_error_get("stat", path));
+ *error_r = SIEVE_ERROR_NO_PERMISSION;
+ break;
+ default:
+ e_error(svinst->event, "action %s: "
+ "failed to stat program `%s': %m",
+ action, path);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ break;
+ }
+
+ return NULL;
+ } else if ( !S_ISREG(st.st_mode) ) {
+ e_error(svinst->event, "action %s: "
+ "executable `%s' for program `%s' is not a regular file",
+ action, path, program_name);
+ *error_r = SIEVE_ERROR_NOT_POSSIBLE;
+ return NULL;
+ } else if ( (st.st_mode & S_IWOTH) != 0 ) {
+ e_error(svinst->event, "action %s: "
+ "executable `%s' for program `%s' is world-writable",
+ action, path, program_name);
+ *error_r = SIEVE_ERROR_NO_PERMISSION;
+ return NULL;
+ }
+ }
+
+ /* None found ? */
+ if ( path == NULL ) {
+ e_error(svinst->event, "action %s: "
+ "program `%s' not found", action, program_name);
+ *error_r = SIEVE_ERROR_NOT_FOUND;
+ return NULL;
+ }
+
+ sprog = i_new(struct sieve_extprogram, 1);
+ sprog->svinst = ext->svinst;
+ sprog->ext_config = ext_config;
+ sprog->scriptenv = senv;
+
+ sprog->set.client_connect_timeout_msecs =
+ SIEVE_EXTPROGRAMS_CONNECT_TIMEOUT_MSECS;
+ sprog->set.input_idle_timeout_msecs =
+ ext_config->execute_timeout * 1000;
+ restrict_access_init(&sprog->set.restrict_set);
+ if (senv->user->uid != 0)
+ sprog->set.restrict_set.uid = senv->user->uid;
+ if (senv->user->gid != 0)
+ sprog->set.restrict_set.gid = senv->user->gid;
+ sprog->set.debug = svinst->debug;
+
+ if ( fork ) {
+ sprog->program_client =
+ program_client_local_create(path, args, &sprog->set);
+ } else {
+ sprog->program_client =
+ program_client_unix_create(path, args, &sprog->set, FALSE);
+ }
+
+ if ( svinst->username != NULL )
+ program_client_set_env(sprog->program_client, "USER", svinst->username);
+ if ( svinst->home_dir != NULL )
+ program_client_set_env(sprog->program_client, "HOME", svinst->home_dir);
+ if ( svinst->hostname != NULL )
+ program_client_set_env(sprog->program_client, "HOST", svinst->hostname);
+
+ sender = msgdata->envelope.mail_from;
+ recipient = msgdata->envelope.rcpt_to;
+ orig_recipient = NULL;
+ if ( msgdata->envelope.rcpt_params != NULL )
+ orig_recipient = msgdata->envelope.rcpt_params->orcpt.addr;
+
+ if ( !smtp_address_isnull(sender) ) {
+ program_client_set_env(sprog->program_client, "SENDER",
+ smtp_address_encode(sender));
+ }
+ if ( !smtp_address_isnull(recipient) ) {
+ program_client_set_env(sprog->program_client, "RECIPIENT",
+ smtp_address_encode(recipient));
+ }
+ if ( !smtp_address_isnull(orig_recipient) ) {
+ program_client_set_env(sprog->program_client, "ORIG_RECIPIENT",
+ smtp_address_encode(orig_recipient));
+ }
+
+ return sprog;
+}
+
+void sieve_extprogram_destroy(struct sieve_extprogram **_sprog)
+{
+ struct sieve_extprogram *sprog = *_sprog;
+
+ program_client_destroy(&sprog->program_client);
+ i_free(sprog);
+ *_sprog = NULL;
+}
+
+/* I/0 */
+
+void sieve_extprogram_set_output
+(struct sieve_extprogram *sprog, struct ostream *output)
+{
+ program_client_set_output(sprog->program_client, output);
+}
+
+void sieve_extprogram_set_input
+(struct sieve_extprogram *sprog, struct istream *input)
+{
+ switch (sprog->ext_config->default_input_eol) {
+ case SIEVE_EXTPROGRAMS_EOL_LF:
+ input = i_stream_create_lf(input);
+ break;
+ case SIEVE_EXTPROGRAMS_EOL_CRLF:
+ input = i_stream_create_crlf(input);
+ break;
+ default:
+ i_unreached();
+ }
+
+ program_client_set_input(sprog->program_client, input);
+
+ i_stream_unref(&input);
+}
+
+void sieve_extprogram_set_output_seekable
+(struct sieve_extprogram *sprog)
+{
+ string_t *prefix;
+ prefix = t_str_new(128);
+ mail_user_set_get_temp_prefix(prefix, sprog->scriptenv->user->set);
+
+ program_client_set_output_seekable(sprog->program_client, str_c(prefix));
+}
+
+struct istream *sieve_extprogram_get_output_seekable
+(struct sieve_extprogram *sprog)
+{
+ return program_client_get_output_seekable(sprog->program_client);
+}
+
+int sieve_extprogram_set_input_mail
+(struct sieve_extprogram *sprog, struct mail *mail)
+{
+ struct istream *input;
+
+ if (mail_get_stream(mail, NULL, NULL, &input) < 0)
+ return -1;
+
+ sieve_extprogram_set_input(sprog, input);
+ return 1;
+}
+
+int sieve_extprogram_run(struct sieve_extprogram *sprog)
+{
+ switch (program_client_run(sprog->program_client)) {
+ case PROGRAM_CLIENT_EXIT_STATUS_INTERNAL_FAILURE:
+ return -1;
+ case PROGRAM_CLIENT_EXIT_STATUS_FAILURE:
+ return 0;
+ case PROGRAM_CLIENT_EXIT_STATUS_SUCCESS:
+ return 1;
+ }
+ i_unreached();
+}
+
diff --git a/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-common.h b/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-common.h
new file mode 100644
index 0000000..063c02b
--- /dev/null
+++ b/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-common.h
@@ -0,0 +1,107 @@
+#ifndef SIEVE_EXTPROGRAMS_COMMON_H
+#define SIEVE_EXTPROGRAMS_COMMON_H
+
+#include "sieve-common.h"
+
+/*
+ * Extension configuration
+ */
+
+enum sieve_extprograms_eol {
+ SIEVE_EXTPROGRAMS_EOL_CRLF = 0,
+ SIEVE_EXTPROGRAMS_EOL_LF
+};
+
+struct sieve_extprograms_config {
+ const struct sieve_extension *copy_ext;
+ const struct sieve_extension *var_ext;
+
+ char *socket_dir;
+ char *bin_dir;
+
+ enum sieve_extprograms_eol default_input_eol;
+
+ unsigned int execute_timeout;
+};
+
+struct sieve_extprograms_config *sieve_extprograms_config_init
+ (const struct sieve_extension *ext);
+void sieve_extprograms_config_deinit
+ (struct sieve_extprograms_config **ext_config);
+
+/*
+ * Extensions
+ */
+
+extern const struct sieve_extension_def sieve_ext_vnd_pipe;
+extern const struct sieve_extension_def sieve_ext_vnd_filter;
+extern const struct sieve_extension_def sieve_ext_vnd_execute;
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def sieve_cmd_pipe;
+extern const struct sieve_command_def sieve_cmd_filter;
+extern const struct sieve_command_def sieve_cmd_execute;
+
+/*
+ * Operations
+ */
+
+extern const struct sieve_operation_def sieve_opr_pipe;
+extern const struct sieve_operation_def sieve_opr_filter;
+extern const struct sieve_operation_def sieve_opr_execute;
+
+/*
+ * Program name and arguments
+ */
+
+bool sieve_extprogram_arg_is_valid(string_t *arg);
+bool sieve_extprogram_name_is_valid(string_t *name);
+
+/*
+ * Command validation
+ */
+
+bool sieve_extprogram_command_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+
+/*
+ * Common command operands
+ */
+
+int sieve_extprogram_command_read_operands
+ (const struct sieve_runtime_env *renv, sieve_size_t *address,
+ string_t **pname_r, struct sieve_stringlist **args_list_r);
+
+/*
+ * Running external programs
+ */
+
+void sieve_extprogram_exec_error
+ (struct sieve_error_handler *ehandler, const char *location,
+ const char *fmt, ...) ATTR_FORMAT(3, 4);
+
+struct sieve_extprogram *sieve_extprogram_create
+ (const struct sieve_extension *ext, const struct sieve_script_env *senv,
+ const struct sieve_message_data *msgdata, const char *action,
+ const char *program_name, const char * const *args,
+ enum sieve_error *error_r);
+void sieve_extprogram_destroy(struct sieve_extprogram **_sprog);
+
+void sieve_extprogram_set_output
+ (struct sieve_extprogram *sprog, struct ostream *output);
+void sieve_extprogram_set_output_seekable
+ (struct sieve_extprogram *sprog);
+struct istream *sieve_extprogram_get_output_seekable
+ (struct sieve_extprogram *sprog);
+
+void sieve_extprogram_set_input
+ (struct sieve_extprogram *sprog, struct istream *input);
+int sieve_extprogram_set_input_mail
+ (struct sieve_extprogram *sprog, struct mail *mail);
+
+int sieve_extprogram_run(struct sieve_extprogram *sprog);
+
+#endif
diff --git a/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-plugin.c b/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-plugin.c
new file mode 100644
index 0000000..bf17a80
--- /dev/null
+++ b/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-plugin.c
@@ -0,0 +1,68 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-extensions.h"
+
+#include "sieve-extprograms-common.h"
+#include "sieve-extprograms-plugin.h"
+
+/*
+ * Sieve plugin interface
+ */
+
+struct _plugin_context {
+ const struct sieve_extension *ext_pipe;
+ const struct sieve_extension *ext_filter;
+ const struct sieve_extension *ext_execute;
+};
+
+const char *sieve_extprograms_plugin_version = PIGEONHOLE_ABI_VERSION;
+
+void sieve_extprograms_plugin_load
+(struct sieve_instance *svinst, void **context)
+{
+ struct _plugin_context *pctx = i_new(struct _plugin_context, 1);
+
+ pctx->ext_pipe = sieve_extension_register
+ (svinst, &sieve_ext_vnd_pipe, FALSE);
+ pctx->ext_filter = sieve_extension_register
+ (svinst, &sieve_ext_vnd_filter, FALSE);
+ pctx->ext_execute = sieve_extension_register
+ (svinst, &sieve_ext_vnd_execute, FALSE);
+
+ if ( svinst->debug ) {
+ e_debug(svinst->event,
+ "Sieve Extprograms plugin for %s version %s loaded",
+ PIGEONHOLE_NAME, PIGEONHOLE_VERSION_FULL);
+ }
+
+ *context = (void *)pctx;
+}
+
+void sieve_extprograms_plugin_unload
+(struct sieve_instance *svinst ATTR_UNUSED, void *context)
+{
+ struct _plugin_context *pctx = (struct _plugin_context *)context;
+
+ sieve_extension_unregister(pctx->ext_pipe);
+ sieve_extension_unregister(pctx->ext_filter);
+ sieve_extension_unregister(pctx->ext_execute);
+
+ i_free(pctx);
+}
+
+/*
+ * Module interface
+ */
+
+void sieve_extprograms_plugin_init(void)
+{
+ /* Nothing */
+}
+
+void sieve_extprograms_plugin_deinit(void)
+{
+ /* Nothing */
+}
diff --git a/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-plugin.h b/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-plugin.h
new file mode 100644
index 0000000..20fa55a
--- /dev/null
+++ b/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-plugin.h
@@ -0,0 +1,20 @@
+#ifndef SIEVE_EXTPROGRAMS_PLUGIN_H
+#define SIEVE_EXTPROGRAMS_PLUGIN_H
+
+/*
+ * Plugin interface
+ */
+
+void sieve_extprograms_plugin_load
+ (struct sieve_instance *svinst, void **context);
+void sieve_extprograms_plugin_unload
+ (struct sieve_instance *svinst, void *context);
+
+/*
+ * Module interface
+ */
+
+void sieve_extprograms_plugin_init(void);
+void sieve_extprograms_plugin_deinit(void);
+
+#endif
diff --git a/pigeonhole/src/sieve-tools/Makefile.am b/pigeonhole/src/sieve-tools/Makefile.am
new file mode 100644
index 0000000..f2ceffd
--- /dev/null
+++ b/pigeonhole/src/sieve-tools/Makefile.am
@@ -0,0 +1,59 @@
+bin_PROGRAMS = sievec sieve-dump sieve-test sieve-filter
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib-sieve \
+ -I$(top_srcdir)/src/lib-sieve-tool \
+ -I$(srcdir)/debug \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_SERVICE_INCLUDE)
+
+libs = \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la \
+ $(top_builddir)/src/lib-sieve-tool/libsieve-tool.la
+
+libs_ldadd = $(libs) $(LIBDOVECOT_STORAGE) $(LIBDOVECOT_LDA) $(LIBDOVECOT)
+libs_deps = $(libs) $(LIBDOVECOT_STORAGE_DEPS) $(LIBDOVECOT_LDA_DEPS) $(LIBDOVECOT_DEPS)
+
+# Sieve Compile Tool
+
+sievec_CPPFLAGS = $(AM_CPPFLAGS) $(BINARY_CFLAGS)
+sievec_LDFLAGS = -export-dynamic $(BINARY_LDFLAGS)
+sievec_LDADD = $(libs_ldadd)
+sievec_DEPENDENCIES = $(libs_deps)
+
+sievec_SOURCES = \
+ sievec.c
+
+# Sieve Dump Tool
+
+sieve_dump_CPPFLAGS = $(AM_CPPFLAGS) $(BINARY_CFLAGS)
+sieve_dump_LDFLAGS = -export-dynamic $(BINARY_LDFLAGS)
+sieve_dump_LDADD = $(libs_ldadd)
+sieve_dump_DEPENDENCIES = $(libs_deps)
+
+sieve_dump_SOURCES = \
+ sieve-dump.c
+
+# Sieve Test Tool
+
+sieve_test_CPPFLAGS = $(AM_CPPFLAGS) $(BINARY_CFLAGS)
+sieve_test_LDFLAGS = -export-dynamic $(BINARY_LDFLAGS)
+sieve_test_LDADD = $(libs_ldadd)
+sieve_test_DEPENDENCIES = $(libs_deps)
+
+sieve_test_SOURCES = \
+ sieve-test.c
+
+## Unfinished tools
+
+# Sieve Filter Tool
+
+sieve_filter_CPPFLAGS = $(AM_CPPFLAGS) $(BINARY_CFLAGS)
+sieve_filter_LDFLAGS = -export-dynamic $(BINARY_LDFLAGS)
+sieve_filter_LDADD = $(libs_ldadd)
+sieve_filter_DEPENDENCIES = $(libs_deps)
+
+sieve_filter_SOURCES = \
+ sieve-filter.c
+
+noinst_HEADERS =
diff --git a/pigeonhole/src/sieve-tools/Makefile.in b/pigeonhole/src/sieve-tools/Makefile.in
new file mode 100644
index 0000000..6b5b0d0
--- /dev/null
+++ b/pigeonhole/src/sieve-tools/Makefile.in
@@ -0,0 +1,863 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+bin_PROGRAMS = sievec$(EXEEXT) sieve-dump$(EXEEXT) sieve-test$(EXEEXT) \
+ sieve-filter$(EXEEXT)
+subdir = src/sieve-tools
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_sieve_dump_OBJECTS = sieve_dump-sieve-dump.$(OBJEXT)
+sieve_dump_OBJECTS = $(am_sieve_dump_OBJECTS)
+am__DEPENDENCIES_1 =
+am__DEPENDENCIES_2 = $(libs) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+sieve_dump_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(sieve_dump_LDFLAGS) $(LDFLAGS) -o $@
+am_sieve_filter_OBJECTS = sieve_filter-sieve-filter.$(OBJEXT)
+sieve_filter_OBJECTS = $(am_sieve_filter_OBJECTS)
+sieve_filter_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(sieve_filter_LDFLAGS) $(LDFLAGS) -o $@
+am_sieve_test_OBJECTS = sieve_test-sieve-test.$(OBJEXT)
+sieve_test_OBJECTS = $(am_sieve_test_OBJECTS)
+sieve_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(sieve_test_LDFLAGS) $(LDFLAGS) -o $@
+am_sievec_OBJECTS = sievec-sievec.$(OBJEXT)
+sievec_OBJECTS = $(am_sievec_OBJECTS)
+sievec_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(sievec_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/sieve_dump-sieve-dump.Po \
+ ./$(DEPDIR)/sieve_filter-sieve-filter.Po \
+ ./$(DEPDIR)/sieve_test-sieve-test.Po \
+ ./$(DEPDIR)/sievec-sievec.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(sieve_dump_SOURCES) $(sieve_filter_SOURCES) \
+ $(sieve_test_SOURCES) $(sievec_SOURCES)
+DIST_SOURCES = $(sieve_dump_SOURCES) $(sieve_filter_SOURCES) \
+ $(sieve_test_SOURCES) $(sievec_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib-sieve \
+ -I$(top_srcdir)/src/lib-sieve-tool \
+ -I$(srcdir)/debug \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_SERVICE_INCLUDE)
+
+libs = \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la \
+ $(top_builddir)/src/lib-sieve-tool/libsieve-tool.la
+
+libs_ldadd = $(libs) $(LIBDOVECOT_STORAGE) $(LIBDOVECOT_LDA) $(LIBDOVECOT)
+libs_deps = $(libs) $(LIBDOVECOT_STORAGE_DEPS) $(LIBDOVECOT_LDA_DEPS) $(LIBDOVECOT_DEPS)
+
+# Sieve Compile Tool
+sievec_CPPFLAGS = $(AM_CPPFLAGS) $(BINARY_CFLAGS)
+sievec_LDFLAGS = -export-dynamic $(BINARY_LDFLAGS)
+sievec_LDADD = $(libs_ldadd)
+sievec_DEPENDENCIES = $(libs_deps)
+sievec_SOURCES = \
+ sievec.c
+
+
+# Sieve Dump Tool
+sieve_dump_CPPFLAGS = $(AM_CPPFLAGS) $(BINARY_CFLAGS)
+sieve_dump_LDFLAGS = -export-dynamic $(BINARY_LDFLAGS)
+sieve_dump_LDADD = $(libs_ldadd)
+sieve_dump_DEPENDENCIES = $(libs_deps)
+sieve_dump_SOURCES = \
+ sieve-dump.c
+
+
+# Sieve Test Tool
+sieve_test_CPPFLAGS = $(AM_CPPFLAGS) $(BINARY_CFLAGS)
+sieve_test_LDFLAGS = -export-dynamic $(BINARY_LDFLAGS)
+sieve_test_LDADD = $(libs_ldadd)
+sieve_test_DEPENDENCIES = $(libs_deps)
+sieve_test_SOURCES = \
+ sieve-test.c
+
+
+# Sieve Filter Tool
+sieve_filter_CPPFLAGS = $(AM_CPPFLAGS) $(BINARY_CFLAGS)
+sieve_filter_LDFLAGS = -export-dynamic $(BINARY_LDFLAGS)
+sieve_filter_LDADD = $(libs_ldadd)
+sieve_filter_DEPENDENCIES = $(libs_deps)
+sieve_filter_SOURCES = \
+ sieve-filter.c
+
+noinst_HEADERS =
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/sieve-tools/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/sieve-tools/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+sieve-dump$(EXEEXT): $(sieve_dump_OBJECTS) $(sieve_dump_DEPENDENCIES) $(EXTRA_sieve_dump_DEPENDENCIES)
+ @rm -f sieve-dump$(EXEEXT)
+ $(AM_V_CCLD)$(sieve_dump_LINK) $(sieve_dump_OBJECTS) $(sieve_dump_LDADD) $(LIBS)
+
+sieve-filter$(EXEEXT): $(sieve_filter_OBJECTS) $(sieve_filter_DEPENDENCIES) $(EXTRA_sieve_filter_DEPENDENCIES)
+ @rm -f sieve-filter$(EXEEXT)
+ $(AM_V_CCLD)$(sieve_filter_LINK) $(sieve_filter_OBJECTS) $(sieve_filter_LDADD) $(LIBS)
+
+sieve-test$(EXEEXT): $(sieve_test_OBJECTS) $(sieve_test_DEPENDENCIES) $(EXTRA_sieve_test_DEPENDENCIES)
+ @rm -f sieve-test$(EXEEXT)
+ $(AM_V_CCLD)$(sieve_test_LINK) $(sieve_test_OBJECTS) $(sieve_test_LDADD) $(LIBS)
+
+sievec$(EXEEXT): $(sievec_OBJECTS) $(sievec_DEPENDENCIES) $(EXTRA_sievec_DEPENDENCIES)
+ @rm -f sievec$(EXEEXT)
+ $(AM_V_CCLD)$(sievec_LINK) $(sievec_OBJECTS) $(sievec_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve_dump-sieve-dump.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve_filter-sieve-filter.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve_test-sieve-test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sievec-sievec.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+sieve_dump-sieve-dump.o: sieve-dump.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sieve_dump_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sieve_dump-sieve-dump.o -MD -MP -MF $(DEPDIR)/sieve_dump-sieve-dump.Tpo -c -o sieve_dump-sieve-dump.o `test -f 'sieve-dump.c' || echo '$(srcdir)/'`sieve-dump.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sieve_dump-sieve-dump.Tpo $(DEPDIR)/sieve_dump-sieve-dump.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sieve-dump.c' object='sieve_dump-sieve-dump.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sieve_dump_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sieve_dump-sieve-dump.o `test -f 'sieve-dump.c' || echo '$(srcdir)/'`sieve-dump.c
+
+sieve_dump-sieve-dump.obj: sieve-dump.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sieve_dump_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sieve_dump-sieve-dump.obj -MD -MP -MF $(DEPDIR)/sieve_dump-sieve-dump.Tpo -c -o sieve_dump-sieve-dump.obj `if test -f 'sieve-dump.c'; then $(CYGPATH_W) 'sieve-dump.c'; else $(CYGPATH_W) '$(srcdir)/sieve-dump.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sieve_dump-sieve-dump.Tpo $(DEPDIR)/sieve_dump-sieve-dump.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sieve-dump.c' object='sieve_dump-sieve-dump.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sieve_dump_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sieve_dump-sieve-dump.obj `if test -f 'sieve-dump.c'; then $(CYGPATH_W) 'sieve-dump.c'; else $(CYGPATH_W) '$(srcdir)/sieve-dump.c'; fi`
+
+sieve_filter-sieve-filter.o: sieve-filter.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sieve_filter_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sieve_filter-sieve-filter.o -MD -MP -MF $(DEPDIR)/sieve_filter-sieve-filter.Tpo -c -o sieve_filter-sieve-filter.o `test -f 'sieve-filter.c' || echo '$(srcdir)/'`sieve-filter.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sieve_filter-sieve-filter.Tpo $(DEPDIR)/sieve_filter-sieve-filter.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sieve-filter.c' object='sieve_filter-sieve-filter.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sieve_filter_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sieve_filter-sieve-filter.o `test -f 'sieve-filter.c' || echo '$(srcdir)/'`sieve-filter.c
+
+sieve_filter-sieve-filter.obj: sieve-filter.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sieve_filter_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sieve_filter-sieve-filter.obj -MD -MP -MF $(DEPDIR)/sieve_filter-sieve-filter.Tpo -c -o sieve_filter-sieve-filter.obj `if test -f 'sieve-filter.c'; then $(CYGPATH_W) 'sieve-filter.c'; else $(CYGPATH_W) '$(srcdir)/sieve-filter.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sieve_filter-sieve-filter.Tpo $(DEPDIR)/sieve_filter-sieve-filter.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sieve-filter.c' object='sieve_filter-sieve-filter.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sieve_filter_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sieve_filter-sieve-filter.obj `if test -f 'sieve-filter.c'; then $(CYGPATH_W) 'sieve-filter.c'; else $(CYGPATH_W) '$(srcdir)/sieve-filter.c'; fi`
+
+sieve_test-sieve-test.o: sieve-test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sieve_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sieve_test-sieve-test.o -MD -MP -MF $(DEPDIR)/sieve_test-sieve-test.Tpo -c -o sieve_test-sieve-test.o `test -f 'sieve-test.c' || echo '$(srcdir)/'`sieve-test.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sieve_test-sieve-test.Tpo $(DEPDIR)/sieve_test-sieve-test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sieve-test.c' object='sieve_test-sieve-test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sieve_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sieve_test-sieve-test.o `test -f 'sieve-test.c' || echo '$(srcdir)/'`sieve-test.c
+
+sieve_test-sieve-test.obj: sieve-test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sieve_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sieve_test-sieve-test.obj -MD -MP -MF $(DEPDIR)/sieve_test-sieve-test.Tpo -c -o sieve_test-sieve-test.obj `if test -f 'sieve-test.c'; then $(CYGPATH_W) 'sieve-test.c'; else $(CYGPATH_W) '$(srcdir)/sieve-test.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sieve_test-sieve-test.Tpo $(DEPDIR)/sieve_test-sieve-test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sieve-test.c' object='sieve_test-sieve-test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sieve_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sieve_test-sieve-test.obj `if test -f 'sieve-test.c'; then $(CYGPATH_W) 'sieve-test.c'; else $(CYGPATH_W) '$(srcdir)/sieve-test.c'; fi`
+
+sievec-sievec.o: sievec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sievec_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sievec-sievec.o -MD -MP -MF $(DEPDIR)/sievec-sievec.Tpo -c -o sievec-sievec.o `test -f 'sievec.c' || echo '$(srcdir)/'`sievec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sievec-sievec.Tpo $(DEPDIR)/sievec-sievec.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sievec.c' object='sievec-sievec.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sievec_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sievec-sievec.o `test -f 'sievec.c' || echo '$(srcdir)/'`sievec.c
+
+sievec-sievec.obj: sievec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sievec_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sievec-sievec.obj -MD -MP -MF $(DEPDIR)/sievec-sievec.Tpo -c -o sievec-sievec.obj `if test -f 'sievec.c'; then $(CYGPATH_W) 'sievec.c'; else $(CYGPATH_W) '$(srcdir)/sievec.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sievec-sievec.Tpo $(DEPDIR)/sievec-sievec.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sievec.c' object='sievec-sievec.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sievec_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sievec-sievec.obj `if test -f 'sievec.c'; then $(CYGPATH_W) 'sievec.c'; else $(CYGPATH_W) '$(srcdir)/sievec.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/sieve_dump-sieve-dump.Po
+ -rm -f ./$(DEPDIR)/sieve_filter-sieve-filter.Po
+ -rm -f ./$(DEPDIR)/sieve_test-sieve-test.Po
+ -rm -f ./$(DEPDIR)/sievec-sievec.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/sieve_dump-sieve-dump.Po
+ -rm -f ./$(DEPDIR)/sieve_filter-sieve-filter.Po
+ -rm -f ./$(DEPDIR)/sieve_test-sieve-test.Po
+ -rm -f ./$(DEPDIR)/sievec-sievec.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-binPROGRAMS \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/sieve-tools/sieve-dump.c b/pigeonhole/src/sieve-tools/sieve-dump.c
new file mode 100644
index 0000000..23b2be4
--- /dev/null
+++ b/pigeonhole/src/sieve-tools/sieve-dump.c
@@ -0,0 +1,97 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "master-service.h"
+#include "master-service-settings.h"
+#include "mail-storage-service.h"
+#include "mail-user.h"
+
+#include "sieve.h"
+#include "sieve-extensions.h"
+#include "sieve-tool.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sysexits.h>
+
+/*
+ * Print help
+ */
+
+static void print_help(void)
+{
+ printf(
+"Usage: sieve-dump [-c <config-file>] [-D] [-h] [-P <plugin>] [-x <extensions>]\n"
+" <sieve-binary> [<out-file>]\n"
+ );
+}
+
+/*
+ * Tool implementation
+ */
+
+int main(int argc, char **argv)
+{
+ struct sieve_instance *svinst;
+ struct sieve_binary *sbin;
+ const char *binfile, *outfile;
+ bool hexdump = FALSE;
+ int exit_status = EXIT_SUCCESS;
+ int c;
+
+ sieve_tool = sieve_tool_init("sieve-dump", &argc, &argv, "DhP:x:", FALSE);
+
+ outfile = NULL;
+
+ while ((c = sieve_tool_getopt(sieve_tool)) > 0) {
+ switch (c) {
+ case 'h':
+ /* produce hexdump */
+ hexdump = TRUE;
+ break;
+ default:
+ print_help();
+ i_fatal_status(EX_USAGE, "Unknown argument: %c", c);
+ break;
+ }
+ }
+
+ if ( optind < argc ) {
+ binfile = argv[optind++];
+ } else {
+ print_help();
+ i_fatal_status(EX_USAGE, "Missing <script-file> argument");
+ }
+
+ if ( optind < argc ) {
+ outfile = argv[optind++];
+ }
+
+ /* Finish tool initialization */
+ svinst = sieve_tool_init_finish(sieve_tool, FALSE, TRUE);
+
+ /* Enable debug extension */
+ sieve_enable_debug_extension(svinst);
+
+ /* Dump binary */
+ sbin = sieve_load(svinst, binfile, NULL);
+ if ( sbin != NULL ) {
+ sieve_tool_dump_binary_to(sbin, outfile == NULL ? "-" : outfile, hexdump);
+
+ sieve_close(&sbin);
+ } else {
+ i_error("failed to load binary: %s", binfile);
+ exit_status = EXIT_FAILURE;
+ }
+
+ sieve_tool_deinit(&sieve_tool);
+
+ return exit_status;
+}
+
diff --git a/pigeonhole/src/sieve-tools/sieve-filter.c b/pigeonhole/src/sieve-tools/sieve-filter.c
new file mode 100644
index 0000000..2b98fe6
--- /dev/null
+++ b/pigeonhole/src/sieve-tools/sieve-filter.c
@@ -0,0 +1,614 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "lib-signals.h"
+#include "ioloop.h"
+#include "env-util.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "ostream.h"
+#include "array.h"
+#include "mail-namespace.h"
+#include "mail-storage.h"
+#include "mail-search-build.h"
+
+#include "sieve.h"
+#include "sieve-extensions.h"
+#include "sieve-binary.h"
+
+#include "sieve-tool.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <sysexits.h>
+
+/*
+ * Print help
+ */
+
+static void print_help(void)
+{
+ printf(
+"Usage: sieve-filter [-c <config-file>] [-C] [-D] [-e] [-m <default-mailbox>]\n"
+" [-P <plugin>] [-q <output-mailbox>] [-Q <mail-command>]\n"
+" [-s <script-file>] [-u <user>] [-v] [-W] [-x <extensions>]\n"
+" <script-file> <source-mailbox> [<discard-action>]\n"
+ );
+}
+
+enum sieve_filter_discard_action {
+ SIEVE_FILTER_DACT_KEEP, /* Keep discarded messages in source folder */
+ SIEVE_FILTER_DACT_MOVE, /* Move discarded messages to Trash folder */
+ SIEVE_FILTER_DACT_DELETE, /* Flag discarded messages as \DELETED */
+ SIEVE_FILTER_DACT_EXPUNGE /* Expunge discarded messages */
+};
+
+struct sieve_filter_data {
+ enum sieve_filter_discard_action discard_action;
+ struct mailbox *move_mailbox;
+
+ struct sieve_script_env *senv;
+ struct sieve_binary *main_sbin;
+ struct sieve_error_handler *ehandler;
+
+ bool execute:1;
+ bool source_write:1;
+ bool default_move:1;
+};
+
+struct sieve_filter_context {
+ const struct sieve_filter_data *data;
+
+ struct mailbox_transaction_context *move_trans;
+
+ struct ostream *teststream;
+};
+
+static const char *
+result_amend_log_message(const struct sieve_script_env *senv,
+ enum log_type log_type, const char *message)
+{
+ const struct sieve_message_data *msgdata = senv->script_context;
+ string_t *str;
+
+ if (log_type == LOG_TYPE_DEBUG)
+ return message;
+
+ str = t_str_new(256);
+ str_printfa(str, "msgid=%s", (msgdata->id == NULL ?
+ "unspecified" : msgdata->id));
+ str_append(str, ": ");
+ str_append(str, message);
+
+ return str_c(str);
+}
+
+static int filter_message(struct sieve_filter_context *sfctx, struct mail *mail)
+{
+ struct sieve_error_handler *ehandler = sfctx->data->ehandler;
+ enum sieve_execute_flags exflags = SIEVE_EXECUTE_FLAG_LOG_RESULT;
+ struct sieve_script_env *senv = sfctx->data->senv;
+ struct sieve_exec_status estatus;
+ struct sieve_binary *sbin;
+ struct sieve_message_data msgdata;
+ bool execute = sfctx->data->execute;
+ bool source_write = sfctx->data->source_write;
+ const char *subject, *date;
+ uoff_t size = 0;
+ int ret;
+
+ /* Initialize execution status */
+ i_zero(&estatus);
+ senv->exec_status = &estatus;
+
+ /* Collect necessary message data */
+ i_zero(&msgdata);
+ msgdata.mail = mail;
+ msgdata.auth_user = senv->user->username;
+ (void)mail_get_message_id(mail, &msgdata.id);
+ senv->script_context = &msgdata;
+
+ sieve_tool_get_envelope_data(&msgdata, mail, NULL, NULL, NULL);
+
+ if (mail_get_virtual_size(mail, &size) < 0) {
+ if (mail->expunged)
+ return 1;
+
+ sieve_error(ehandler, NULL, "failed to obtain message size; "
+ "skipping this message (id=%s)",
+ (msgdata.id == NULL ? "none" : msgdata.id));
+ return 0;
+ }
+
+ if (mail_get_first_header(mail, "date", &date) <= 0)
+ date = "";
+ if (mail_get_first_header(mail, "subject", &subject) <= 0)
+ subject = "";
+
+ /* Single script */
+ sbin = sfctx->data->main_sbin;
+
+ /* Execute script */
+ if (execute) {
+ sieve_info(ehandler, NULL,
+ "filtering: [%s; %"PRIuUOFF_T" bytes] `%s'",
+ date, size, str_sanitize(subject, 40));
+
+ ret = sieve_execute(sbin, &msgdata, senv, ehandler, ehandler,
+ exflags);
+ } else {
+ o_stream_nsend_str(
+ sfctx->teststream,
+ t_strdup_printf(">> Filtering message:\n\n"
+ " ID: %s\n"
+ " Date: %s\n"
+ " Size: %"PRIuUOFF_T" bytes\n"
+ " Subject: %s\n",
+ (msgdata.id == NULL ?
+ "none" : msgdata.id), date, size,
+ str_sanitize(subject, 40)));
+
+ ret = sieve_test(sbin, &msgdata, senv, ehandler,
+ sfctx->teststream, exflags);
+ }
+
+ /* Handle message in source folder */
+ if (ret > 0) {
+ struct mailbox *move_box = sfctx->data->move_mailbox;
+ enum sieve_filter_discard_action discard_action =
+ sfctx->data->discard_action;
+
+ if (!source_write) {
+ /* READ-ONLY; Do nothing */
+ } else if (estatus.keep_original) {
+ /* Explicitly `stored' in source box; just keep it there */
+ sieve_info(ehandler, NULL,
+ "message kept in source mailbox");
+ } else if (estatus.message_saved) {
+ sieve_info(
+ ehandler, NULL,
+ "message expunged from source mailbox upon successful move");
+
+ if (execute)
+ mail_expunge(mail);
+ } else {
+ switch (discard_action) {
+ /* Leave it there */
+ case SIEVE_FILTER_DACT_KEEP:
+ sieve_info(ehandler, NULL,
+ "message left in source mailbox");
+ break;
+ /* Move message to indicated folder */
+ case SIEVE_FILTER_DACT_MOVE:
+ sieve_info(
+ ehandler, NULL,
+ "message in source mailbox moved to mailbox '%s'",
+ mailbox_get_name(move_box));
+
+ if (execute && move_box != NULL) {
+ struct mailbox_transaction_context *t =
+ sfctx->move_trans;
+ struct mail_save_context *save_ctx;
+
+ save_ctx = mailbox_save_alloc(t);
+
+ if (mailbox_copy(&save_ctx, mail) < 0) {
+ enum mail_error error;
+ const char *errstr;
+
+ errstr = mail_storage_get_last_error(
+ mailbox_get_storage(move_box), &error);
+
+ sieve_error(
+ ehandler, NULL,
+ "failed to move message to mailbox %s: %s",
+ mailbox_get_name(move_box), errstr);
+ return -1;
+ }
+ mail_expunge(mail);
+ }
+ break;
+ /* Flag message as \DELETED */
+ case SIEVE_FILTER_DACT_DELETE:
+ sieve_info(
+ ehandler, NULL,
+ "message flagged as deleted in source mailbox");
+ if (execute)
+ mail_update_flags(mail, MODIFY_ADD, MAIL_DELETED);
+ break;
+ /* Expunge the message immediately */
+ case SIEVE_FILTER_DACT_EXPUNGE:
+ sieve_info(ehandler, NULL,
+ "message expunged from source mailbox");
+ if (execute)
+ mail_expunge(mail);
+ break;
+ /* Unknown */
+ default:
+ i_unreached();
+ break;
+ }
+ }
+ }
+
+ switch (ret) {
+ case SIEVE_EXEC_OK:
+ break;
+ case SIEVE_EXEC_RESOURCE_LIMIT:
+ sieve_error(ehandler, NULL, "sieve resource limit exceeded");
+ return -1;
+ case SIEVE_EXEC_BIN_CORRUPT:
+ sieve_error(ehandler, NULL, "sieve script binary is corrupt");
+ return -1;
+ case SIEVE_EXEC_FAILURE:
+ case SIEVE_EXEC_TEMP_FAILURE:
+ if (source_write && execute && sfctx->data->default_move &&
+ !estatus.keep_original && estatus.message_saved) {
+ /* The implicit keep action moved message to default
+ mailbox, so the source message still needs to be
+ expunged */
+ sieve_error(
+ ehandler, NULL,
+ "sieve script execution failed for this message; "
+ "message moved to default mailbox");
+ mail_expunge(mail);
+ return 0;
+ }
+ /* Fall through */
+ case SIEVE_EXEC_KEEP_FAILED:
+ sieve_error(
+ ehandler, NULL,
+ "sieve script execution failed for this message; "
+ "message left in source mailbox");
+ return 0;
+ }
+
+ return 1;
+}
+
+/* FIXME: introduce this into Dovecot */
+static void
+mail_search_build_add_flags(struct mail_search_args *args,
+ enum mail_flags flags, bool not)
+{
+ struct mail_search_arg *arg;
+
+ arg = p_new(args->pool, struct mail_search_arg, 1);
+ arg->type = SEARCH_FLAGS;
+ arg->value.flags = flags;
+ arg->match_not = not;
+
+ arg->next = args->args;
+ args->args = arg;
+}
+
+static int
+filter_mailbox(const struct sieve_filter_data *sfdata, struct mailbox *src_box)
+{
+ struct sieve_filter_context sfctx;
+ struct mailbox *move_box = sfdata->move_mailbox;
+ struct sieve_error_handler *ehandler = sfdata->ehandler;
+ struct mail_search_args *search_args;
+ struct mailbox_transaction_context *t;
+ struct mail_search_context *search_ctx;
+ struct mail *mail;
+ int ret = 1;
+
+ /* Sync source mailbox */
+
+ if (mailbox_sync(src_box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
+ sieve_error(ehandler, NULL, "failed to sync source mailbox");
+ return -1;
+ }
+
+ /* Initialize */
+
+ i_zero(&sfctx);
+ sfctx.data = sfdata;
+
+ /* Create test stream */
+ if (!sfdata->execute) {
+ sfctx.teststream = o_stream_create_fd(1, 0);
+ o_stream_set_no_error_handling(sfctx.teststream, TRUE);
+ }
+
+ /* Start move mailbox transaction */
+
+ if (move_box != NULL) {
+ sfctx.move_trans = mailbox_transaction_begin(
+ move_box, MAILBOX_TRANSACTION_FLAG_EXTERNAL,
+ "sieve_filter_data move_box");
+ }
+
+ /* Search non-deleted messages in the source folder */
+
+ search_args = mail_search_build_init();
+ mail_search_build_add_flags(search_args, MAIL_DELETED, TRUE);
+
+ t = mailbox_transaction_begin(src_box, 0,
+ "sieve_filter_data src_box");
+ search_ctx = mailbox_search_init(t, search_args, NULL, 0, NULL);
+ mail_search_args_unref(&search_args);
+
+ /* Iterate through all requested messages */
+
+ while (ret >= 0 && mailbox_search_next(search_ctx, &mail))
+ ret = filter_message(&sfctx, mail);
+
+ /* Cleanup */
+
+ if (mailbox_search_deinit(&search_ctx) < 0)
+ ret = -1;
+
+ if (sfctx.move_trans != NULL) {
+ if (mailbox_transaction_commit(&sfctx.move_trans) < 0)
+ ret = -1;
+ }
+
+ if (mailbox_transaction_commit(&t) < 0)
+ ret = -1;
+
+ if (sfctx.teststream != NULL)
+ o_stream_destroy(&sfctx.teststream);
+
+ if (ret < 0) return ret;
+
+ /* Sync mailbox */
+
+ if (sfdata->execute) {
+ if (mailbox_sync(src_box, MAILBOX_SYNC_FLAG_FULL_WRITE) < 0) {
+ sieve_error(ehandler, NULL,
+ "failed to sync source mailbox");
+ return -1;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Tool implementation
+ */
+
+int main(int argc, char **argv)
+{
+ struct sieve_instance *svinst;
+ ARRAY_TYPE(const_string) scriptfiles;
+ const char *scriptfile, *src_mailbox, *dst_mailbox, *move_mailbox;
+ struct sieve_filter_data sfdata;
+ enum sieve_filter_discard_action discard_action =
+ SIEVE_FILTER_DACT_KEEP;
+ struct mail_user *mail_user;
+ struct sieve_binary *main_sbin;
+ struct sieve_script_env scriptenv;
+ struct sieve_error_handler *ehandler;
+ bool force_compile, execute, source_write, verbose, default_move;
+ struct mail_namespace *ns;
+ struct mailbox *src_box = NULL, *move_box = NULL;
+ enum mailbox_flags open_flags = MAILBOX_FLAG_IGNORE_ACLS;
+ enum mail_error error;
+ const char *errstr;
+ int c;
+
+ sieve_tool = sieve_tool_init("sieve-filter", &argc, &argv,
+ "m:s:x:P:u:q:Q:DCevW", FALSE);
+
+ t_array_init(&scriptfiles, 16);
+
+ /* Parse arguments */
+ dst_mailbox = move_mailbox = NULL;
+ force_compile = execute = source_write = default_move = FALSE;
+ verbose = FALSE;
+ while ((c = sieve_tool_getopt(sieve_tool)) > 0) {
+ switch (c) {
+ case 'm':
+ /* default mailbox (keep box) */
+ dst_mailbox = optarg;
+ break;
+ case 's':
+ /* scriptfile executed before main script */
+ {
+ const char *file;
+
+ file = t_strdup(optarg);
+ array_append(&scriptfiles, &file, 1);
+
+ /* FIXME: */
+ i_fatal_status(
+ EX_USAGE,
+ "The -s argument is currently NOT IMPLEMENTED");
+ }
+ break;
+ case 'q':
+ i_fatal_status(
+ EX_USAGE,
+ "The -q argument is currently NOT IMPLEMENTED");
+ break;
+ case 'Q':
+ i_fatal_status(
+ EX_USAGE,
+ "The -Q argument is currently NOT IMPLEMENTED");
+ break;
+ case 'e':
+ /* execution mode */
+ execute = TRUE;
+ break;
+ case 'C':
+ /* force script compile */
+ force_compile = TRUE;
+ break;
+ case 'W':
+ /* enable source mailbox write */
+ source_write = TRUE;
+ break;
+ case 'v':
+ /* enable verbose output */
+ verbose = TRUE;
+ break;
+ default:
+ /* unrecognized option */
+ print_help();
+ i_fatal_status(EX_USAGE, "Unknown argument: %c", c);
+ break;
+ }
+ }
+
+ /* Script file argument */
+ if (optind < argc)
+ scriptfile = t_strdup(argv[optind++]);
+ else {
+ print_help();
+ i_fatal_status(EX_USAGE, "Missing <script-file> argument");
+ }
+
+ /* Source mailbox argument */
+ if (optind < argc)
+ src_mailbox = t_strdup(argv[optind++]);
+ else {
+ print_help();
+ i_fatal_status(EX_USAGE, "Missing <source-mailbox> argument");
+ }
+
+ /* Source action argument */
+ if (optind < argc) {
+ const char *srcact = argv[optind++];
+
+ if (strcmp(srcact, "keep") == 0) {
+ discard_action = SIEVE_FILTER_DACT_KEEP;
+ } else if (strcmp(srcact, "move") == 0) {
+ discard_action = SIEVE_FILTER_DACT_MOVE;
+ if (optind < argc)
+ move_mailbox = t_strdup(argv[optind++]);
+ else {
+ print_help();
+ i_fatal_status(
+ EX_USAGE,
+ "Invalid <discard-action> argument: "
+ "the `move' action requires mailbox argument");
+ }
+ } else if (strcmp(srcact, "delete") == 0) {
+ discard_action = SIEVE_FILTER_DACT_DELETE;
+ } else if (strcmp(srcact, "expunge") == 0) {
+ discard_action = SIEVE_FILTER_DACT_EXPUNGE;
+ } else {
+ print_help();
+ i_fatal_status(EX_USAGE,
+ "Invalid <discard-action> argument");
+ }
+ }
+
+ if (optind != argc) {
+ print_help();
+ i_fatal_status(EX_USAGE, "Unknown argument: %s", argv[optind]);
+ }
+
+ if (dst_mailbox == NULL) {
+ dst_mailbox = src_mailbox;
+ } else {
+ /* The (implicit) keep action will move the message */
+ default_move = TRUE;
+ }
+
+ /* Finish tool initialization */
+ svinst = sieve_tool_init_finish(sieve_tool, TRUE, FALSE);
+
+ /* Enable debug extension */
+ sieve_enable_debug_extension(svinst);
+
+ /* Create error handler */
+ ehandler = sieve_stderr_ehandler_create(svinst, 0);
+ sieve_error_handler_accept_infolog(ehandler, verbose);
+ sieve_error_handler_accept_debuglog(ehandler, svinst->debug);
+
+ /* Compile main sieve script */
+ if (force_compile) {
+ main_sbin = sieve_tool_script_compile(svinst, scriptfile, NULL);
+ if (main_sbin != NULL)
+ (void)sieve_save(main_sbin, TRUE, NULL);
+ } else {
+ main_sbin = sieve_tool_script_open(svinst, scriptfile);
+ }
+
+ /* Initialize mail user */
+ mail_user = sieve_tool_get_mail_user(sieve_tool);
+
+ /* Open the source mailbox */
+
+ ns = mail_namespace_find(mail_user->namespaces, src_mailbox);
+ if (ns == NULL) {
+ i_fatal("Unknown namespace for source mailbox '%s'",
+ src_mailbox);
+ }
+
+ if (!source_write || !execute)
+ open_flags |= MAILBOX_FLAG_READONLY;
+
+ src_box = mailbox_alloc(ns->list, src_mailbox, open_flags);
+ if (mailbox_open(src_box) < 0) {
+ i_fatal("Couldn't open source mailbox '%s': %s",
+ src_mailbox, mailbox_get_last_internal_error(src_box, &error));
+ }
+
+ /* Open move box if necessary */
+
+ if (execute && discard_action == SIEVE_FILTER_DACT_MOVE &&
+ move_mailbox != NULL) {
+ ns = mail_namespace_find(mail_user->namespaces, move_mailbox);
+ if (ns == NULL)
+ i_fatal("Unknown namespace for mailbox '%s'",
+ move_mailbox);
+
+ move_box = mailbox_alloc(ns->list, move_mailbox, open_flags);
+ if (mailbox_open(move_box) < 0) {
+ i_fatal("Couldn't open mailbox '%s': %s",
+ move_mailbox,
+ mailbox_get_last_internal_error(move_box, &error));
+ }
+
+ if (mailbox_backends_equal(src_box, move_box))
+ i_fatal("Source mailbox and mailbox for move action are identical.");
+ }
+
+ /* Compose script environment */
+ if (sieve_script_env_init(&scriptenv, mail_user, &errstr) < 0)
+ i_fatal("Failed to initialize script execution: %s", errstr);
+ scriptenv.mailbox_autocreate = FALSE;
+ scriptenv.default_mailbox = dst_mailbox;
+ scriptenv.result_amend_log_message = result_amend_log_message;
+
+ /* Compose filter context */
+ i_zero(&sfdata);
+ sfdata.senv = &scriptenv;
+ sfdata.discard_action = discard_action;
+ sfdata.move_mailbox = move_box;
+ sfdata.main_sbin = main_sbin;
+ sfdata.ehandler = ehandler;
+ sfdata.execute = execute;
+ sfdata.source_write = source_write;
+ sfdata.default_move = default_move;
+
+ /* Apply Sieve filter to all messages found */
+ (void)filter_mailbox(&sfdata, src_box);
+
+ /* Close the source mailbox */
+ if (src_box != NULL)
+ mailbox_free(&src_box);
+
+ /* Close the move mailbox */
+ if (move_box != NULL)
+ mailbox_free(&move_box);
+
+ /* Close the script binary */
+ if (main_sbin != NULL)
+ sieve_close(&main_sbin);
+
+ /* Cleanup error handler */
+ sieve_error_handler_unref(&ehandler);
+
+ sieve_tool_deinit(&sieve_tool);
+
+ return 0;
+}
diff --git a/pigeonhole/src/sieve-tools/sieve-test.c b/pigeonhole/src/sieve-tools/sieve-test.c
new file mode 100644
index 0000000..e7345be
--- /dev/null
+++ b/pigeonhole/src/sieve-tools/sieve-test.c
@@ -0,0 +1,515 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "lib-signals.h"
+#include "ioloop.h"
+#include "env-util.h"
+#include "str.h"
+#include "ostream.h"
+#include "array.h"
+#include "mail-namespace.h"
+#include "mail-storage.h"
+#include "master-service.h"
+#include "master-service-settings.h"
+#include "mail-storage-service.h"
+
+#include "sieve.h"
+#include "sieve-binary.h"
+#include "sieve-extensions.h"
+
+#include "sieve-tool.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <sysexits.h>
+
+
+/*
+ * Configuration
+ */
+
+#define DEFAULT_SENDMAIL_PATH "/usr/lib/sendmail"
+
+/*
+ * Print help
+ */
+
+static void print_help(void)
+{
+ printf(
+"Usage: sieve-test [-a <orig-recipient-address] [-c <config-file>]\n"
+" [-C] [-D] [-d <dump-filename>] [-e]\n"
+" [-f <envelope-sender>] [-l <mail-location>]\n"
+" [-m <default-mailbox>] [-P <plugin>]\n"
+" [-r <recipient-address>] [-s <script-file>]\n"
+" [-t <trace-file>] [-T <trace-option>] [-x <extensions>]\n"
+" <script-file> <mail-file>\n"
+ );
+}
+
+/*
+ * Dummy SMTP session
+ */
+
+static void *
+sieve_smtp_start(const struct sieve_script_env *senv ATTR_UNUSED,
+ const struct smtp_address *mail_from)
+{
+ struct ostream *output;
+
+ i_info("sending message from <%s>:", smtp_address_encode(mail_from));
+
+ output = o_stream_create_fd(STDOUT_FILENO, (size_t)-1);
+ o_stream_set_no_error_handling(output, TRUE);
+ return (void*)output;
+}
+
+static void
+sieve_smtp_add_rcpt(const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle ATTR_UNUSED,
+ const struct smtp_address *rcpt_to)
+{
+ printf("\nRECIPIENT: %s\n", smtp_address_encode(rcpt_to));
+}
+
+static struct ostream *
+sieve_smtp_send(const struct sieve_script_env *senv ATTR_UNUSED, void *handle)
+{
+ printf("START MESSAGE:\n");
+
+ return (struct ostream *)handle;
+}
+
+static void
+sieve_smtp_abort(const struct sieve_script_env *senv ATTR_UNUSED, void *handle)
+{
+ struct ostream *output = (struct ostream *)handle;
+
+ printf("#### ABORT MESSAGE ####\n\n");
+ o_stream_unref(&output);
+}
+
+static int
+sieve_smtp_finish(const struct sieve_script_env *senv ATTR_UNUSED, void *handle,
+ const char **error_r ATTR_UNUSED)
+{
+ struct ostream *output = (struct ostream *)handle;
+
+ printf("END MESSAGE\n\n");
+ o_stream_unref(&output);
+ return 1;
+}
+
+/*
+ * Dummy duplicate check implementation
+ */
+
+static void *
+duplicate_transaction_begin(const struct sieve_script_env *senv ATTR_UNUSED)
+{
+ return NULL;
+}
+
+static void duplicate_transaction_commit(void **_dup_trans ATTR_UNUSED)
+{
+}
+
+static void duplicate_transaction_rollback(void **_dup_trans ATTR_UNUSED)
+{
+}
+
+static int
+duplicate_check(void *_dup_trans ATTR_UNUSED,
+ const struct sieve_script_env *senv,
+ const void *id ATTR_UNUSED, size_t id_size ATTR_UNUSED)
+{
+ i_info("checked duplicate for user %s.\n", senv->user->username);
+ return 0;
+}
+
+static void
+duplicate_mark(void *_dup_trans ATTR_UNUSED,
+ const struct sieve_script_env *senv,
+ const void *id ATTR_UNUSED, size_t id_size ATTR_UNUSED,
+ time_t time ATTR_UNUSED)
+{
+ i_info("marked duplicate for user %s.\n", senv->user->username);
+}
+
+/*
+ * Result logging
+ */
+
+static const char *
+result_amend_log_message(const struct sieve_script_env *senv,
+ enum log_type log_type, const char *message)
+{
+ const struct sieve_message_data *msgdata = senv->script_context;
+ string_t *str;
+
+ if (log_type == LOG_TYPE_DEBUG)
+ return message;
+
+ str = t_str_new(256);
+ str_printfa(str, "msgid=%s", (msgdata->id == NULL ?
+ "unspecified" : msgdata->id));
+ str_append(str, ": ");
+ str_append(str, message);
+
+ return str_c(str);
+}
+
+/*
+ * Tool implementation
+ */
+
+int main(int argc, char **argv)
+{
+ struct sieve_instance *svinst;
+ ARRAY_TYPE (const_string) scriptfiles;
+ const char *scriptfile, *mailbox, *dumpfile, *tracefile, *mailfile,
+ *mailloc, *errstr;
+ struct smtp_address *rcpt_to, *final_rcpt_to, *mail_from;
+ struct sieve_trace_config trace_config;
+ struct mail *mail;
+ struct sieve_binary *main_sbin, *sbin = NULL;
+ struct sieve_message_data msgdata;
+ struct sieve_script_env scriptenv;
+ struct sieve_exec_status estatus;
+ enum sieve_execute_flags exflags = SIEVE_EXECUTE_FLAG_LOG_RESULT;
+ struct sieve_error_handler *ehandler;
+ struct ostream *teststream = NULL;
+ struct sieve_trace_log *trace_log = NULL;
+ bool force_compile = FALSE, execute = FALSE;
+ int exit_status = EXIT_SUCCESS;
+ int ret, c;
+
+ sieve_tool = sieve_tool_init("sieve-test", &argc, &argv,
+ "r:a:f:m:d:l:s:eCt:T:DP:x:u:", FALSE);
+
+ ehandler = NULL;
+ t_array_init(&scriptfiles, 16);
+
+ /* Parse arguments */
+ mailbox = dumpfile = tracefile = mailloc = NULL;
+ mail_from = final_rcpt_to = rcpt_to = NULL;
+ i_zero(&trace_config);
+ trace_config.level = SIEVE_TRLVL_ACTIONS;
+ while ((c = sieve_tool_getopt(sieve_tool)) > 0) {
+ switch (c) {
+ case 'r':
+ /* final recipient address */
+ if (smtp_address_parse_mailbox(
+ pool_datastack_create(), optarg,
+ SMTP_ADDRESS_PARSE_FLAG_ALLOW_LOCALPART,
+ &final_rcpt_to, &errstr) < 0)
+ i_fatal("Invalid -r parameter: %s", errstr);
+ break;
+ case 'a':
+ /* original recipient address */
+ if (smtp_address_parse_mailbox(
+ pool_datastack_create(), optarg,
+ SMTP_ADDRESS_PARSE_FLAG_ALLOW_LOCALPART,
+ &rcpt_to, &errstr) < 0)
+ i_fatal("Invalid -a parameter: %s", errstr);
+ break;
+ case 'f':
+ /* envelope sender address */
+ if (smtp_address_parse_mailbox(
+ pool_datastack_create(), optarg,
+ 0, &mail_from, &errstr) < 0)
+ i_fatal("Invalid -f parameter: %s", errstr);
+ break;
+ case 'm':
+ /* default mailbox (keep box) */
+ mailbox = optarg;
+ break;
+ case 'l':
+ /* mail location */
+ mailloc = optarg;
+ break;
+ case 't':
+ /* trace file */
+ tracefile = optarg;
+ break;
+ /* trace options */
+ case 'T':
+ sieve_tool_parse_trace_option(&trace_config, optarg);
+ break;
+ case 'd':
+ /* dump file */
+ dumpfile = optarg;
+ break;
+ case 's':
+ /* scriptfile executed before main script */
+ {
+ const char *file;
+
+ file = t_strdup(optarg);
+ array_append(&scriptfiles, &file, 1);
+ }
+ break;
+ /* execution mode */
+ case 'e':
+ execute = TRUE;
+ break;
+ /* force script compile */
+ case 'C':
+ force_compile = TRUE;
+ break;
+ default:
+ /* unrecognized option */
+ print_help();
+ i_fatal_status(EX_USAGE, "Unknown argument: %c", c);
+ break;
+ }
+ }
+
+ if (optind < argc)
+ scriptfile = argv[optind++];
+ else {
+ print_help();
+ i_fatal_status(EX_USAGE, "Missing <script-file> argument");
+ }
+
+ if (optind < argc)
+ mailfile = argv[optind++];
+ else {
+ print_help();
+ i_fatal_status(EX_USAGE, "Missing <mail-file> argument");
+ }
+
+ if (optind != argc) {
+ print_help();
+ i_fatal_status(EX_USAGE, "Unknown argument: %s", argv[optind]);
+ }
+
+ /* Finish tool initialization */
+ svinst = sieve_tool_init_finish(sieve_tool, mailloc == NULL, FALSE);
+
+ /* Enable debug extension */
+ sieve_enable_debug_extension(svinst);
+
+ /* Create error handler */
+ ehandler = sieve_stderr_ehandler_create(svinst, 0);
+ sieve_error_handler_accept_infolog(ehandler, TRUE);
+ sieve_error_handler_accept_debuglog(ehandler, svinst->debug);
+
+ /* Compile main sieve script */
+ if (force_compile) {
+ main_sbin = sieve_tool_script_compile(svinst, scriptfile, NULL);
+ if (main_sbin != NULL)
+ (void)sieve_save(main_sbin, TRUE, NULL);
+ } else {
+ main_sbin = sieve_tool_script_open(svinst, scriptfile);
+ }
+
+ if (main_sbin == NULL) {
+ exit_status = EXIT_FAILURE;
+ } else {
+ /* Dump script */
+ sieve_tool_dump_binary_to(main_sbin, dumpfile, FALSE);
+
+ /* Obtain mail namespaces from -l argument */
+ if (mailloc != NULL)
+ sieve_tool_init_mail_user(sieve_tool, mailloc);
+
+ /* Initialize raw mail object */
+ mail = sieve_tool_open_file_as_mail(sieve_tool, mailfile);
+
+ if (mailbox == NULL)
+ mailbox = "INBOX";
+
+ /* Collect necessary message data */
+ i_zero(&msgdata);
+ msgdata.mail = mail;
+ msgdata.auth_user = sieve_tool_get_username(sieve_tool);
+ (void)mail_get_message_id(mail, &msgdata.id);
+
+ sieve_tool_get_envelope_data(&msgdata, mail,
+ mail_from, rcpt_to, final_rcpt_to);
+
+ /* Create streams for test and trace output */
+
+ if (!execute) {
+ teststream = o_stream_create_fd(1, 0);
+ o_stream_set_no_error_handling(teststream, TRUE);
+ }
+
+ if (tracefile != NULL) {
+ (void)sieve_trace_log_create(
+ svinst, (strcmp(tracefile, "-") == 0 ?
+ NULL : tracefile), &trace_log);
+ }
+
+ /* Compose script environment */
+ if (sieve_script_env_init(
+ &scriptenv, sieve_tool_get_mail_user(sieve_tool),
+ &errstr) < 0) {
+ i_fatal("Failed to initialize script execution: %s",
+ errstr);
+ }
+
+ scriptenv.default_mailbox = mailbox;
+ scriptenv.smtp_start = sieve_smtp_start;
+ scriptenv.smtp_add_rcpt = sieve_smtp_add_rcpt;
+ scriptenv.smtp_send = sieve_smtp_send;
+ scriptenv.smtp_abort = sieve_smtp_abort;
+ scriptenv.smtp_finish = sieve_smtp_finish;
+ scriptenv.duplicate_transaction_begin =
+ duplicate_transaction_begin;
+ scriptenv.duplicate_transaction_commit =
+ duplicate_transaction_commit;
+ scriptenv.duplicate_transaction_rollback =
+ duplicate_transaction_rollback;
+ scriptenv.duplicate_mark = duplicate_mark;
+ scriptenv.duplicate_check = duplicate_check;
+ scriptenv.result_amend_log_message = result_amend_log_message;
+ scriptenv.trace_log = trace_log;
+ scriptenv.trace_config = trace_config;
+ scriptenv.script_context = &msgdata;
+
+ i_zero(&estatus);
+ scriptenv.exec_status = &estatus;
+
+ /* Run the test */
+ ret = 1;
+ if (array_count(&scriptfiles) == 0) {
+ /* Single script */
+ sbin = main_sbin;
+ main_sbin = NULL;
+
+ /* Execute/Test script */
+ if (execute) {
+ ret = sieve_execute(sbin, &msgdata, &scriptenv,
+ ehandler, ehandler,
+ exflags);
+ } else {
+ ret = sieve_test(sbin, &msgdata, &scriptenv,
+ ehandler, teststream, exflags);
+ }
+ } else {
+ /* Multiple scripts */
+ const char *const *sfiles;
+ unsigned int i, count;
+ struct sieve_multiscript *mscript;
+ bool more = TRUE;
+
+ if (execute)
+ mscript = sieve_multiscript_start_execute(
+ svinst, &msgdata, &scriptenv);
+ else
+ mscript = sieve_multiscript_start_test(
+ svinst, &msgdata, &scriptenv,
+ teststream);
+
+ /* Execute scripts sequentially */
+ sfiles = array_get(&scriptfiles, &count);
+ for (i = 0; i < count && more; i++) {
+ if (teststream != NULL) {
+ o_stream_nsend_str(
+ teststream,
+ t_strdup_printf("\n## Executing script: %s\n",
+ sfiles[i]));
+ }
+
+ /* Close previous script */
+ if (sbin != NULL)
+ sieve_close(&sbin);
+
+ /* Compile sieve script */
+ if (force_compile) {
+ sbin = sieve_tool_script_compile(
+ svinst, sfiles[i], sfiles[i]);
+ if (sbin != NULL)
+ (void)sieve_save(sbin, FALSE, NULL);
+ } else {
+ sbin = sieve_tool_script_open(svinst, sfiles[i]);
+ }
+
+ if (sbin == NULL) {
+ ret = SIEVE_EXEC_FAILURE;
+ break;
+ }
+
+ /* Execute/Test script */
+ more = sieve_multiscript_run(
+ mscript, sbin, ehandler, ehandler,
+ exflags);
+ }
+
+ /* Execute/Test main script */
+ if (more && ret > 0) {
+ if (teststream != NULL) {
+ o_stream_nsend_str(
+ teststream,
+ t_strdup_printf("## Executing script: %s\n",
+ scriptfile));
+ }
+
+ /* Close previous script */
+ if (sbin != NULL)
+ sieve_close(&sbin);
+
+ sbin = main_sbin;
+ main_sbin = NULL;
+
+ (void)sieve_multiscript_run(
+ mscript, sbin, ehandler, ehandler,
+ exflags);
+ }
+
+ ret = sieve_multiscript_finish(&mscript, ehandler,
+ exflags, ret);
+ }
+
+ /* Run */
+ switch (ret) {
+ case SIEVE_EXEC_OK:
+ i_info("final result: success");
+ break;
+ case SIEVE_EXEC_RESOURCE_LIMIT:
+ i_info("resource limit exceeded");
+ exit_status = EXIT_FAILURE;
+ break;
+ case SIEVE_EXEC_BIN_CORRUPT:
+ i_info("corrupt binary deleted.");
+ i_unlink_if_exists(sieve_binary_path(sbin));
+ /* fall through */
+ case SIEVE_EXEC_FAILURE:
+ i_info("final result: failed; "
+ "resolved with successful implicit keep");
+ exit_status = EXIT_FAILURE;
+ break;
+ case SIEVE_EXEC_TEMP_FAILURE:
+ i_info("final result: temporary failure");
+ exit_status = EXIT_FAILURE;
+ break;
+ case SIEVE_EXEC_KEEP_FAILED:
+ i_info("final result: utter failure");
+ exit_status = EXIT_FAILURE;
+ break;
+ }
+
+ if (teststream != NULL)
+ o_stream_destroy(&teststream);
+ if (trace_log != NULL)
+ sieve_trace_log_free(&trace_log);
+
+ /* Cleanup remaining binaries */
+ if (sbin != NULL)
+ sieve_close(&sbin);
+ if (main_sbin != NULL)
+ sieve_close(&main_sbin);
+ }
+
+ /* Cleanup error handler */
+ sieve_error_handler_unref(&ehandler);
+
+ sieve_tool_deinit(&sieve_tool);
+
+ return exit_status;
+}
diff --git a/pigeonhole/src/sieve-tools/sievec.c b/pigeonhole/src/sieve-tools/sievec.c
new file mode 100644
index 0000000..d70435d
--- /dev/null
+++ b/pigeonhole/src/sieve-tools/sievec.c
@@ -0,0 +1,157 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "master-service.h"
+#include "master-service-settings.h"
+#include "mail-storage-service.h"
+#include "mail-user.h"
+
+#include "sieve.h"
+#include "sieve-extensions.h"
+#include "sieve-script.h"
+#include "sieve-tool.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <sysexits.h>
+
+/*
+ * Print help
+ */
+
+static void print_help(void)
+{
+ printf(
+"Usage: sievec [-c <config-file>] [-d] [-D] [-P <plugin>] [-x <extensions>] \n"
+" <script-file> [<out-file>]\n"
+ );
+}
+
+/*
+ * Tool implementation
+ */
+
+int main(int argc, char **argv)
+{
+ struct sieve_instance *svinst;
+ struct stat st;
+ struct sieve_binary *sbin;
+ bool dump = FALSE;
+ const char *scriptfile, *outfile;
+ int exit_status = EXIT_SUCCESS;
+ int c;
+
+ sieve_tool = sieve_tool_init("sievec", &argc, &argv, "DdP:x:u:", FALSE);
+
+ outfile = NULL;
+ while ((c = sieve_tool_getopt(sieve_tool)) > 0) {
+ switch (c) {
+ case 'd':
+ /* dump file */
+ dump = TRUE;
+ break;
+ default:
+ print_help();
+ i_fatal_status(EX_USAGE, "Unknown argument: %c", c);
+ break;
+ }
+ }
+
+ if ( optind < argc ) {
+ scriptfile = argv[optind++];
+ } else {
+ print_help();
+ i_fatal_status(EX_USAGE, "Missing <script-file> argument");
+ }
+
+ if ( optind < argc ) {
+ outfile = argv[optind++];
+ } else if ( dump ) {
+ outfile = "-";
+ }
+
+ svinst = sieve_tool_init_finish(sieve_tool, FALSE, TRUE);
+
+ /* Enable debug extension */
+ sieve_enable_debug_extension(svinst);
+
+ if ( stat(scriptfile, &st) == 0 && S_ISDIR(st.st_mode) ) {
+ /* Script directory */
+ DIR *dirp;
+ struct dirent *dp;
+
+ /* Sanity checks on some of the arguments */
+
+ if ( dump )
+ i_fatal_status(EX_USAGE,
+ "the -d option is not allowed when scriptfile is a directory.");
+
+ if ( outfile != NULL )
+ i_fatal_status(EX_USAGE,
+ "the outfile argument is not allowed when scriptfile is a directory.");
+
+ /* Open the directory */
+ if ( (dirp = opendir(scriptfile)) == NULL )
+ i_fatal("opendir(%s) failed: %m", scriptfile);
+
+ /* Compile each sieve file */
+ for (;;) {
+
+ errno = 0;
+ if ( (dp = readdir(dirp)) == NULL ) {
+ if ( errno != 0 )
+ i_fatal("readdir(%s) failed: %m", scriptfile);
+ break;
+ }
+
+ if ( sieve_script_file_has_extension(dp->d_name) ) {
+ const char *file;
+
+ if ( scriptfile[strlen(scriptfile)-1] == '/' )
+ file = t_strconcat(scriptfile, dp->d_name, NULL);
+ else
+ file = t_strconcat(scriptfile, "/", dp->d_name, NULL);
+
+ sbin = sieve_tool_script_compile(svinst, file, NULL);
+
+ if ( sbin != NULL ) {
+ sieve_save(sbin, TRUE, NULL);
+ sieve_close(&sbin);
+ }
+ }
+ }
+
+ /* Close the directory */
+ if ( closedir(dirp) < 0 )
+ i_fatal("closedir(%s) failed: %m", scriptfile);
+ } else {
+ /* Script file (i.e. not a directory)
+ *
+ * NOTE: For consistency, stat errors are handled here as well
+ */
+ sbin = sieve_tool_script_compile(svinst, scriptfile, NULL);
+
+ if ( sbin != NULL ) {
+ if ( dump )
+ sieve_tool_dump_binary_to(sbin, outfile, FALSE);
+ else {
+ sieve_save_as(sbin, outfile, TRUE, 0600, NULL);
+ }
+
+ sieve_close(&sbin);
+ } else {
+ exit_status = EXIT_FAILURE;
+ }
+ }
+
+ sieve_tool_deinit(&sieve_tool);
+
+ return exit_status;
+}
diff --git a/pigeonhole/src/testsuite/Makefile.am b/pigeonhole/src/testsuite/Makefile.am
new file mode 100644
index 0000000..f7b85dc
--- /dev/null
+++ b/pigeonhole/src/testsuite/Makefile.am
@@ -0,0 +1,74 @@
+noinst_PROGRAMS = testsuite
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib-sieve \
+ -I$(top_srcdir)/src/lib-sieve/util \
+ -I$(top_srcdir)/src/lib-sieve/plugins/variables \
+ -I$(top_srcdir)/src/lib-sieve-tool \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_SERVICE_INCLUDE)
+
+testsuite_LDFLAGS = -export-dynamic
+
+libs = \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la \
+ $(top_builddir)/src/lib-sieve-tool/libsieve-tool.la
+
+testsuite_LDADD = $(libs) $(LIBDOVECOT_STORAGE) $(LIBDOVECOT_LDA) $(LIBDOVECOT)
+testsuite_DEPENDENCIES = $(libs) $(LIBDOVECOT_STORAGE_DEPS) $(LIBDOVECOT_LDA_DEPS) $(LIBDOVECOT_DEPS)
+
+commands = \
+ cmd-test.c \
+ cmd-test-fail.c \
+ cmd-test-config.c \
+ cmd-test-set.c \
+ cmd-test-result.c \
+ cmd-test-message.c \
+ cmd-test-mailbox.c \
+ cmd-test-binary.c \
+ cmd-test-imap-metadata.c
+
+tests = \
+ tst-test-script-compile.c \
+ tst-test-script-run.c \
+ tst-test-multiscript.c \
+ tst-test-error.c \
+ tst-test-result-action.c \
+ tst-test-result-execute.c
+
+testsuite_SOURCES = \
+ testsuite-common.c \
+ testsuite-settings.c \
+ testsuite-objects.c \
+ testsuite-substitutions.c \
+ testsuite-variables.c \
+ testsuite-arguments.c \
+ testsuite-message.c \
+ testsuite-log.c \
+ testsuite-script.c \
+ testsuite-result.c \
+ testsuite-smtp.c \
+ testsuite-mailstore.c \
+ testsuite-binary.c \
+ $(commands) \
+ $(tests) \
+ ext-testsuite.c \
+ testsuite.c
+
+noinst_HEADERS = \
+ testsuite-common.h \
+ testsuite-settings.h \
+ testsuite-objects.h \
+ testsuite-substitutions.h \
+ testsuite-variables.h \
+ testsuite-arguments.h \
+ testsuite-message.h \
+ testsuite-log.h \
+ testsuite-script.h \
+ testsuite-result.h \
+ testsuite-smtp.h \
+ testsuite-mailstore.h \
+ testsuite-binary.h
+
+clean-local:
+ -rm -rf test.out.*
diff --git a/pigeonhole/src/testsuite/Makefile.in b/pigeonhole/src/testsuite/Makefile.in
new file mode 100644
index 0000000..1f9043f
--- /dev/null
+++ b/pigeonhole/src/testsuite/Makefile.in
@@ -0,0 +1,869 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+noinst_PROGRAMS = testsuite$(EXEEXT)
+subdir = src/testsuite
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/dummy-config.h \
+ $(top_builddir)/pigeonhole-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+PROGRAMS = $(noinst_PROGRAMS)
+am__objects_1 = cmd-test.$(OBJEXT) cmd-test-fail.$(OBJEXT) \
+ cmd-test-config.$(OBJEXT) cmd-test-set.$(OBJEXT) \
+ cmd-test-result.$(OBJEXT) cmd-test-message.$(OBJEXT) \
+ cmd-test-mailbox.$(OBJEXT) cmd-test-binary.$(OBJEXT) \
+ cmd-test-imap-metadata.$(OBJEXT)
+am__objects_2 = tst-test-script-compile.$(OBJEXT) \
+ tst-test-script-run.$(OBJEXT) tst-test-multiscript.$(OBJEXT) \
+ tst-test-error.$(OBJEXT) tst-test-result-action.$(OBJEXT) \
+ tst-test-result-execute.$(OBJEXT)
+am_testsuite_OBJECTS = testsuite-common.$(OBJEXT) \
+ testsuite-settings.$(OBJEXT) testsuite-objects.$(OBJEXT) \
+ testsuite-substitutions.$(OBJEXT) \
+ testsuite-variables.$(OBJEXT) testsuite-arguments.$(OBJEXT) \
+ testsuite-message.$(OBJEXT) testsuite-log.$(OBJEXT) \
+ testsuite-script.$(OBJEXT) testsuite-result.$(OBJEXT) \
+ testsuite-smtp.$(OBJEXT) testsuite-mailstore.$(OBJEXT) \
+ testsuite-binary.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
+ ext-testsuite.$(OBJEXT) testsuite.$(OBJEXT)
+testsuite_OBJECTS = $(am_testsuite_OBJECTS)
+am__DEPENDENCIES_1 =
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+testsuite_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(testsuite_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cmd-test-binary.Po \
+ ./$(DEPDIR)/cmd-test-config.Po ./$(DEPDIR)/cmd-test-fail.Po \
+ ./$(DEPDIR)/cmd-test-imap-metadata.Po \
+ ./$(DEPDIR)/cmd-test-mailbox.Po \
+ ./$(DEPDIR)/cmd-test-message.Po ./$(DEPDIR)/cmd-test-result.Po \
+ ./$(DEPDIR)/cmd-test-set.Po ./$(DEPDIR)/cmd-test.Po \
+ ./$(DEPDIR)/ext-testsuite.Po \
+ ./$(DEPDIR)/testsuite-arguments.Po \
+ ./$(DEPDIR)/testsuite-binary.Po \
+ ./$(DEPDIR)/testsuite-common.Po ./$(DEPDIR)/testsuite-log.Po \
+ ./$(DEPDIR)/testsuite-mailstore.Po \
+ ./$(DEPDIR)/testsuite-message.Po \
+ ./$(DEPDIR)/testsuite-objects.Po \
+ ./$(DEPDIR)/testsuite-result.Po \
+ ./$(DEPDIR)/testsuite-script.Po \
+ ./$(DEPDIR)/testsuite-settings.Po \
+ ./$(DEPDIR)/testsuite-smtp.Po \
+ ./$(DEPDIR)/testsuite-substitutions.Po \
+ ./$(DEPDIR)/testsuite-variables.Po ./$(DEPDIR)/testsuite.Po \
+ ./$(DEPDIR)/tst-test-error.Po \
+ ./$(DEPDIR)/tst-test-multiscript.Po \
+ ./$(DEPDIR)/tst-test-result-action.Po \
+ ./$(DEPDIR)/tst-test-result-execute.Po \
+ ./$(DEPDIR)/tst-test-script-compile.Po \
+ ./$(DEPDIR)/tst-test-script-run.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(testsuite_SOURCES)
+DIST_SOURCES = $(testsuite_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@
+DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@
+DOVECOT_CFLAGS = @DOVECOT_CFLAGS@
+DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@
+DOVECOT_INSTALLED = @DOVECOT_INSTALLED@
+DOVECOT_LIBS = @DOVECOT_LIBS@
+DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@
+DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@
+DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@
+DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@
+LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@
+LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@
+LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@
+LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@
+LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@
+LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@
+LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@
+LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@
+LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@
+LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@
+LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@
+LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@
+LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@
+LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@
+LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@
+LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@
+LIBDOVECOT_SSL = @LIBDOVECOT_SSL@
+LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@
+LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dovecot_docdir = @dovecot_docdir@
+dovecot_installed_moduledir = @dovecot_installed_moduledir@
+dovecot_moduledir = @dovecot_moduledir@
+dovecot_pkgincludedir = @dovecot_pkgincludedir@
+dovecot_pkglibdir = @dovecot_pkglibdir@
+dovecot_pkglibexecdir = @dovecot_pkglibexecdir@
+dovecot_statedir = @dovecot_statedir@
+dovecotdir = @dovecotdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sieve_docdir = @sieve_docdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib-sieve \
+ -I$(top_srcdir)/src/lib-sieve/util \
+ -I$(top_srcdir)/src/lib-sieve/plugins/variables \
+ -I$(top_srcdir)/src/lib-sieve-tool \
+ $(LIBDOVECOT_INCLUDE) \
+ $(LIBDOVECOT_SERVICE_INCLUDE)
+
+testsuite_LDFLAGS = -export-dynamic
+libs = \
+ $(top_builddir)/src/lib-sieve/libdovecot-sieve.la \
+ $(top_builddir)/src/lib-sieve-tool/libsieve-tool.la
+
+testsuite_LDADD = $(libs) $(LIBDOVECOT_STORAGE) $(LIBDOVECOT_LDA) $(LIBDOVECOT)
+testsuite_DEPENDENCIES = $(libs) $(LIBDOVECOT_STORAGE_DEPS) $(LIBDOVECOT_LDA_DEPS) $(LIBDOVECOT_DEPS)
+commands = \
+ cmd-test.c \
+ cmd-test-fail.c \
+ cmd-test-config.c \
+ cmd-test-set.c \
+ cmd-test-result.c \
+ cmd-test-message.c \
+ cmd-test-mailbox.c \
+ cmd-test-binary.c \
+ cmd-test-imap-metadata.c
+
+tests = \
+ tst-test-script-compile.c \
+ tst-test-script-run.c \
+ tst-test-multiscript.c \
+ tst-test-error.c \
+ tst-test-result-action.c \
+ tst-test-result-execute.c
+
+testsuite_SOURCES = \
+ testsuite-common.c \
+ testsuite-settings.c \
+ testsuite-objects.c \
+ testsuite-substitutions.c \
+ testsuite-variables.c \
+ testsuite-arguments.c \
+ testsuite-message.c \
+ testsuite-log.c \
+ testsuite-script.c \
+ testsuite-result.c \
+ testsuite-smtp.c \
+ testsuite-mailstore.c \
+ testsuite-binary.c \
+ $(commands) \
+ $(tests) \
+ ext-testsuite.c \
+ testsuite.c
+
+noinst_HEADERS = \
+ testsuite-common.h \
+ testsuite-settings.h \
+ testsuite-objects.h \
+ testsuite-substitutions.h \
+ testsuite-variables.h \
+ testsuite-arguments.h \
+ testsuite-message.h \
+ testsuite-log.h \
+ testsuite-script.h \
+ testsuite-result.h \
+ testsuite-smtp.h \
+ testsuite-mailstore.h \
+ testsuite-binary.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/testsuite/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/testsuite/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+testsuite$(EXEEXT): $(testsuite_OBJECTS) $(testsuite_DEPENDENCIES) $(EXTRA_testsuite_DEPENDENCIES)
+ @rm -f testsuite$(EXEEXT)
+ $(AM_V_CCLD)$(testsuite_LINK) $(testsuite_OBJECTS) $(testsuite_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-test-binary.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-test-config.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-test-fail.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-test-imap-metadata.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-test-mailbox.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-test-message.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-test-result.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-test-set.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-testsuite.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testsuite-arguments.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testsuite-binary.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testsuite-common.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testsuite-log.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testsuite-mailstore.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testsuite-message.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testsuite-objects.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testsuite-result.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testsuite-script.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testsuite-settings.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testsuite-smtp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testsuite-substitutions.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testsuite-variables.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testsuite.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-test-error.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-test-multiscript.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-test-result-action.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-test-result-execute.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-test-script-compile.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-test-script-run.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local clean-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/cmd-test-binary.Po
+ -rm -f ./$(DEPDIR)/cmd-test-config.Po
+ -rm -f ./$(DEPDIR)/cmd-test-fail.Po
+ -rm -f ./$(DEPDIR)/cmd-test-imap-metadata.Po
+ -rm -f ./$(DEPDIR)/cmd-test-mailbox.Po
+ -rm -f ./$(DEPDIR)/cmd-test-message.Po
+ -rm -f ./$(DEPDIR)/cmd-test-result.Po
+ -rm -f ./$(DEPDIR)/cmd-test-set.Po
+ -rm -f ./$(DEPDIR)/cmd-test.Po
+ -rm -f ./$(DEPDIR)/ext-testsuite.Po
+ -rm -f ./$(DEPDIR)/testsuite-arguments.Po
+ -rm -f ./$(DEPDIR)/testsuite-binary.Po
+ -rm -f ./$(DEPDIR)/testsuite-common.Po
+ -rm -f ./$(DEPDIR)/testsuite-log.Po
+ -rm -f ./$(DEPDIR)/testsuite-mailstore.Po
+ -rm -f ./$(DEPDIR)/testsuite-message.Po
+ -rm -f ./$(DEPDIR)/testsuite-objects.Po
+ -rm -f ./$(DEPDIR)/testsuite-result.Po
+ -rm -f ./$(DEPDIR)/testsuite-script.Po
+ -rm -f ./$(DEPDIR)/testsuite-settings.Po
+ -rm -f ./$(DEPDIR)/testsuite-smtp.Po
+ -rm -f ./$(DEPDIR)/testsuite-substitutions.Po
+ -rm -f ./$(DEPDIR)/testsuite-variables.Po
+ -rm -f ./$(DEPDIR)/testsuite.Po
+ -rm -f ./$(DEPDIR)/tst-test-error.Po
+ -rm -f ./$(DEPDIR)/tst-test-multiscript.Po
+ -rm -f ./$(DEPDIR)/tst-test-result-action.Po
+ -rm -f ./$(DEPDIR)/tst-test-result-execute.Po
+ -rm -f ./$(DEPDIR)/tst-test-script-compile.Po
+ -rm -f ./$(DEPDIR)/tst-test-script-run.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/cmd-test-binary.Po
+ -rm -f ./$(DEPDIR)/cmd-test-config.Po
+ -rm -f ./$(DEPDIR)/cmd-test-fail.Po
+ -rm -f ./$(DEPDIR)/cmd-test-imap-metadata.Po
+ -rm -f ./$(DEPDIR)/cmd-test-mailbox.Po
+ -rm -f ./$(DEPDIR)/cmd-test-message.Po
+ -rm -f ./$(DEPDIR)/cmd-test-result.Po
+ -rm -f ./$(DEPDIR)/cmd-test-set.Po
+ -rm -f ./$(DEPDIR)/cmd-test.Po
+ -rm -f ./$(DEPDIR)/ext-testsuite.Po
+ -rm -f ./$(DEPDIR)/testsuite-arguments.Po
+ -rm -f ./$(DEPDIR)/testsuite-binary.Po
+ -rm -f ./$(DEPDIR)/testsuite-common.Po
+ -rm -f ./$(DEPDIR)/testsuite-log.Po
+ -rm -f ./$(DEPDIR)/testsuite-mailstore.Po
+ -rm -f ./$(DEPDIR)/testsuite-message.Po
+ -rm -f ./$(DEPDIR)/testsuite-objects.Po
+ -rm -f ./$(DEPDIR)/testsuite-result.Po
+ -rm -f ./$(DEPDIR)/testsuite-script.Po
+ -rm -f ./$(DEPDIR)/testsuite-settings.Po
+ -rm -f ./$(DEPDIR)/testsuite-smtp.Po
+ -rm -f ./$(DEPDIR)/testsuite-substitutions.Po
+ -rm -f ./$(DEPDIR)/testsuite-variables.Po
+ -rm -f ./$(DEPDIR)/testsuite.Po
+ -rm -f ./$(DEPDIR)/tst-test-error.Po
+ -rm -f ./$(DEPDIR)/tst-test-multiscript.Po
+ -rm -f ./$(DEPDIR)/tst-test-result-action.Po
+ -rm -f ./$(DEPDIR)/tst-test-result-execute.Po
+ -rm -f ./$(DEPDIR)/tst-test-script-compile.Po
+ -rm -f ./$(DEPDIR)/tst-test-script-run.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-local clean-noinstPROGRAMS \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+clean-local:
+ -rm -rf test.out.*
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/pigeonhole/src/testsuite/cmd-test-binary.c b/pigeonhole/src/testsuite/cmd-test-binary.c
new file mode 100644
index 0000000..6f810bd
--- /dev/null
+++ b/pigeonhole/src/testsuite/cmd-test-binary.c
@@ -0,0 +1,208 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+
+#include "testsuite-common.h"
+#include "testsuite-binary.h"
+#include "testsuite-script.h"
+
+/*
+ * Commands
+ */
+
+static bool cmd_test_binary_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool cmd_test_binary_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+/* Test_binary_load command
+ *
+ * Syntax:
+ * test_binary_load <binary-name: string>
+ */
+
+const struct sieve_command_def cmd_test_binary_load = {
+ .identifier = "test_binary_load",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_test_binary_validate,
+ .generate = cmd_test_binary_generate
+};
+
+/* Test_binary_save command
+ *
+ * Syntax:
+ * test_binary_save <binary-name: string>
+ */
+
+const struct sieve_command_def cmd_test_binary_save = {
+ .identifier = "test_binary_save",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_test_binary_validate,
+ .generate = cmd_test_binary_generate,
+};
+
+/*
+ * Operations
+ */
+
+static bool cmd_test_binary_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int cmd_test_binary_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+/* test_binary_create operation */
+
+const struct sieve_operation_def test_binary_load_operation = {
+ .mnemonic = "TEST_BINARY_LOAD",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_BINARY_LOAD,
+ .dump = cmd_test_binary_operation_dump,
+ .execute = cmd_test_binary_operation_execute
+};
+
+/* test_binary_delete operation */
+
+const struct sieve_operation_def test_binary_save_operation = {
+ .mnemonic = "TEST_BINARY_SAVE",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_BINARY_SAVE,
+ .dump = cmd_test_binary_operation_dump,
+ .execute = cmd_test_binary_operation_execute
+};
+
+/*
+ * Validation
+ */
+
+static bool cmd_test_binary_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, cmd, arg, "binary-name", 1, SAAT_STRING) ) {
+ return FALSE;
+ }
+
+ return sieve_validator_argument_activate(valdtr, cmd, arg, FALSE);
+}
+
+/*
+ * Code generation
+ */
+
+static bool cmd_test_binary_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ /* Emit operation */
+ if ( sieve_command_is(cmd, cmd_test_binary_load) )
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &test_binary_load_operation);
+ else if ( sieve_command_is(cmd, cmd_test_binary_save) )
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &test_binary_save_operation);
+ else
+ i_unreached();
+
+ /* Generate arguments */
+ if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool cmd_test_binary_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "%s:", sieve_operation_mnemonic(denv->oprtn));
+
+ sieve_code_descend(denv);
+
+ return sieve_opr_string_dump(denv, address, "binary-name");
+}
+
+/*
+ * Intepretation
+ */
+
+static int cmd_test_binary_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ const struct sieve_operation *oprtn = renv->oprtn;
+ string_t *binary_name = NULL;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Binary Name */
+
+ if ( (ret=sieve_opr_string_read(renv, address, "binary-name", &binary_name))
+ <= 0 )
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ if ( sieve_operation_is(oprtn, test_binary_load_operation) ) {
+ struct sieve_binary *sbin = testsuite_binary_load(str_c(binary_name));
+
+ if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+ sieve_runtime_trace(renv, 0, "testsuite: test_binary_load command");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(renv, 0, "load binary `%s'", str_c(binary_name));
+ }
+
+ if ( sbin != NULL ) {
+ testsuite_script_set_binary(renv, sbin);
+
+ sieve_binary_unref(&sbin);
+ } else {
+ e_error(testsuite_sieve_instance->event,
+ "failed to load binary %s", str_c(binary_name));
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ } else if ( sieve_operation_is(oprtn, test_binary_save_operation) ) {
+ struct sieve_binary *sbin = testsuite_script_get_binary(renv);
+
+ if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+ sieve_runtime_trace(renv, 0, "testsuite: test_binary_save command");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(renv, 0, "save binary `%s'", str_c(binary_name));
+ }
+
+ if ( sbin != NULL )
+ testsuite_binary_save(sbin, str_c(binary_name));
+ else {
+ e_error(testsuite_sieve_instance->event,
+ "no compiled binary to save as %s",
+ str_c(binary_name));
+ return SIEVE_EXEC_FAILURE;
+ }
+ } else {
+ i_unreached();
+ }
+
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/testsuite/cmd-test-config.c b/pigeonhole/src/testsuite/cmd-test-config.c
new file mode 100644
index 0000000..c1399b0
--- /dev/null
+++ b/pigeonhole/src/testsuite/cmd-test-config.c
@@ -0,0 +1,504 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-settings.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+
+#include "testsuite-common.h"
+#include "testsuite-settings.h"
+
+/*
+ * Commands
+ */
+
+static bool
+cmd_test_config_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+/* Test_config_set command
+ *
+ * Syntax:
+ * test_config_set <setting: string> <value: string>
+ */
+
+static bool
+cmd_test_config_set_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd);
+
+const struct sieve_command_def cmd_test_config_set = {
+ .identifier = "test_config_set",
+ .type = SCT_COMMAND,
+ .positional_args = 2,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_test_config_set_validate,
+ .generate = cmd_test_config_generate
+};
+
+/* Test_config_unset command
+ *
+ * Syntax:
+ * test_config_unset <setting: string>
+ */
+
+static bool
+cmd_test_config_unset_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd);
+
+const struct sieve_command_def cmd_test_config_unset = {
+ .identifier = "test_config_unset",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_test_config_unset_validate,
+ .generate = cmd_test_config_generate,
+};
+
+/* Test_config_reload command
+ *
+ * Syntax:
+ * test_config_reload [:extension <extension: string>]
+ */
+
+static bool
+cmd_test_config_reload_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+
+const struct sieve_command_def cmd_test_config_reload = {
+ .identifier = "test_config_reload",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = cmd_test_config_reload_registered,
+ .generate = cmd_test_config_generate
+};
+
+/*
+ * Command tags
+ */
+
+/* Forward declarations */
+
+static bool
+cmd_test_config_reload_validate_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+/* Argument objects */
+
+static const struct sieve_argument_def test_config_reload_extension_tag = {
+ .identifier = "extension",
+ .validate = cmd_test_config_reload_validate_tag,
+};
+
+/* Codes for optional arguments */
+
+enum cmd_test_config_optional {
+ OPT_END,
+ OPT_EXTENSION
+};
+
+/*
+ * Operations
+ */
+
+/* Test_config_set operation */
+
+static bool
+cmd_test_config_set_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_test_config_set_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def test_config_set_operation = {
+ .mnemonic = "TEST_CONFIG_SET",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_CONFIG_SET,
+ .dump = cmd_test_config_set_operation_dump,
+ .execute = cmd_test_config_set_operation_execute
+};
+
+/* Test_config_unset operation */
+
+static bool
+cmd_test_config_unset_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_test_config_unset_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def test_config_unset_operation = {
+ .mnemonic = "TEST_CONFIG_UNSET",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_CONFIG_UNSET,
+ .dump = cmd_test_config_unset_operation_dump,
+ .execute = cmd_test_config_unset_operation_execute
+};
+
+/* Test_config_read operation */
+
+static bool
+cmd_test_config_reload_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_test_config_reload_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def test_config_reload_operation = {
+ .mnemonic = "TEST_CONFIG_RELOAD",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_CONFIG_RELOAD,
+ .dump = cmd_test_config_reload_operation_dump,
+ .execute = cmd_test_config_reload_operation_execute
+};
+
+/*
+ * Tag validation
+ */
+
+static bool
+cmd_test_config_reload_validate_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ /* Check syntax:
+ * :extension <extension: string>
+ */
+ if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0,
+ SAAT_STRING, TRUE))
+ return FALSE;
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+/*
+ * Command registration
+ */
+
+static bool
+cmd_test_config_reload_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &test_config_reload_extension_tag,
+ OPT_EXTENSION);
+ return TRUE;
+}
+
+/*
+ * Command validation
+ */
+
+static bool
+cmd_test_config_set_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+
+ /* Check syntax:
+ * <setting: string> <value: string>
+ */
+
+ if (!sieve_validate_positional_argument(valdtr, cmd, arg, "setting",
+ 1, SAAT_STRING))
+ return FALSE;
+
+ if (!sieve_validator_argument_activate(valdtr, cmd, arg, FALSE))
+ return FALSE;
+
+ arg = sieve_ast_argument_next(arg);
+
+ if (!sieve_validate_positional_argument(valdtr, cmd, arg, "value", 2,
+ SAAT_STRING))
+ return FALSE;
+
+ return sieve_validator_argument_activate(valdtr, cmd, arg, FALSE);
+}
+
+static bool
+cmd_test_config_unset_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+
+ /* Check syntax:
+ * <setting: string>
+ */
+ if (!sieve_validate_positional_argument(valdtr, cmd, arg, "setting", 1,
+ SAAT_STRING))
+ return FALSE;
+
+ return sieve_validator_argument_activate(valdtr, cmd, arg, FALSE);
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+cmd_test_config_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ if (sieve_command_is(cmd, cmd_test_config_set)) {
+ sieve_operation_emit(cgenv->sblock, cmd->ext,
+ &test_config_set_operation);
+ } else if (sieve_command_is(cmd, cmd_test_config_unset)) {
+ sieve_operation_emit(cgenv->sblock, cmd->ext,
+ &test_config_unset_operation);
+ } else if (sieve_command_is(cmd, cmd_test_config_reload)) {
+ sieve_operation_emit(cgenv->sblock, cmd->ext,
+ &test_config_reload_operation);
+ } else {
+ i_unreached();
+ }
+
+ /* Generate arguments */
+ if (!sieve_generate_arguments(cgenv, cmd, NULL))
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+cmd_test_config_set_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "TEST_CONFIG_SET:");
+
+ sieve_code_descend(denv);
+
+ return (sieve_opr_string_dump(denv, address, "setting") &&
+ sieve_opr_string_dump(denv, address, "value"));
+}
+
+static bool
+cmd_test_config_unset_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "TEST_CONFIG_UNSET:");
+
+ sieve_code_descend(denv);
+
+ return sieve_opr_string_dump(denv, address, "setting");
+}
+
+static bool
+cmd_test_config_reload_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "TEST_CONFIG_RELOAD:");
+ sieve_code_descend(denv);
+
+ /* Dump optional operands */
+
+ for (;;) {
+ int opt;
+ bool opok = TRUE;
+
+ if ((opt = sieve_opr_optional_dump(denv, address,
+ &opt_code)) < 0)
+ return FALSE;
+
+ if (opt == 0)
+ break;
+
+ switch (opt_code) {
+ case OPT_EXTENSION:
+ opok = sieve_opr_string_dump(denv, address,
+ "extensions");
+ break;
+ default:
+ opok = FALSE;
+ break;
+ }
+
+ if (!opok)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Interpretation
+ */
+
+static int
+cmd_test_config_set_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ string_t *setting;
+ string_t *value;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Setting */
+ if ((ret = sieve_opr_string_read(renv, address, "setting",
+ &setting)) <= 0)
+ return ret;
+
+ /* Value */
+ if ((ret = sieve_opr_string_read(renv, address, "value",
+ &value)) <= 0)
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
+ sieve_runtime_trace(
+ renv, 0, "testsuite: test_config_set command");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(
+ renv, 0, "set config `%s' = `%s'",
+ str_c(setting), str_c(value));
+ }
+
+ testsuite_setting_set(str_c(setting), str_c(value));
+
+ return SIEVE_EXEC_OK;
+}
+
+static int
+cmd_test_config_unset_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ string_t *setting;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Setting */
+ if ((ret = sieve_opr_string_read(renv, address, "setting",
+ &setting)) <= 0)
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
+ sieve_runtime_trace(
+ renv, 0, "testsuite: test_config_unset command");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(
+ renv, 0, "unset config `%s'", str_c(setting));
+ }
+
+ testsuite_setting_unset(str_c(setting));
+
+ return SIEVE_EXEC_OK;
+}
+
+static int
+cmd_test_config_reload_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_extension *ext;
+ int opt_code = 0;
+ string_t *extension = NULL;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Optional operands */
+ for (;;) {
+ int opt;
+
+ if ((opt = sieve_opr_optional_read(renv, address,
+ &opt_code)) < 0)
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ if (opt == 0)
+ break;
+
+ switch (opt_code) {
+ case OPT_EXTENSION:
+ ret = sieve_opr_string_read(renv, address, "extension",
+ &extension);
+ break;
+ default:
+ sieve_runtime_trace_error(
+ renv, "unknown optional operand");
+ ret = SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if (ret <= 0)
+ return ret;
+ }
+
+ /*
+ * Perform operation
+ */
+
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
+ sieve_runtime_trace(
+ renv, 0, "testsuite: test_config_reload command");
+ sieve_runtime_trace_descend(renv);
+ }
+
+ if (extension == NULL) {
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
+ sieve_runtime_trace(
+ renv, 0,
+ "reload configuration for sieve engine");
+ }
+
+ sieve_settings_load(eenv->svinst);
+ } else {
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
+ sieve_runtime_trace(
+ renv, 0,
+ "reload configuration for extension `%s'",
+ str_c(extension));
+ }
+
+ ext = sieve_extension_get_by_name(eenv->svinst,
+ str_c(extension));
+ if (ext == NULL) {
+ return testsuite_test_failf(
+ renv, "test_config_reload: "
+ "unknown extension '%s'", str_c(extension));
+ }
+ sieve_extension_reload(ext);
+ }
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/testsuite/cmd-test-fail.c b/pigeonhole/src/testsuite/cmd-test-fail.c
new file mode 100644
index 0000000..346c187
--- /dev/null
+++ b/pigeonhole/src/testsuite/cmd-test-fail.c
@@ -0,0 +1,129 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+
+#include "testsuite-common.h"
+
+/*
+ * Test_fail command
+ *
+ * Syntax:
+ * test_fail <reason: string>
+ */
+
+static bool
+cmd_test_fail_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd);
+static bool
+cmd_test_fail_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+const struct sieve_command_def cmd_test_fail = {
+ .identifier = "test_fail",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_test_fail_validate,
+ .generate = cmd_test_fail_generate,
+};
+
+/*
+ * Test operation
+ */
+
+static bool
+cmd_test_fail_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_test_fail_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def test_fail_operation = {
+ .mnemonic = "TEST_FAIL",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_FAIL,
+ .dump = cmd_test_fail_operation_dump,
+ .execute = cmd_test_fail_operation_execute,
+};
+
+/*
+ * Validation
+ */
+
+static bool
+cmd_test_fail_validate(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+
+ if (!sieve_validate_positional_argument(valdtr, cmd, arg, "reason", 1,
+ SAAT_STRING))
+ return FALSE;
+
+ return sieve_validator_argument_activate(valdtr, cmd, arg, FALSE);
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+cmd_test_fail_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &test_fail_operation);
+
+ /* Generate arguments */
+ if (!sieve_generate_arguments(cgenv, cmd, NULL))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+cmd_test_fail_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "TEST_FAIL:");
+ sieve_code_descend(denv);
+
+ if (!sieve_opr_string_dump(denv, address, "reason"))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Intepretation
+ */
+
+static int
+cmd_test_fail_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ string_t *reason;
+ int ret;
+
+ ret = sieve_opr_string_read(renv, address, "reason", &reason);
+ if (ret <= 0)
+ return ret;
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "testsuite: "
+ "test_fail command; FAIL current test");
+
+ return testsuite_test_fail(renv, reason);
+}
diff --git a/pigeonhole/src/testsuite/cmd-test-imap-metadata.c b/pigeonhole/src/testsuite/cmd-test-imap-metadata.c
new file mode 100644
index 0000000..1c5e2a9
--- /dev/null
+++ b/pigeonhole/src/testsuite/cmd-test-imap-metadata.c
@@ -0,0 +1,284 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+
+#include "testsuite-common.h"
+#include "testsuite-mailstore.h"
+
+/*
+ * Commands
+ */
+
+static bool cmd_test_imap_metadata_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool cmd_test_imap_metadata_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool cmd_test_imap_metadata_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+/* Test_mailbox_create command
+ *
+ * Syntax:
+ * test_imap_metadata_set
+ * <mailbox: string> <annotation: string> <value:string>
+ */
+
+const struct sieve_command_def cmd_test_imap_metadata_set = {
+ .identifier = "test_imap_metadata_set",
+ .type = SCT_COMMAND,
+ .positional_args = 2,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = cmd_test_imap_metadata_registered,
+ .validate = cmd_test_imap_metadata_validate,
+ .generate = cmd_test_imap_metadata_generate,
+};
+
+/*
+ * Command tags
+ */
+
+static bool cmd_test_imap_metadata_validate_mailbox_tag
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+static const struct sieve_argument_def test_imap_metadata_mailbox_tag = {
+ .identifier = "mailbox",
+ .validate = cmd_test_imap_metadata_validate_mailbox_tag
+};
+
+/*
+ * Operations
+ */
+
+static bool cmd_test_imap_metadata_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int cmd_test_imap_metadata_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+/* Test_mailbox_create operation */
+
+const struct sieve_operation_def test_imap_metadata_set_operation = {
+ .mnemonic = "TEST_IMAP_METADATA_SET",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_IMAP_METADATA_SET,
+ .dump = cmd_test_imap_metadata_operation_dump,
+ .execute = cmd_test_imap_metadata_operation_execute
+};
+
+/* Codes for optional arguments */
+
+enum cmd_vacation_optional {
+ OPT_END,
+ OPT_MAILBOX
+};
+
+/*
+ * Tag validation
+ */
+
+static bool cmd_test_imap_metadata_validate_mailbox_tag
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+
+ /* Delete this tag */
+ *arg = sieve_ast_arguments_detach(*arg, 1);
+
+ /* Check syntax:
+ * :mailbox string
+ */
+ if ( !sieve_validate_tag_parameter
+ (valdtr, cmd, tag, *arg, NULL, 0, SAAT_STRING, FALSE) ) {
+ return FALSE;
+ }
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+ return TRUE;
+}
+
+/*
+ * Command registration
+ */
+
+static bool cmd_test_imap_metadata_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, ext, &test_imap_metadata_mailbox_tag, OPT_MAILBOX);
+ return TRUE;
+}
+
+
+/*
+ * Validation
+ */
+
+static bool cmd_test_imap_metadata_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, cmd, arg, "annotation", 2, SAAT_STRING) )
+ return FALSE;
+
+ if (!sieve_validator_argument_activate(valdtr, cmd, arg, FALSE))
+ return FALSE;
+
+ arg = sieve_ast_argument_next(arg);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, cmd, arg, "value", 3, SAAT_STRING) )
+ return FALSE;
+
+ if (!sieve_validator_argument_activate(valdtr, cmd, arg, FALSE))
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool cmd_test_imap_metadata_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ /* Emit operation */
+ if ( sieve_command_is(cmd, cmd_test_imap_metadata_set) )
+ sieve_operation_emit
+ (cgenv->sblock, cmd->ext, &test_imap_metadata_set_operation);
+ else
+ i_unreached();
+
+ /* Generate arguments */
+ if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool cmd_test_imap_metadata_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "%s:", sieve_operation_mnemonic(denv->oprtn));
+ sieve_code_descend(denv);
+
+ /* Dump optional operands */
+
+ for (;;) {
+ int opt;
+ bool opok = TRUE;
+
+ if ( (opt=sieve_opr_optional_dump(denv, address, &opt_code)) < 0 )
+ return FALSE;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_MAILBOX:
+ opok = sieve_opr_string_dump(denv, address, "mailbox");
+ break;
+ default:
+ return FALSE;
+ }
+
+ if ( !opok ) return FALSE;
+ }
+
+ return
+ ( sieve_opr_string_dump(denv, address, "annotation") &&
+ sieve_opr_string_dump(denv, address, "value") );
+}
+
+/*
+ * Intepretation
+ */
+
+static int cmd_test_imap_metadata_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ const struct sieve_operation *oprtn = renv->oprtn;
+ int opt_code = 0;
+ string_t *mailbox = NULL, *annotation = NULL, *value = NULL;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Optional operands */
+
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_opr_optional_read(renv, address, &opt_code)) < 0 )
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_MAILBOX:
+ ret = sieve_opr_string_read(renv, address, "mailbox", &mailbox);
+ break;
+ default:
+ sieve_runtime_trace_error(renv, "unknown optional operand");
+ ret = SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if ( ret <= 0 ) return ret;
+ }
+
+ /* Fixed operands */
+
+ if ( (ret=sieve_opr_string_read
+ (renv, address, "annotation", &annotation)) <= 0 )
+ return ret;
+ if ( (ret=sieve_opr_string_read
+ (renv, address, "value", &value)) <= 0 )
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ if ( sieve_operation_is(oprtn, test_imap_metadata_set_operation) ) {
+ if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+ sieve_runtime_trace(renv, 0, "testsuite/test_imap_metadata_set command");
+ sieve_runtime_trace_descend(renv);
+ if (mailbox == NULL) {
+ sieve_runtime_trace(renv, 0,
+ "set server annotation `%s'", str_c(annotation));
+ } else {
+ sieve_runtime_trace(renv, 0,
+ "set annotation `%s' for mailbox `%s'",
+ str_c(annotation), str_c(mailbox));
+ }
+ }
+
+ if (testsuite_mailstore_set_imap_metadata
+ (( mailbox == NULL ? NULL : str_c(mailbox) ),
+ str_c(annotation), str_c(value)) < 0)
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/testsuite/cmd-test-mailbox.c b/pigeonhole/src/testsuite/cmd-test-mailbox.c
new file mode 100644
index 0000000..b5d946c
--- /dev/null
+++ b/pigeonhole/src/testsuite/cmd-test-mailbox.c
@@ -0,0 +1,261 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+#include "sieve-actions.h"
+
+#include "testsuite-common.h"
+#include "testsuite-mailstore.h"
+
+/*
+ * Commands
+ */
+
+static bool
+cmd_test_mailbox_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd);
+static bool
+cmd_test_mailbox_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+/* Test_mailbox_create command
+ *
+ * Syntax:
+ * test_mailbox_create <mailbox: string>
+ */
+
+const struct sieve_command_def cmd_test_mailbox_create = {
+ .identifier = "test_mailbox_create",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_test_mailbox_validate,
+ .generate = cmd_test_mailbox_generate,
+};
+
+/* Test_mailbox_delete command
+ *
+ * Syntax:
+ * test_mailbox_create <mailbox: string>
+ */
+
+const struct sieve_command_def cmd_test_mailbox_delete = {
+ .identifier = "test_mailbox_delete",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_test_mailbox_validate,
+ .generate = cmd_test_mailbox_generate,
+};
+
+/*
+ * Operations
+ */
+
+static bool
+cmd_test_mailbox_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_test_mailbox_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+/* Test_mailbox_create operation */
+
+const struct sieve_operation_def test_mailbox_create_operation = {
+ .mnemonic = "TEST_MAILBOX_CREATE",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_MAILBOX_CREATE,
+ .dump = cmd_test_mailbox_operation_dump,
+ .execute = cmd_test_mailbox_operation_execute,
+};
+
+/* Test_mailbox_delete operation */
+
+const struct sieve_operation_def test_mailbox_delete_operation = {
+ .mnemonic = "TEST_MAILBOX_DELETE",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_MAILBOX_DELETE,
+ .dump = cmd_test_mailbox_operation_dump,
+ .execute = cmd_test_mailbox_operation_execute,
+};
+
+/*
+ * Validation
+ */
+
+static bool
+cmd_test_mailbox_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+
+ if (!sieve_validate_positional_argument(valdtr, cmd, arg, "mailbox", 1,
+ SAAT_STRING))
+ return FALSE;
+
+ if ( !sieve_validator_argument_activate(valdtr, cmd, arg, FALSE) )
+ return FALSE;
+
+ /* Check name validity when folder argument is not a variable */
+ if ( sieve_argument_is_string_literal(arg) ) {
+ const char *folder = sieve_ast_argument_strc(arg), *error;
+
+ if ( !sieve_mailbox_check_name(folder, &error) ) {
+ sieve_command_validate_error(
+ valdtr, cmd, "%s command: "
+ "invalid mailbox `%s' specified: %s",
+ sieve_command_identifier(cmd),
+ str_sanitize(folder, 256), error);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+cmd_test_mailbox_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ /* Emit operation */
+ if (sieve_command_is(cmd, cmd_test_mailbox_create)) {
+ sieve_operation_emit(cgenv->sblock, cmd->ext,
+ &test_mailbox_create_operation);
+ } else if (sieve_command_is(cmd, cmd_test_mailbox_delete)) {
+ sieve_operation_emit(cgenv->sblock, cmd->ext,
+ &test_mailbox_delete_operation);
+ } else {
+ i_unreached();
+ }
+
+ /* Generate arguments */
+ if (!sieve_generate_arguments(cgenv, cmd, NULL))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+cmd_test_mailbox_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "%s:", sieve_operation_mnemonic(denv->oprtn));
+
+ sieve_code_descend(denv);
+
+ return sieve_opr_string_dump(denv, address, "mailbox");
+}
+
+/*
+ * Intepretation
+ */
+
+static const char *
+cmd_test_mailbox_get_command_name(const struct sieve_operation *oprtn)
+{
+ if (sieve_operation_is(oprtn, test_mailbox_create_operation))
+ return "test_mailbox_create";
+ if (sieve_operation_is(oprtn, test_mailbox_delete_operation))
+ return "test_mailbox_delete";
+
+ i_unreached();
+}
+
+static int
+cmd_test_mailbox_create_execute(const struct sieve_runtime_env *renv,
+ const char *mailbox)
+{
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
+ sieve_runtime_trace(
+ renv, 0,
+ "testsuite/test_mailbox_create command");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(
+ renv, 0, "create mailbox `%s'", mailbox);
+ }
+
+ testsuite_mailstore_mailbox_create(renv, mailbox);
+ return SIEVE_EXEC_OK;
+}
+
+static int
+cmd_test_mailbox_delete_execute(const struct sieve_runtime_env *renv,
+ const char *mailbox)
+{
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
+ sieve_runtime_trace(
+ renv, 0,
+ "testsuite/test_mailbox_delete command");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(
+ renv, 0, "delete mailbox `%s'", mailbox);
+ }
+
+ /* FIXME: implement */
+ return testsuite_test_failf(
+ renv, "test_mailbox_delete: NOT IMPLEMENTED");
+}
+
+static int
+cmd_test_mailbox_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ const struct sieve_operation *oprtn = renv->oprtn;
+ string_t *mailbox = NULL;
+ const char *error;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Mailbox */
+
+ ret = sieve_opr_string_read(renv, address, "mailbox", &mailbox);
+ if (ret <= 0)
+ return ret;
+
+ if (!sieve_mailbox_check_name(str_c(mailbox), &error)) {
+ sieve_runtime_error(
+ renv, NULL, "%s command: "
+ "invalid mailbox `%s' specified: %s",
+ cmd_test_mailbox_get_command_name(oprtn),
+ str_c(mailbox), error);
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ /*
+ * Perform operation
+ */
+
+ if (sieve_operation_is(oprtn, test_mailbox_create_operation))
+ ret = cmd_test_mailbox_create_execute(renv, str_c(mailbox));
+ else if (sieve_operation_is(oprtn, test_mailbox_delete_operation))
+ ret = cmd_test_mailbox_delete_execute(renv, str_c(mailbox));
+ else
+ i_unreached();
+
+ return ret;
+}
diff --git a/pigeonhole/src/testsuite/cmd-test-message.c b/pigeonhole/src/testsuite/cmd-test-message.c
new file mode 100644
index 0000000..ff36704
--- /dev/null
+++ b/pigeonhole/src/testsuite/cmd-test-message.c
@@ -0,0 +1,569 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str-sanitize.h"
+#include "istream.h"
+#include "mail-storage.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-message.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+
+#include "testsuite-common.h"
+#include "testsuite-smtp.h"
+#include "testsuite-mailstore.h"
+
+/*
+ * Commands
+ */
+
+/* Test_message command
+ *
+ * Syntax:
+ * test_message ( :smtp / :mailbox <mailbox: string> ) <index: number>
+ */
+
+static bool
+cmd_test_message_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool
+cmd_test_message_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd);
+static bool
+cmd_test_message_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *ctx);
+
+const struct sieve_command_def cmd_test_message = {
+ .identifier = "test_message",
+ .type = SCT_HYBRID,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = cmd_test_message_registered,
+ .validate = cmd_test_message_validate,
+ .generate = cmd_test_message_generate,
+};
+
+/* Test_message_print command
+ *
+ * Syntax:
+ * test_message_print
+ */
+
+static bool
+cmd_test_message_print_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd);
+
+const struct sieve_command_def cmd_test_message_print = {
+ .identifier = "test_message_print",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .generate = cmd_test_message_print_generate,
+};
+
+/*
+ * Operations
+ */
+
+/* Test_message_smtp operation */
+
+static bool
+cmd_test_message_smtp_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_test_message_smtp_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def test_message_smtp_operation = {
+ .mnemonic = "TEST_MESSAGE_SMTP",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_MESSAGE_SMTP,
+ .dump = cmd_test_message_smtp_operation_dump,
+ .execute = cmd_test_message_smtp_operation_execute,
+};
+
+/* Test_message_mailbox operation */
+
+static bool
+cmd_test_message_mailbox_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_test_message_mailbox_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def test_message_mailbox_operation = {
+ .mnemonic = "TEST_MESSAGE_MAILBOX",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_MESSAGE_MAILBOX,
+ .dump = cmd_test_message_mailbox_operation_dump,
+ .execute = cmd_test_message_mailbox_operation_execute,
+};
+
+/* Test_message_print operation */
+
+static bool
+cmd_test_message_print_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_test_message_print_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def test_message_print_operation = {
+ .mnemonic = "TEST_MESSAGE_PRINT",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_MESSAGE_PRINT,
+ .dump = cmd_test_message_print_operation_dump,
+ .execute = cmd_test_message_print_operation_execute,
+};
+
+/*
+ * Compiler context data
+ */
+
+enum test_message_source {
+ MSG_SOURCE_SMTP,
+ MSG_SOURCE_MAILBOX,
+ MSG_SOURCE_LAST,
+};
+
+const struct sieve_operation_def *test_message_operations[] = {
+ &test_message_smtp_operation,
+ &test_message_mailbox_operation,
+};
+
+struct cmd_test_message_context_data {
+ enum test_message_source msg_source;
+ const char *folder;
+};
+
+#define CMD_TEST_MESSAGE_ERROR_DUP_TAG \
+ "exactly one of the ':smtp' or ':folder' tags must be specified " \
+ "for the test_message command, but more were found"
+
+/*
+ * Command tags
+ */
+
+static bool
+cmd_test_message_validate_smtp_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+static bool
+cmd_test_message_validate_folder_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+static const struct sieve_argument_def test_message_smtp_tag = {
+ .identifier = "smtp",
+ .validate = cmd_test_message_validate_smtp_tag,
+};
+
+static const struct sieve_argument_def test_message_folder_tag = {
+ .identifier = "folder",
+ .validate = cmd_test_message_validate_folder_tag,
+};
+
+static bool
+cmd_test_message_registered(struct sieve_validator *valdtr,
+ const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ /* Register our tags */
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &test_message_folder_tag, 0);
+ sieve_validator_register_tag(valdtr, cmd_reg, ext,
+ &test_message_smtp_tag, 0);
+ return TRUE;
+}
+
+static struct cmd_test_message_context_data *
+cmd_test_message_validate_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct cmd_test_message_context_data *ctx_data =
+ (struct cmd_test_message_context_data *)cmd->data;
+
+ if (ctx_data != NULL) {
+ sieve_argument_validate_error(valdtr, *arg,
+ CMD_TEST_MESSAGE_ERROR_DUP_TAG);
+ return NULL;
+ }
+
+ ctx_data = p_new(sieve_command_pool(cmd),
+ struct cmd_test_message_context_data, 1);
+ cmd->data = ctx_data;
+
+ /* Delete this tag */
+ *arg = sieve_ast_arguments_detach(*arg, 1);
+
+ return ctx_data;
+}
+
+static bool
+cmd_test_message_validate_smtp_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct cmd_test_message_context_data *ctx_data =
+ cmd_test_message_validate_tag(valdtr, arg, cmd);
+
+ /* Return value is NULL on error */
+ if (ctx_data == NULL)
+ return FALSE;
+
+ /* Assign chosen message source */
+ ctx_data->msg_source = MSG_SOURCE_SMTP;
+
+ return TRUE;
+}
+
+static bool
+cmd_test_message_validate_folder_tag(struct sieve_validator *valdtr,
+ struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+ struct cmd_test_message_context_data *ctx_data =
+ cmd_test_message_validate_tag(valdtr, arg, cmd);
+
+ /* Return value is NULL on error */
+ if (ctx_data == NULL)
+ return FALSE;
+
+ /* Assign chose message source */
+ ctx_data->msg_source = MSG_SOURCE_MAILBOX;
+
+ /* Check syntax:
+ * :folder string
+ */
+ if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0,
+ SAAT_STRING, FALSE)) {
+ return FALSE;
+ }
+
+ /* Check name validity when folder argument is not a variable */
+ if ( sieve_argument_is_string_literal(*arg) ) {
+ const char *folder = sieve_ast_argument_strc(*arg), *error;
+
+ if ( !sieve_mailbox_check_name(folder, &error) ) {
+ sieve_command_validate_error(
+ valdtr, cmd, "%s command: "
+ "invalid mailbox `%s' specified: %s",
+ sieve_command_identifier(cmd),
+ str_sanitize(folder, 256), error);
+ return FALSE;
+ }
+ }
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+
+ return TRUE;
+}
+
+/*
+ * Validation
+ */
+
+static bool
+cmd_test_message_validate(struct sieve_validator *valdtr,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+
+ if (cmd->data == NULL) {
+ sieve_command_validate_error(
+ valdtr, cmd,
+ "the test_message command requires either "
+ "the :smtp or the :mailbox tag to be specified");
+ return FALSE;
+ }
+
+ if (!sieve_validate_positional_argument(valdtr, cmd, arg, "index", 1,
+ SAAT_NUMBER))
+ return FALSE;
+
+ return sieve_validator_argument_activate(valdtr, cmd, arg, FALSE);
+}
+
+/*
+ * Code generation
+ */
+
+static bool
+cmd_test_message_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ struct cmd_test_message_context_data *ctx_data =
+ (struct cmd_test_message_context_data *)cmd->data;
+
+ i_assert(ctx_data->msg_source < MSG_SOURCE_LAST);
+
+ /* Emit operation */
+ sieve_operation_emit(cgenv->sblock, cmd->ext,
+ test_message_operations[ctx_data->msg_source]);
+
+ /* Emit is_test flag */
+ sieve_binary_emit_byte(cgenv->sblock,
+ (cmd->ast_node->type == SAT_TEST ? 1 : 0));
+
+ /* Generate arguments */
+ if (!sieve_generate_arguments(cgenv, cmd, NULL))
+ return FALSE;
+
+ return TRUE;
+}
+
+static bool
+cmd_test_message_print_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ /* Emit operation */
+ sieve_operation_emit(cgenv->sblock, cmd->ext,
+ &test_message_print_operation);
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+cmd_test_message_smtp_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ unsigned int is_test;
+
+ if (!sieve_binary_read_byte(denv->sblock, address, &is_test))
+ return FALSE;
+
+ sieve_code_dumpf(denv, "TEST_MESSAGE_SMTP (%s):",
+ (is_test > 0 ? "TEST" : "COMMAND"));
+
+ sieve_code_descend(denv);
+
+ return sieve_opr_number_dump(denv, address, "index");
+}
+
+static bool
+cmd_test_message_mailbox_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ unsigned int is_test;
+
+ if (!sieve_binary_read_byte(denv->sblock, address, &is_test))
+ return FALSE;
+
+ sieve_code_dumpf(denv, "TEST_MESSAGE_MAILBOX (%s):",
+ (is_test > 0 ? "TEST" : "COMMAND"));
+
+ sieve_code_descend(denv);
+
+ return (sieve_opr_string_dump(denv, address, "folder") &&
+ sieve_opr_number_dump(denv, address, "index"));
+}
+
+static bool
+cmd_test_message_print_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ sieve_code_dumpf(denv, "TEST_MESSAGE_PRINT");
+
+ return TRUE;
+}
+
+/*
+ * Intepretation
+ */
+
+static int
+cmd_test_message_smtp_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ sieve_number_t msg_index;
+ unsigned int is_test = 0;
+ bool result;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Is test */
+
+ if (!sieve_binary_read_byte(renv->sblock, address, &is_test)) {
+ sieve_runtime_trace_error(renv, "invalid is_test flag");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ /* Index */
+
+ ret = sieve_opr_number_read(renv, address, "index", &msg_index);
+ if (ret <= 0)
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ if (is_test > 0) {
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_TESTS)) {
+ sieve_runtime_trace(
+ renv, 0, "testsuite: test_message test");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(
+ renv, 0,
+ "check and retrieve smtp message [index=%llu]",
+ (unsigned long long)msg_index);
+ }
+ } else {
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
+ sieve_runtime_trace(
+ renv, 0, "testsuite: test_message command");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(
+ renv, 0,
+ "retrieve smtp message [index=%llu]",
+ (unsigned long long)msg_index);
+ }
+ }
+
+ result = testsuite_smtp_get(renv, msg_index);
+
+ if (is_test > 0) {
+ sieve_interpreter_set_test_result(renv->interp, result);
+ return SIEVE_EXEC_OK;
+ }
+
+ if (!result) {
+ return testsuite_test_failf(
+ renv, "no outgoing SMTP message with index %llu",
+ (unsigned long long)msg_index);
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+static int
+cmd_test_message_mailbox_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ string_t *folder;
+ sieve_number_t msg_index;
+ unsigned int is_test = 0;
+ bool result;
+ const char *error;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Is test */
+ if (!sieve_binary_read_byte(renv->sblock, address, &is_test)) {
+ sieve_runtime_trace_error(renv, "invalid is_test flag");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ /* Folder */
+ ret = sieve_opr_string_read(renv, address, "folder", &folder);
+ if (ret <= 0)
+ return ret;
+
+ /* Index */
+ ret = sieve_opr_number_read(renv, address, "index", &msg_index);
+ if (ret <= 0)
+ return ret;
+
+ if (!sieve_mailbox_check_name(str_c(folder), &error)) {
+ return testsuite_test_failf(
+ renv, "invalid mailbox `%s' specified: %s",
+ str_c(folder), error);
+ }
+
+ /*
+ * Perform operation
+ */
+
+ if (is_test > 0) {
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_TESTS)) {
+ sieve_runtime_trace(
+ renv, 0, "testsuite: test_message test");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(
+ renv, 0, "check and retrieve mailbox message "
+ "[mailbox=`%s' index=%llu]",
+ str_c(folder), (unsigned long long)msg_index);
+ }
+ } else {
+ if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
+ sieve_runtime_trace(
+ renv, 0, "testsuite: test_message command");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(
+ renv, 0, "retrieve mailbox message "
+ "[mailbox=`%s' index=%llu]",
+ str_c(folder), (unsigned long long)msg_index);
+ }
+ }
+
+ result = testsuite_mailstore_mail_index(renv, str_c(folder), msg_index);
+
+ if (is_test > 0) {
+ sieve_interpreter_set_test_result(renv->interp, result);
+ return SIEVE_EXEC_OK;
+ }
+
+ if (!result) {
+ return testsuite_test_failf(
+ renv, "no message in folder '%s' with index %llu",
+ str_c(folder), (unsigned long long)msg_index);
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+static int
+cmd_test_message_print_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ struct mail *mail = sieve_message_get_mail(renv->msgctx);
+ struct istream *input;
+ const unsigned char *data;
+ size_t size;
+
+ if (mail_get_stream(mail, NULL, NULL, &input) < 0) {
+ sieve_runtime_error(renv, NULL, "test_message_print: "
+ "failed to read current message");
+ return SIEVE_EXEC_OK;
+ }
+
+ printf("\n--MESSAGE: \n");
+
+ /* Pipe the message to the outgoing SMTP transport */
+ while (i_stream_read_more(input, &data, &size) > 0) {
+ ssize_t wret;
+
+ wret = write(1, data, size);
+ if (wret <= 0)
+ break;
+ i_stream_skip(input, wret);
+ }
+ printf("\n--MESSAGE--\n");
+
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/testsuite/cmd-test-result.c b/pigeonhole/src/testsuite/cmd-test-result.c
new file mode 100644
index 0000000..230aa62
--- /dev/null
+++ b/pigeonhole/src/testsuite/cmd-test-result.c
@@ -0,0 +1,138 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-script.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+#include "sieve.h"
+
+#include "testsuite-common.h"
+#include "testsuite-result.h"
+#include "testsuite-message.h"
+#include "testsuite-smtp.h"
+
+/*
+ * Commands
+ */
+
+static bool
+cmd_test_result_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd);
+
+/* Test_result_reset command
+ *
+ * Syntax:
+ * test_result_reset
+ */
+
+const struct sieve_command_def cmd_test_result_reset = {
+ .identifier = "test_result_reset",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .generate = cmd_test_result_generate,
+};
+
+/* Test_result_print command
+ *
+ * Syntax:
+ * test_result_print
+ */
+
+const struct sieve_command_def cmd_test_result_print = {
+ .identifier = "test_result_print",
+ .type = SCT_COMMAND,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .generate = cmd_test_result_generate,
+};
+
+/*
+ * Operations
+ */
+
+/* test_result_reset */
+
+static int
+cmd_test_result_reset_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def test_result_reset_operation = {
+ .mnemonic = "TEST_RESULT_RESET",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_RESULT_RESET,
+ .execute = cmd_test_result_reset_operation_execute,
+};
+
+/* test_result_print */
+
+static int
+cmd_test_result_print_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def test_result_print_operation = {
+ .mnemonic = "TEST_RESULT_PRINT",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_RESULT_PRINT,
+ .execute = cmd_test_result_print_operation_execute,
+};
+
+/*
+ * Code generation
+ */
+
+static bool
+cmd_test_result_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ if (sieve_command_is(cmd, cmd_test_result_reset)) {
+ sieve_operation_emit(cgenv->sblock, cmd->ext,
+ &test_result_reset_operation);
+ } else if (sieve_command_is(cmd, cmd_test_result_print)) {
+ sieve_operation_emit(cgenv->sblock, cmd->ext,
+ &test_result_print_operation);
+ } else {
+ i_unreached();
+ }
+
+ return TRUE;
+}
+
+/*
+ * Intepretation
+ */
+
+static int
+cmd_test_result_reset_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "testsuite: "
+ "test_result_reset command; reset script result");
+
+ testsuite_result_reset(renv);
+ testsuite_smtp_reset();
+
+ return SIEVE_EXEC_OK;
+}
+
+static int
+cmd_test_result_print_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "testsuite: "
+ "test_result_print command; print script result ");
+
+ testsuite_result_print(renv);
+
+ return SIEVE_EXEC_OK;
+}
diff --git a/pigeonhole/src/testsuite/cmd-test-set.c b/pigeonhole/src/testsuite/cmd-test-set.c
new file mode 100644
index 0000000..22b51d2
--- /dev/null
+++ b/pigeonhole/src/testsuite/cmd-test-set.c
@@ -0,0 +1,161 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "str-sanitize.h"
+#include "istream.h"
+#include "istream-header-filter.h"
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-actions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code-dumper.h"
+#include "sieve-result.h"
+
+#include "testsuite-common.h"
+#include "testsuite-objects.h"
+
+#include <stdio.h>
+
+/*
+ * Test_set command
+ *
+ * Syntax
+ * test_set <testsuite object (member): string> <value: string>
+ */
+
+static bool cmd_test_set_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool cmd_test_set_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
+
+const struct sieve_command_def cmd_test_set = {
+ .identifier = "test_set",
+ .type = SCT_COMMAND,
+ .positional_args = 2,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = cmd_test_set_validate,
+ .generate = cmd_test_set_generate
+};
+
+/*
+ * Test_set operation
+ */
+
+static bool cmd_test_set_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int cmd_test_set_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def test_set_operation = {
+ .mnemonic = "TEST_SET",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_SET,
+ .dump = cmd_test_set_operation_dump,
+ .execute = cmd_test_set_operation_execute
+};
+
+/*
+ * Validation
+ */
+
+static bool cmd_test_set_validate
+(struct sieve_validator *valdtr, struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+
+ /* Check arguments */
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, cmd, arg, "object", 1, SAAT_STRING) ) {
+ return FALSE;
+ }
+
+ if ( !testsuite_object_argument_activate(valdtr, arg, cmd) )
+ return FALSE;
+
+ arg = sieve_ast_argument_next(arg);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, cmd, arg, "value", 2, SAAT_STRING) ) {
+ return FALSE;
+ }
+
+ return sieve_validator_argument_activate(valdtr, cmd, arg, FALSE);
+}
+
+/*
+ * Code generation
+ */
+
+static bool cmd_test_set_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
+{
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &test_set_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, cmd, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool cmd_test_set_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "TEST SET:");
+ sieve_code_descend(denv);
+
+ return
+ testsuite_object_dump(denv, address) &&
+ sieve_opr_string_dump(denv, address, "value");
+}
+
+/*
+ * Intepretation
+ */
+
+static int cmd_test_set_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ struct testsuite_object tobj;
+ string_t *value;
+ int member_id;
+ int ret;
+
+ if ( !testsuite_object_read_member
+ (renv->sblock, address, &tobj, &member_id) ) {
+ sieve_runtime_trace_error(renv, "invalid testsuite object member");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if ( (ret=sieve_opr_string_read(renv, address, "string", &value)) <= 0 )
+ return ret;
+
+ if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+ sieve_runtime_trace(renv, 0, "testsuite: test_set command");
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(renv, 0,
+ "set test parameter '%s' = \"%s\"",
+ testsuite_object_member_name(&tobj, member_id), str_c(value));
+ }
+
+ if ( tobj.def == NULL || tobj.def->set_member == NULL ) {
+ sieve_runtime_trace_error(renv, "unimplemented testsuite object");
+ return SIEVE_EXEC_FAILURE;
+ }
+
+ tobj.def->set_member(renv, member_id, value);
+ return SIEVE_EXEC_OK;
+}
+
+
+
diff --git a/pigeonhole/src/testsuite/cmd-test.c b/pigeonhole/src/testsuite/cmd-test.c
new file mode 100644
index 0000000..c817aed
--- /dev/null
+++ b/pigeonhole/src/testsuite/cmd-test.c
@@ -0,0 +1,208 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+
+#include "testsuite-common.h"
+
+/*
+ * Test command
+ *
+ * Syntax:
+ * test <test-name: string> <block>
+ */
+
+static bool
+cmd_test_validate(struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool
+cmd_test_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *md);
+
+const struct sieve_command_def cmd_test = {
+ .identifier = "test",
+ .type = SCT_COMMAND,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = TRUE,
+ .block_required = TRUE,
+ .validate = cmd_test_validate,
+ .generate = cmd_test_generate,
+};
+
+/*
+ * Test operations
+ */
+
+/* Test operation */
+
+static bool
+cmd_test_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address);
+static int
+cmd_test_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def test_operation = {
+ .mnemonic = "TEST",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST,
+ .dump = cmd_test_operation_dump,
+ .execute = cmd_test_operation_execute,
+};
+
+/* Test_finish operation */
+
+static int
+cmd_test_finish_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+
+const struct sieve_operation_def test_finish_operation = {
+ .mnemonic = "TEST-FINISH",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_FINISH,
+ .execute = cmd_test_finish_operation_execute,
+};
+
+/*
+ * Validation
+ */
+
+static bool
+cmd_test_validate(struct sieve_validator *valdtr ATTR_UNUSED,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *arg = cmd->first_positional;
+
+ /* Check valid command placement */
+ if (!sieve_command_is_toplevel(cmd)) {
+ sieve_command_validate_error(
+ valdtr, cmd, "tests cannot be nested: test "
+ "command must be issued at top-level");
+ return FALSE;
+ }
+
+ if (!sieve_validate_positional_argument(valdtr, cmd, arg, "test-name",
+ 1, SAAT_STRING))
+ return FALSE;
+
+ return sieve_validator_argument_activate(valdtr, cmd, arg, FALSE);
+}
+
+/*
+ * Code generation
+ */
+
+static inline struct testsuite_generator_context *
+_get_generator_context(struct sieve_generator *gentr)
+{
+ return (struct testsuite_generator_context *)
+ sieve_generator_extension_get_context(gentr, testsuite_ext);
+}
+
+static bool
+cmd_test_generate(const struct sieve_codegen_env *cgenv,
+ struct sieve_command *cmd)
+{
+ struct testsuite_generator_context *genctx =
+ _get_generator_context(cgenv->gentr);
+
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &test_operation);
+
+ /* Generate arguments */
+ if (!sieve_generate_arguments(cgenv, cmd, NULL))
+ return FALSE;
+
+ /* Prepare jumplist */
+ sieve_jumplist_reset(genctx->exit_jumps);
+ sieve_jumplist_add(genctx->exit_jumps,
+ sieve_binary_emit_offset(cgenv->sblock, 0));
+
+ /* Test body */
+ if (!sieve_generate_block(cgenv, cmd->ast_node))
+ return FALSE;
+
+ sieve_operation_emit(cgenv->sblock, cmd->ext, &test_finish_operation);
+
+ /* Resolve exit jumps to this point */
+ sieve_jumplist_resolve(genctx->exit_jumps);
+
+ return TRUE;
+}
+
+/*
+ * Code dump
+ */
+
+static bool
+cmd_test_operation_dump(const struct sieve_dumptime_env *denv,
+ sieve_size_t *address)
+{
+ sieve_size_t tst_begin;
+ sieve_offset_t tst_end_offset;
+
+ sieve_code_dumpf(denv, "TEST:");
+ sieve_code_descend(denv);
+
+ if (!sieve_opr_string_dump(denv, address, "test name"))
+ return FALSE;
+
+ sieve_code_mark(denv);
+ tst_begin = *address;
+ if (!sieve_binary_read_offset(denv->sblock, address, &tst_end_offset))
+ return FALSE;
+ sieve_code_dumpf(denv, "end: %d [%08llx]",
+ tst_end_offset,
+ (unsigned long long)tst_begin + tst_end_offset);
+
+ return TRUE;
+}
+
+/*
+ * Interpretation
+ */
+
+static int
+cmd_test_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ sieve_size_t tst_begin, tst_end;
+ sieve_offset_t tst_end_offset;
+ string_t *test_name;
+ int ret;
+
+ ret = sieve_opr_string_read(renv, address, "test name", &test_name);
+ if (ret <= 0)
+ return ret;
+
+ tst_begin = *address;
+ if (!sieve_binary_read_offset(renv->sblock, address, &tst_end_offset)) {
+ sieve_runtime_trace_error(renv, "invalid end offset");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ tst_end = tst_begin + tst_end_offset;
+
+ sieve_runtime_trace_sep(renv);
+ sieve_runtime_trace(renv, SIEVE_TRLVL_NONE,
+ "** Testsuite test start: \"%s\" (end: %08llx)",
+ str_c(test_name),
+ (unsigned long long)tst_end);
+
+ return testsuite_test_start(renv, test_name, tst_end);
+}
+
+static int
+cmd_test_finish_operation_execute(const struct sieve_runtime_env *renv,
+ sieve_size_t *address)
+{
+ sieve_runtime_trace(renv, SIEVE_TRLVL_NONE, "** Testsuite test end");
+ sieve_runtime_trace_sep(renv);
+
+ return testsuite_test_succeed(renv, address, NULL);
+}
diff --git a/pigeonhole/src/testsuite/ext-testsuite.c b/pigeonhole/src/testsuite/ext-testsuite.c
new file mode 100644
index 0000000..cb9c92f
--- /dev/null
+++ b/pigeonhole/src/testsuite/ext-testsuite.c
@@ -0,0 +1,175 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension testsuite
+ * -------------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: vendor-specific
+ * (FIXME: provide specification for test authors)
+ *
+ */
+
+/*
+ * Purpose: This custom extension is used to add sieve commands and tests that
+ * act the Sieve engine and on the test suite itself. This practically
+ * provides the means to completely control and thereby test the Sieve
+ * compiler and interpreter. This extension transforms the basic Sieve
+ * language into something much more powerful and suitable to perform
+ * complex self-test operations. Of course, this extension is only
+ * available (as vnd.dovecot.testsuite) when the sieve engine is used
+ * from within the testsuite commandline tool. Test scripts have the
+ * extension .svtest by convention to distinguish them from any normal
+ * sieve scripts that may reside in the same directory.
+ *
+ * WARNING: Although this code can serve as an example on how to write
+ * extensions to the Sieve interpreter, it is generally _NOT_ to be
+ * used as a source for ideas on new Sieve extensions. Many of the
+ * commands and tests that this extension introduces conflict with the
+ * goal and the implied restrictions of the Sieve language. These
+ * restrictions were put in place with good reason. Therefore, do
+ * _NOT_ export functionality provided by this testsuite extension to
+ * your custom extensions that are to be put to general use.
+ */
+
+#include <stdio.h>
+
+#include "sieve-common.h"
+
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-result.h"
+
+#include "testsuite-common.h"
+#include "testsuite-variables.h"
+#include "testsuite-arguments.h"
+
+/*
+ * Operations
+ */
+
+const struct sieve_operation_def *testsuite_operations[] = {
+ &test_operation,
+ &test_finish_operation,
+ &test_fail_operation,
+ &test_config_set_operation,
+ &test_config_unset_operation,
+ &test_config_reload_operation,
+ &test_set_operation,
+ &test_script_compile_operation,
+ &test_script_run_operation,
+ &test_multiscript_operation,
+ &test_error_operation,
+ &test_result_action_operation,
+ &test_result_execute_operation,
+ &test_result_reset_operation,
+ &test_result_print_operation,
+ &test_message_smtp_operation,
+ &test_message_mailbox_operation,
+ &test_message_print_operation,
+ &test_mailbox_create_operation,
+ &test_mailbox_delete_operation,
+ &test_binary_load_operation,
+ &test_binary_save_operation,
+ &test_imap_metadata_set_operation
+};
+
+/*
+ * Operands
+ */
+
+const struct sieve_operand_def *testsuite_operands[] = {
+ &testsuite_object_operand,
+ &testsuite_substitution_operand,
+ &testsuite_namespace_operand
+};
+
+/*
+ * Extension
+ */
+
+/* Forward declarations */
+
+static bool ext_testsuite_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *valdtr);
+static bool ext_testsuite_generator_load
+ (const struct sieve_extension *ext, const struct sieve_codegen_env *cgenv);
+static bool ext_testsuite_interpreter_load
+ (const struct sieve_extension *ext, const struct sieve_runtime_env *renv,
+ sieve_size_t *address);
+static bool ext_testsuite_binary_load
+ (const struct sieve_extension *ext, struct sieve_binary *sbin);
+
+/* Extension object */
+
+const struct sieve_extension_def testsuite_extension = {
+ .name = "vnd.dovecot.testsuite",
+ .validator_load = ext_testsuite_validator_load,
+ .generator_load = ext_testsuite_generator_load,
+ .interpreter_load = ext_testsuite_interpreter_load,
+ .binary_load = ext_testsuite_binary_load,
+ SIEVE_EXT_DEFINE_OPERATIONS(testsuite_operations),
+ SIEVE_EXT_DEFINE_OPERANDS(testsuite_operands)
+};
+
+/* Extension implementation */
+
+static bool ext_testsuite_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *valdtr)
+{
+ sieve_validator_register_command(valdtr, ext, &cmd_test);
+ sieve_validator_register_command(valdtr, ext, &cmd_test_fail);
+ sieve_validator_register_command(valdtr, ext, &cmd_test_config_set);
+ sieve_validator_register_command(valdtr, ext, &cmd_test_config_unset);
+ sieve_validator_register_command(valdtr, ext, &cmd_test_config_reload);
+ sieve_validator_register_command(valdtr, ext, &cmd_test_set);
+ sieve_validator_register_command(valdtr, ext, &cmd_test_result_print);
+ sieve_validator_register_command(valdtr, ext, &cmd_test_result_reset);
+ sieve_validator_register_command(valdtr, ext, &cmd_test_message);
+ sieve_validator_register_command(valdtr, ext, &cmd_test_message_print);
+ sieve_validator_register_command(valdtr, ext, &cmd_test_mailbox_create);
+ sieve_validator_register_command(valdtr, ext, &cmd_test_mailbox_delete);
+ sieve_validator_register_command(valdtr, ext, &cmd_test_binary_load);
+ sieve_validator_register_command(valdtr, ext, &cmd_test_binary_save);
+ sieve_validator_register_command(valdtr, ext, &cmd_test_imap_metadata_set);
+
+ sieve_validator_register_command(valdtr, ext, &tst_test_script_compile);
+ sieve_validator_register_command(valdtr, ext, &tst_test_script_run);
+ sieve_validator_register_command(valdtr, ext, &tst_test_multiscript);
+ sieve_validator_register_command(valdtr, ext, &tst_test_error);
+ sieve_validator_register_command(valdtr, ext, &tst_test_result_action);
+ sieve_validator_register_command(valdtr, ext, &tst_test_result_execute);
+
+/* sieve_validator_argument_override(valdtr, SAT_VAR_STRING, ext,
+ &testsuite_string_argument);*/
+
+ testsuite_variables_init(ext, valdtr);
+
+ return testsuite_validator_context_initialize(valdtr);
+}
+
+static bool ext_testsuite_generator_load
+(const struct sieve_extension *ext, const struct sieve_codegen_env *cgenv)
+{
+ return testsuite_generator_context_initialize(cgenv->gentr, ext);
+}
+
+static bool ext_testsuite_interpreter_load
+(const struct sieve_extension *ext, const struct sieve_runtime_env *renv,
+ sieve_size_t *address ATTR_UNUSED)
+{
+ return testsuite_interpreter_context_initialize(renv->interp, ext);
+}
+
+static bool ext_testsuite_binary_load
+(const struct sieve_extension *ext ATTR_UNUSED, struct sieve_binary *sbin ATTR_UNUSED)
+{
+ return TRUE;
+}
+
+
+
diff --git a/pigeonhole/src/testsuite/testsuite-arguments.c b/pigeonhole/src/testsuite/testsuite-arguments.c
new file mode 100644
index 0000000..f1e17f4
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-arguments.c
@@ -0,0 +1,190 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-ast.h"
+#include "sieve-commands.h"
+#include "sieve-code.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-dump.h"
+
+#include "testsuite-common.h"
+#include "testsuite-substitutions.h"
+#include "testsuite-arguments.h"
+
+#include <ctype.h>
+
+/*
+ * Testsuite string argument
+ */
+
+static bool arg_testsuite_string_validate
+ (struct sieve_validator *validator, struct sieve_ast_argument **arg,
+ struct sieve_command *context);
+
+const struct sieve_argument_def testsuite_string_argument = {
+ .identifier = "@testsuite-string",
+ .validate = arg_testsuite_string_validate,
+ .generate = sieve_arg_catenated_string_generate,
+};
+
+static bool arg_testsuite_string_validate
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ enum { ST_NONE, ST_OPEN, ST_SUBSTITUTION, ST_PARAM, ST_CLOSE } state =
+ ST_NONE;
+ pool_t pool = sieve_ast_pool((*arg)->ast);
+ struct sieve_arg_catenated_string *catstr = NULL;
+ string_t *str = sieve_ast_argument_str(*arg);
+ const char *p, *strstart, *substart = NULL;
+ const char *strval = (const char *) str_data(str);
+ const char *strend = strval + str_len(str);
+ bool result = TRUE;
+ string_t *subs_name = t_str_new(256);
+ string_t *subs_param = t_str_new(256);
+
+ T_BEGIN {
+ /* Initialize substitution structure */
+
+ p = strval;
+ strstart = p;
+ while ( result && p < strend ) {
+ switch ( state ) {
+
+ /* Nothing found yet */
+ case ST_NONE:
+ if ( *p == '%' ) {
+ substart = p;
+ state = ST_OPEN;
+ str_truncate(subs_name, 0);
+ str_truncate(subs_param, 0);
+ }
+ p++;
+ break;
+
+ /* Got '%' */
+ case ST_OPEN:
+ if ( *p == '{' ) {
+ state = ST_SUBSTITUTION;
+ p++;
+ } else
+ state = ST_NONE;
+ break;
+
+ /* Got '%{' */
+ case ST_SUBSTITUTION:
+ state = ST_PARAM;
+
+ while ( *p != '}' && *p != ':' ) {
+ if ( !i_isalnum(*p) ) {
+ state = ST_NONE;
+ break;
+ }
+ str_append_c(subs_name, *p);
+ p++;
+ }
+ break;
+
+ /* Got '%{name' */
+ case ST_PARAM:
+ if ( *p == ':' ) {
+ p++;
+ while ( *p != '}' ) {
+ str_append_c(subs_param, *p);
+ p++;
+ }
+ }
+ state = ST_CLOSE;
+ break;
+
+ /* Finished parsing param, expecting '}' */
+ case ST_CLOSE:
+ if ( *p == '}' ) {
+ struct sieve_ast_argument *strarg;
+
+ /* We now know that the substitution is valid */
+
+ if ( catstr == NULL ) {
+ catstr = sieve_arg_catenated_string_create(*arg);
+ }
+
+ /* Add the substring that is before the substitution to the
+ * variable-string AST.
+ */
+ if ( substart > strstart ) {
+ string_t *newstr = str_new(pool, substart - strstart);
+ str_append_data(newstr, strstart, substart - strstart);
+
+ strarg = sieve_ast_argument_string_create_raw
+ ((*arg)->ast, newstr, (*arg)->source_line);
+ sieve_arg_catenated_string_add_element(catstr, strarg);
+
+ /* Give other substitution extensions a chance to do their work */
+ if ( !sieve_validator_argument_activate_super
+ (valdtr, cmd, strarg, FALSE) ) {
+ result = FALSE;
+ break;
+ }
+ }
+
+ strarg = testsuite_substitution_argument_create
+ (valdtr, (*arg)->ast, (*arg)->source_line, str_c(subs_name),
+ str_c(subs_param));
+
+ if ( strarg != NULL )
+ sieve_arg_catenated_string_add_element(catstr, strarg);
+ else {
+ sieve_argument_validate_error(valdtr, *arg,
+ "unknown testsuite substitution type '%s'", str_c(subs_name));
+ }
+
+ strstart = p + 1;
+ substart = strstart;
+
+ p++;
+ }
+
+ /* Finished, reset for the next substitution */
+ state = ST_NONE;
+ }
+ }
+ } T_END;
+
+ /* Bail out early if substitution is invalid */
+ if ( !result ) return FALSE;
+
+ /* Check whether any substitutions were found */
+ if ( catstr == NULL ) {
+ /* No substitutions in this string, pass it on to any other substution
+ * extension.
+ */
+ return sieve_validator_argument_activate_super(valdtr, cmd, *arg, TRUE);
+ }
+
+ /* Add the final substring that comes after the last substitution to the
+ * variable-string AST.
+ */
+ if ( strend > strstart ) {
+ struct sieve_ast_argument *strarg;
+ string_t *newstr = str_new(pool, strend - strstart);
+ str_append_data(newstr, strstart, strend - strstart);
+
+ strarg = sieve_ast_argument_string_create_raw
+ ((*arg)->ast, newstr, (*arg)->source_line);
+ sieve_arg_catenated_string_add_element(catstr, strarg);
+
+ /* Give other substitution extensions a chance to do their work */
+ if ( !sieve_validator_argument_activate_super
+ (valdtr, cmd, strarg, FALSE) )
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/pigeonhole/src/testsuite/testsuite-arguments.h b/pigeonhole/src/testsuite/testsuite-arguments.h
new file mode 100644
index 0000000..22ab82b
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-arguments.h
@@ -0,0 +1,6 @@
+#ifndef TESTSUITE_ARGUMENTS_H
+#define TESTSUITE_ARGUMENTS_H
+
+extern const struct sieve_argument_def testsuite_string_argument;
+
+#endif
diff --git a/pigeonhole/src/testsuite/testsuite-binary.c b/pigeonhole/src/testsuite/testsuite-binary.c
new file mode 100644
index 0000000..6c875a7
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-binary.c
@@ -0,0 +1,82 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "mempool.h"
+#include "imem.h"
+#include "array.h"
+#include "strfuncs.h"
+#include "unlink-directory.h"
+
+#include "sieve.h"
+#include "sieve-common.h"
+#include "sieve-script.h"
+#include "sieve-binary.h"
+#include "sieve-error.h"
+
+#include "testsuite-common.h"
+#include "testsuite-binary.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+/*
+ * State
+ */
+
+static char *testsuite_binary_tmp = NULL;
+
+/*
+ * Initialization
+ */
+
+void testsuite_binary_init(void)
+{
+ testsuite_binary_tmp = i_strconcat
+ (testsuite_tmp_dir_get(), "/binaries", NULL);
+
+ if ( mkdir(testsuite_binary_tmp, 0700) < 0 ) {
+ i_fatal("failed to create temporary directory '%s': %m.",
+ testsuite_binary_tmp);
+ }
+}
+
+void testsuite_binary_deinit(void)
+{
+ const char *error;
+
+ if ( unlink_directory(testsuite_binary_tmp, UNLINK_DIRECTORY_FLAG_RMDIR, &error) < 0 ) {
+ i_warning("failed to remove temporary directory '%s': %s.",
+ testsuite_binary_tmp, error);
+ }
+
+ i_free(testsuite_binary_tmp);
+}
+
+void testsuite_binary_reset(void)
+{
+ testsuite_binary_init();
+ testsuite_binary_deinit();
+}
+
+/*
+ * Binary Access
+ */
+
+bool testsuite_binary_save(struct sieve_binary *sbin, const char *name)
+{
+ return ( sieve_save_as(sbin, t_strdup_printf
+ ("%s/%s", testsuite_binary_tmp, sieve_binfile_from_name(name)), TRUE,
+ 0600, NULL) > 0 );
+}
+
+struct sieve_binary *testsuite_binary_load(const char *name)
+{
+ struct sieve_instance *svinst = testsuite_sieve_instance;
+
+ return sieve_load(svinst, t_strdup_printf
+ ("%s/%s", testsuite_binary_tmp, sieve_binfile_from_name(name)), NULL);
+}
+
+
+
diff --git a/pigeonhole/src/testsuite/testsuite-binary.h b/pigeonhole/src/testsuite/testsuite-binary.h
new file mode 100644
index 0000000..0a09d2b
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-binary.h
@@ -0,0 +1,17 @@
+#ifndef TESTSUITE_BINARY_H
+#define TESTSUITE_BINARY_H
+
+#include "sieve-common.h"
+
+void testsuite_binary_init(void);
+void testsuite_binary_deinit(void);
+void testsuite_binary_reset(void);
+
+/*
+ * Binary Access
+ */
+
+bool testsuite_binary_save(struct sieve_binary *sbin, const char *name);
+struct sieve_binary *testsuite_binary_load(const char *name);
+
+#endif
diff --git a/pigeonhole/src/testsuite/testsuite-common.c b/pigeonhole/src/testsuite/testsuite-common.c
new file mode 100644
index 0000000..269deee
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-common.c
@@ -0,0 +1,374 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "string.h"
+#include "ostream.h"
+#include "hash.h"
+#include "mail-storage.h"
+#include "env-util.h"
+#include "unlink-directory.h"
+
+#include "mail-raw.h"
+
+#include "sieve-common.h"
+#include "sieve-code.h"
+#include "sieve-message.h"
+#include "sieve-commands.h"
+#include "sieve-extensions.h"
+#include "sieve-binary.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-result.h"
+#include "sieve-dump.h"
+
+#include "testsuite-common.h"
+#include "testsuite-settings.h"
+#include "testsuite-objects.h"
+#include "testsuite-log.h"
+#include "testsuite-script.h"
+#include "testsuite-binary.h"
+#include "testsuite-result.h"
+#include "testsuite-smtp.h"
+
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+/*
+ * Global data
+ */
+
+struct sieve_instance *testsuite_sieve_instance = NULL;
+char *testsuite_test_path = NULL;
+
+/* Test context */
+
+static string_t *test_name;
+static sieve_size_t test_block_end;
+static unsigned int test_index;
+static unsigned int test_failures;
+
+/* Extension */
+
+const struct sieve_extension *testsuite_ext;
+
+/*
+ * Validator context
+ */
+
+bool testsuite_validator_context_initialize(struct sieve_validator *valdtr)
+{
+ pool_t pool = sieve_validator_pool(valdtr);
+ struct testsuite_validator_context *ctx =
+ p_new(pool, struct testsuite_validator_context, 1);
+
+ /* Setup object registry */
+ ctx->object_registrations =
+ sieve_validator_object_registry_create(valdtr);
+ testsuite_register_core_objects(ctx);
+
+ sieve_validator_extension_set_context(valdtr, testsuite_ext, ctx);
+
+ return TRUE;
+}
+
+struct testsuite_validator_context *
+testsuite_validator_context_get(struct sieve_validator *valdtr)
+{
+ return (struct testsuite_validator_context *)
+ sieve_validator_extension_get_context(valdtr, testsuite_ext);
+}
+
+/*
+ * Generator context
+ */
+
+bool testsuite_generator_context_initialize(
+ struct sieve_generator *gentr, const struct sieve_extension *this_ext)
+{
+ pool_t pool = sieve_generator_pool(gentr);
+ struct sieve_binary_block *sblock = sieve_generator_get_block(gentr);
+ struct testsuite_generator_context *ctx =
+ p_new(pool, struct testsuite_generator_context, 1);
+
+ /* Setup exit jumplist */
+ ctx->exit_jumps = sieve_jumplist_create(pool, sblock);
+
+ sieve_generator_extension_set_context(gentr, this_ext, ctx);
+
+ return TRUE;
+}
+
+/*
+ * Interpreter context
+ */
+
+static void
+testsuite_interpreter_free(const struct sieve_extension *ext ATTR_UNUSED,
+ struct sieve_interpreter *interp ATTR_UNUSED,
+ void *context)
+{
+ struct testsuite_interpreter_context *ctx =
+ (struct testsuite_interpreter_context *)context;
+
+ sieve_binary_unref(&ctx->compiled_script);
+}
+
+const struct sieve_interpreter_extension testsuite_interpreter_ext = {
+ .ext_def = &testsuite_extension,
+ .free = testsuite_interpreter_free,
+};
+
+bool testsuite_interpreter_context_initialize(
+ struct sieve_interpreter *interp, const struct sieve_extension *this_ext)
+{
+ pool_t pool = sieve_interpreter_pool(interp);
+ struct testsuite_interpreter_context *ctx =
+ p_new(pool, struct testsuite_interpreter_context, 1);
+
+ sieve_interpreter_extension_register(interp, this_ext,
+ &testsuite_interpreter_ext, ctx);
+ return TRUE;
+}
+
+struct testsuite_interpreter_context *
+testsuite_interpreter_context_get(struct sieve_interpreter *interp,
+ const struct sieve_extension *this_ext)
+{
+ struct testsuite_interpreter_context *ctx =
+ sieve_interpreter_extension_get_context(interp, this_ext);
+
+ return ctx;
+}
+
+/*
+ * Test context
+ */
+
+static void testsuite_test_context_init(void)
+{
+ test_name = str_new(default_pool, 128);
+ test_block_end = 0;
+ test_index = 0;
+ test_failures = 0;
+}
+
+int testsuite_test_start(const struct sieve_runtime_env *renv,
+ string_t *name, sieve_size_t block_end)
+{
+ if (test_block_end != 0) {
+ sieve_runtime_trace_error(renv, "already inside test block");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ str_truncate(test_name, 0);
+ str_append_str(test_name, name);
+
+ test_block_end = block_end;
+ test_index++;
+
+ return SIEVE_EXEC_OK;
+}
+
+int testsuite_test_fail(const struct sieve_runtime_env *renv,
+ string_t *reason)
+{
+ return testsuite_test_fail_cstr(renv, str_c(reason));
+}
+
+int testsuite_test_failf(const struct sieve_runtime_env *renv,
+ const char *fmt, ...)
+{
+ va_list args;
+ int ret;
+
+ va_start(args, fmt);
+ ret = testsuite_test_fail_cstr(renv, t_strdup_vprintf(fmt, args));
+ va_end(args);
+
+ return ret;
+}
+
+int testsuite_test_fail_cstr(const struct sieve_runtime_env *renv,
+ const char *reason)
+{
+ sieve_size_t end = test_block_end;
+
+ if (str_len(test_name) == 0) {
+ if (reason == NULL || *reason == '\0')
+ printf("%2d: Test FAILED\n", test_index);
+ else
+ printf("%2d: Test FAILED: %s\n", test_index, reason);
+ } else {
+ if (reason == NULL || *reason == '\0') {
+ printf("%2d: Test '%s' FAILED\n",
+ test_index, str_c(test_name));
+ } else {
+ printf("%2d: Test '%s' FAILED: %s\n",
+ test_index, str_c(test_name), reason);
+ }
+ }
+
+ str_truncate(test_name, 0);
+ test_block_end = 0;
+
+ test_failures++;
+
+ return sieve_interpreter_program_jump_to(renv->interp, end, FALSE);
+}
+
+void testsuite_testcase_fail(const char *reason)
+{
+ if (reason == NULL || *reason == '\0')
+ printf("XX: Test CASE FAILED\n");
+ else
+ printf("XX: Test CASE FAILED: %s\n", reason);
+
+ test_failures++;
+}
+
+int testsuite_test_succeed(const struct sieve_runtime_env *renv,
+ sieve_size_t *address, string_t *reason)
+{
+ sieve_size_t end = test_block_end;
+ int ret;
+
+ if (str_len(test_name) == 0) {
+ if (reason == NULL || str_len(reason) == 0)
+ printf("%2d: Test SUCCEEDED\n", test_index);
+ else {
+ printf("%2d: Test SUCCEEDED: %s\n",
+ test_index, str_c(reason));
+ }
+ } else {
+ if (reason == NULL || str_len(reason) == 0) {
+ printf("%2d: Test '%s' SUCCEEDED\n",
+ test_index, str_c(test_name));
+ } else {
+ printf("%2d: Test '%s' SUCCEEDED: %s\n", test_index,
+ str_c(test_name), str_c(reason));
+ }
+ }
+
+ str_truncate(test_name, 0);
+ test_block_end = 0;
+
+ if (*address > end) {
+ sieve_runtime_trace_error(
+ renv, "invalid test block end offset");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ } else if (*address < end) {
+ ret = sieve_interpreter_program_jump_to(
+ renv->interp, end, FALSE);
+ if (ret <= 0)
+ return ret;
+ }
+
+ return SIEVE_EXEC_OK;
+}
+
+static void testsuite_test_context_deinit(void)
+{
+ str_free(&test_name);
+}
+
+bool testsuite_testcase_result(bool expect_failure)
+{
+ if (expect_failure) {
+ if (test_failures < test_index) {
+ printf("\nFAIL: Only %d of %d tests failed "
+ "(all expected to fail).\n\n",
+ test_failures, test_index);
+ return FALSE;
+ }
+
+ printf("\nPASS: %d tests failed (expected to fail).\n\n",
+ (test_index == 0 ? 1 : test_index));
+ return TRUE;
+ }
+
+ if (test_failures > 0) {
+ printf("\nFAIL: %d of %d tests failed.\n\n",
+ test_failures, test_index);
+ return FALSE;
+ }
+
+ printf("\nPASS: %d tests succeeded.\n\n", test_index);
+ return TRUE;
+}
+
+/*
+ * Testsuite temporary directory
+ */
+
+static char *testsuite_tmp_dir;
+
+static void testsuite_tmp_dir_init(void)
+{
+ testsuite_tmp_dir = i_strdup_printf("/tmp/dsieve-testsuite.%s.%s",
+ dec2str(time(NULL)),
+ dec2str(getpid()));
+
+ if (mkdir(testsuite_tmp_dir, 0700) < 0) {
+ i_fatal("failed to create temporary directory '%s': %m.",
+ testsuite_tmp_dir);
+ }
+}
+
+static void testsuite_tmp_dir_deinit(void)
+{
+ const char *error;
+
+ if (unlink_directory(testsuite_tmp_dir,
+ UNLINK_DIRECTORY_FLAG_RMDIR, &error) < 0)
+ i_warning("failed to remove temporary directory '%s': %s.",
+ testsuite_tmp_dir, error);
+
+ i_free(testsuite_tmp_dir);
+}
+
+const char *testsuite_tmp_dir_get(void)
+{
+ return testsuite_tmp_dir;
+}
+
+/*
+ * Main testsuite init/deinit
+ */
+
+void testsuite_init(struct sieve_instance *svinst, const char *test_path,
+ bool log_stdout)
+{
+ testsuite_sieve_instance = svinst;
+
+ testsuite_test_context_init();
+ testsuite_log_init(log_stdout);
+ testsuite_tmp_dir_init();
+
+ testsuite_script_init();
+ testsuite_binary_init();
+ testsuite_smtp_init();
+
+ testsuite_ext =
+ sieve_extension_register(svinst, &testsuite_extension, TRUE);
+
+ testsuite_test_path = i_strdup(test_path);
+}
+
+void testsuite_deinit(void)
+{
+ i_free(testsuite_test_path);
+
+ testsuite_smtp_deinit();
+ testsuite_binary_deinit();
+ testsuite_script_deinit();
+
+ testsuite_tmp_dir_deinit();
+ testsuite_log_deinit();
+ testsuite_test_context_deinit();
+}
diff --git a/pigeonhole/src/testsuite/testsuite-common.h b/pigeonhole/src/testsuite/testsuite-common.h
new file mode 100644
index 0000000..9a40cdd
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-common.h
@@ -0,0 +1,193 @@
+#ifndef TESTSUITE_COMMON_H
+#define TESTSUITE_COMMON_H
+
+#include "sieve-common.h"
+
+#include "sieve-tool.h"
+
+/*
+ * Global data
+ */
+
+extern struct sieve_instance *testsuite_sieve_instance;
+
+extern const struct sieve_extension_def testsuite_extension;
+
+extern const struct sieve_extension *testsuite_ext;
+
+extern const struct sieve_script_env *testsuite_scriptenv;
+
+extern char *testsuite_test_path;
+
+
+/*
+ * Validator context
+ */
+
+struct testsuite_validator_context {
+ struct sieve_validator_object_registry *object_registrations;
+};
+
+bool testsuite_validator_context_initialize(struct sieve_validator *valdtr);
+struct testsuite_validator_context *
+testsuite_validator_context_get(struct sieve_validator *valdtr);
+
+/*
+ * Generator context
+ */
+
+struct testsuite_generator_context {
+ struct sieve_jumplist *exit_jumps;
+};
+
+bool testsuite_generator_context_initialize(
+ struct sieve_generator *gentr, const struct sieve_extension *this_ext);
+
+/*
+ * Interpreter context
+ */
+
+struct testsuite_interpreter_context {
+ struct sieve_binary *compiled_script;
+};
+
+bool testsuite_interpreter_context_initialize(
+ struct sieve_interpreter *interp,
+ const struct sieve_extension *this_ext);
+struct testsuite_interpreter_context *
+testsuite_interpreter_context_get(struct sieve_interpreter *interp,
+ const struct sieve_extension *this_ext);
+
+/*
+ * Commands
+ */
+
+extern const struct sieve_command_def cmd_test;
+extern const struct sieve_command_def cmd_test_fail;
+extern const struct sieve_command_def cmd_test_config_set;
+extern const struct sieve_command_def cmd_test_config_unset;
+extern const struct sieve_command_def cmd_test_config_reload;
+extern const struct sieve_command_def cmd_test_set;
+extern const struct sieve_command_def cmd_test_result_reset;
+extern const struct sieve_command_def cmd_test_result_print;
+extern const struct sieve_command_def cmd_test_message;
+extern const struct sieve_command_def cmd_test_message_print;
+extern const struct sieve_command_def cmd_test_mailbox;
+extern const struct sieve_command_def cmd_test_mailbox_create;
+extern const struct sieve_command_def cmd_test_mailbox_delete;
+extern const struct sieve_command_def cmd_test_binary_load;
+extern const struct sieve_command_def cmd_test_binary_save;
+extern const struct sieve_command_def cmd_test_imap_metadata_set;
+
+/*
+ * Tests
+ */
+
+extern const struct sieve_command_def tst_test_script_compile;
+extern const struct sieve_command_def tst_test_script_run;
+extern const struct sieve_command_def tst_test_multiscript;
+extern const struct sieve_command_def tst_test_error;
+extern const struct sieve_command_def tst_test_result_action;
+extern const struct sieve_command_def tst_test_result_execute;
+
+/*
+ * Operations
+ */
+
+enum testsuite_operation_code {
+ TESTSUITE_OPERATION_TEST,
+ TESTSUITE_OPERATION_TEST_FINISH,
+ TESTSUITE_OPERATION_TEST_FAIL,
+ TESTSUITE_OPERATION_TEST_CONFIG_SET,
+ TESTSUITE_OPERATION_TEST_CONFIG_UNSET,
+ TESTSUITE_OPERATION_TEST_CONFIG_RELOAD,
+ TESTSUITE_OPERATION_TEST_SET,
+ TESTSUITE_OPERATION_TEST_SCRIPT_COMPILE,
+ TESTSUITE_OPERATION_TEST_SCRIPT_RUN,
+ TESTSUITE_OPERATION_TEST_MULTISCRIPT,
+ TESTSUITE_OPERATION_TEST_ERROR,
+ TESTSUITE_OPERATION_TEST_RESULT_ACTION,
+ TESTSUITE_OPERATION_TEST_RESULT_EXECUTE,
+ TESTSUITE_OPERATION_TEST_RESULT_RESET,
+ TESTSUITE_OPERATION_TEST_RESULT_PRINT,
+ TESTSUITE_OPERATION_TEST_MESSAGE_SMTP,
+ TESTSUITE_OPERATION_TEST_MESSAGE_MAILBOX,
+ TESTSUITE_OPERATION_TEST_MESSAGE_PRINT,
+ TESTSUITE_OPERATION_TEST_MAILBOX_CREATE,
+ TESTSUITE_OPERATION_TEST_MAILBOX_DELETE,
+ TESTSUITE_OPERATION_TEST_BINARY_LOAD,
+ TESTSUITE_OPERATION_TEST_BINARY_SAVE,
+ TESTSUITE_OPERATION_TEST_IMAP_METADATA_SET
+};
+
+extern const struct sieve_operation_def test_operation;
+extern const struct sieve_operation_def test_finish_operation;
+extern const struct sieve_operation_def test_fail_operation;
+extern const struct sieve_operation_def test_config_set_operation;
+extern const struct sieve_operation_def test_config_unset_operation;
+extern const struct sieve_operation_def test_config_reload_operation;
+extern const struct sieve_operation_def test_set_operation;
+extern const struct sieve_operation_def test_script_compile_operation;
+extern const struct sieve_operation_def test_script_run_operation;
+extern const struct sieve_operation_def test_multiscript_operation;
+extern const struct sieve_operation_def test_error_operation;
+extern const struct sieve_operation_def test_result_action_operation;
+extern const struct sieve_operation_def test_result_execute_operation;
+extern const struct sieve_operation_def test_result_reset_operation;
+extern const struct sieve_operation_def test_result_print_operation;
+extern const struct sieve_operation_def test_message_smtp_operation;
+extern const struct sieve_operation_def test_message_mailbox_operation;
+extern const struct sieve_operation_def test_message_print_operation;
+extern const struct sieve_operation_def test_mailbox_create_operation;
+extern const struct sieve_operation_def test_mailbox_delete_operation;
+extern const struct sieve_operation_def test_binary_load_operation;
+extern const struct sieve_operation_def test_binary_save_operation;
+extern const struct sieve_operation_def test_imap_metadata_set_operation;
+
+/*
+ * Operands
+ */
+
+extern const struct sieve_operand_def testsuite_object_operand;
+extern const struct sieve_operand_def testsuite_substitution_operand;
+
+enum testsuite_operand_code {
+ TESTSUITE_OPERAND_OBJECT,
+ TESTSUITE_OPERAND_SUBSTITUTION,
+ TESTSUITE_OPERAND_NAMESPACE
+};
+
+/*
+ * Test context
+ */
+
+int testsuite_test_start(const struct sieve_runtime_env *renv,
+ string_t *name, sieve_size_t block_end);
+int testsuite_test_fail(const struct sieve_runtime_env *renv,
+ string_t *reason);
+int testsuite_test_failf(const struct sieve_runtime_env *renv,
+ const char *fmt, ...) ATTR_FORMAT(2, 3);
+int testsuite_test_fail_cstr(const struct sieve_runtime_env *renv,
+ const char *reason);
+
+int testsuite_test_succeed(const struct sieve_runtime_env *renv,
+ sieve_size_t *address, string_t *reason);
+
+void testsuite_testcase_fail(const char *reason);
+bool testsuite_testcase_result(bool expect_failure);
+
+/*
+ * Testsuite temporary directory
+ */
+
+const char *testsuite_tmp_dir_get(void);
+
+/*
+ * Testsuite init/deinit
+ */
+
+void testsuite_init(struct sieve_instance *svinst, const char *test_path,
+ bool log_stdout);
+void testsuite_deinit(void);
+
+#endif
diff --git a/pigeonhole/src/testsuite/testsuite-log.c b/pigeonhole/src/testsuite/testsuite-log.c
new file mode 100644
index 0000000..d06b744
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-log.c
@@ -0,0 +1,319 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-stringlist.h"
+#include "sieve-error-private.h"
+
+#include "testsuite-common.h"
+#include "testsuite-log.h"
+
+/*
+ * Configuration
+ */
+
+bool _testsuite_log_stdout = FALSE;
+
+/*
+ * Testsuite log error handlers
+ */
+
+struct sieve_error_handler *testsuite_log_ehandler = NULL;
+struct sieve_error_handler *testsuite_log_main_ehandler = NULL;
+
+struct _testsuite_log_message {
+ const char *location;
+ const char *message;
+};
+
+static pool_t _testsuite_logmsg_pool = NULL;
+ARRAY(struct _testsuite_log_message) _testsuite_log_errors;
+ARRAY(struct _testsuite_log_message) _testsuite_log_warnings;
+ARRAY(struct _testsuite_log_message) _testsuite_log_messages;
+
+static inline void
+_testsuite_stdout_log(const struct sieve_error_params *params,
+ const char *prefix, const char *message)
+{
+ if (_testsuite_log_stdout) {
+ if (params->location == NULL || *params->location == '\0') {
+ fprintf(stdout, "LOG: %s: %s\n",
+ prefix, message);
+ } else {
+ fprintf(stdout, "LOG: %s: %s: %s\n",
+ params->location, prefix, message);
+ }
+ }
+}
+
+static void
+_testsuite_log(struct sieve_error_handler *ehandler ATTR_UNUSED,
+ const struct sieve_error_params *params,
+ enum sieve_error_flags flags ATTR_UNUSED, const char *message)
+{
+ pool_t pool = _testsuite_logmsg_pool;
+ struct _testsuite_log_message msg;
+ const char *prefix;
+
+ switch (params->log_type) {
+ case LOG_TYPE_ERROR:
+ prefix = "error";
+ break;
+ case LOG_TYPE_WARNING:
+ prefix = "warning";
+ break;
+ case LOG_TYPE_INFO:
+ prefix = "info";
+ break;
+ case LOG_TYPE_DEBUG:
+ prefix = "debug";
+ break;
+ default:
+ i_unreached();
+ }
+
+ _testsuite_stdout_log(params, prefix, message);
+
+ msg.location = p_strdup(pool, params->location);
+ msg.message = p_strdup(pool, message);
+
+ switch (params->log_type) {
+ case LOG_TYPE_ERROR:
+ array_append(&_testsuite_log_errors, &msg, 1);
+ break;
+ case LOG_TYPE_WARNING:
+ array_append(&_testsuite_log_warnings, &msg, 1);
+ break;
+ case LOG_TYPE_INFO:
+ array_append(&_testsuite_log_messages, &msg, 1);
+ break;
+ case LOG_TYPE_DEBUG:
+ break;
+ default:
+ i_unreached();
+ }
+}
+
+static void
+_testsuite_main_log(struct sieve_error_handler *ehandler,
+ const struct sieve_error_params *params,
+ enum sieve_error_flags flags, const char *message)
+{
+ if (params->log_type != LOG_TYPE_ERROR)
+ return _testsuite_log(ehandler, params, flags, message);
+
+ if (params->location == NULL || *params->location == '\0')
+ fprintf(stderr, "error: %s\n", message);
+ else
+ fprintf(stderr, "%s: error: %s\n", params->location, message);
+}
+
+static struct sieve_error_handler *_testsuite_log_ehandler_create(void)
+{
+ pool_t pool;
+ struct sieve_error_handler *ehandler;
+
+ pool = pool_alloconly_create("testsuite_log_ehandler",
+ sizeof(struct sieve_error_handler));
+ ehandler = p_new(pool, struct sieve_error_handler, 1);
+ sieve_error_handler_init(ehandler, testsuite_sieve_instance, pool, 0);
+
+ ehandler->log = _testsuite_log;
+
+ return ehandler;
+}
+
+static struct sieve_error_handler *_testsuite_log_main_ehandler_create(void)
+{
+ pool_t pool;
+ struct sieve_error_handler *ehandler;
+
+ pool = pool_alloconly_create("testsuite_log_main_ehandler",
+ sizeof(struct sieve_error_handler));
+ ehandler = p_new(pool, struct sieve_error_handler, 1);
+ sieve_error_handler_init(ehandler, testsuite_sieve_instance, pool, 0);
+
+ ehandler->log = _testsuite_main_log;
+
+ return ehandler;
+}
+
+static void ATTR_FORMAT(2, 0)
+testsuite_error_handler(const struct failure_context *ctx, const char *fmt,
+ va_list args)
+{
+ struct sieve_error_params params = {
+ .location = NULL,
+ };
+ pool_t pool = _testsuite_logmsg_pool;
+ struct _testsuite_log_message msg;
+
+ i_zero(&msg);
+ switch (ctx->type) {
+ case LOG_TYPE_DEBUG:
+ T_BEGIN {
+ _testsuite_stdout_log(&params, "debug",
+ t_strdup_vprintf(fmt, args));
+ } T_END;
+ break;
+ case LOG_TYPE_INFO:
+ msg.message = p_strdup_vprintf(pool, fmt, args);
+ array_append(&_testsuite_log_messages, &msg, 1);
+
+ _testsuite_stdout_log(&params, "info", msg.message);
+ break;
+ case LOG_TYPE_WARNING:
+ msg.message = p_strdup_vprintf(pool, fmt, args);
+ array_append(&_testsuite_log_warnings, &msg, 1);
+
+ _testsuite_stdout_log(&params, "warning", msg.message);
+ break;
+ case LOG_TYPE_ERROR:
+ msg.message = p_strdup_vprintf(pool, fmt, args);
+ array_append(&_testsuite_log_errors, &msg, 1);
+
+ _testsuite_stdout_log(&params, "error", msg.message);
+ break;
+ default:
+ default_error_handler(ctx, fmt, args);
+ break;
+ }
+}
+
+/*
+ *
+ */
+
+void testsuite_log_clear_messages(void)
+{
+ if (_testsuite_logmsg_pool != NULL) {
+ if (array_count(&_testsuite_log_errors) == 0)
+ return;
+ pool_unref(&_testsuite_logmsg_pool);
+ }
+
+ _testsuite_logmsg_pool =
+ pool_alloconly_create("testsuite_log_messages", 8192);
+
+ p_array_init(&_testsuite_log_errors, _testsuite_logmsg_pool, 128);
+ p_array_init(&_testsuite_log_warnings, _testsuite_logmsg_pool, 128);
+ p_array_init(&_testsuite_log_messages, _testsuite_logmsg_pool, 128);
+
+ sieve_error_handler_reset(testsuite_log_ehandler);
+}
+
+/*
+ *
+ */
+
+void testsuite_log_init(bool log_stdout)
+{
+ _testsuite_log_stdout = log_stdout;
+
+ testsuite_log_ehandler = _testsuite_log_ehandler_create();
+ sieve_error_handler_accept_infolog(testsuite_log_ehandler, TRUE);
+ sieve_error_handler_accept_debuglog(testsuite_log_ehandler, TRUE);
+
+ testsuite_log_main_ehandler = _testsuite_log_main_ehandler_create();
+ sieve_error_handler_accept_infolog(testsuite_log_main_ehandler, TRUE);
+ sieve_error_handler_accept_debuglog(testsuite_log_main_ehandler, TRUE);
+
+ i_set_error_handler(testsuite_error_handler);
+ i_set_info_handler(testsuite_error_handler);
+ i_set_debug_handler(testsuite_error_handler);
+
+ testsuite_log_clear_messages();
+}
+
+void testsuite_log_deinit(void)
+{
+ sieve_error_handler_unref(&testsuite_log_ehandler);
+ sieve_error_handler_unref(&testsuite_log_main_ehandler);
+
+ i_set_error_handler(default_error_handler);
+ i_set_info_handler(default_error_handler);
+ i_set_debug_handler(default_error_handler);
+
+ pool_unref(&_testsuite_logmsg_pool);
+}
+
+/*
+ * Log stringlist
+ */
+
+/* Forward declarations */
+
+static int
+testsuite_log_stringlist_next_item(struct sieve_stringlist *_strlist,
+ string_t **str_r);
+static void testsuite_log_stringlist_reset(struct sieve_stringlist *_strlist);
+
+/* Stringlist object */
+
+struct testsuite_log_stringlist {
+ struct sieve_stringlist strlist;
+
+ int pos, index;
+};
+
+struct sieve_stringlist *
+testsuite_log_stringlist_create(const struct sieve_runtime_env *renv,
+ int index)
+{
+ struct testsuite_log_stringlist *strlist;
+
+ strlist = t_new(struct testsuite_log_stringlist, 1);
+ strlist->strlist.runenv = renv;
+ strlist->strlist.exec_status = SIEVE_EXEC_OK;
+ strlist->strlist.next_item = testsuite_log_stringlist_next_item;
+ strlist->strlist.reset = testsuite_log_stringlist_reset;
+
+ strlist->index = index;
+ strlist->pos = 0;
+
+ return &strlist->strlist;
+}
+
+static int
+testsuite_log_stringlist_next_item(struct sieve_stringlist *_strlist,
+ string_t **str_r)
+{
+ struct testsuite_log_stringlist *strlist =
+ (struct testsuite_log_stringlist *) _strlist;
+ const struct _testsuite_log_message *msg;
+ int pos;
+
+ *str_r = NULL;
+
+ if (strlist->pos < 0)
+ return 0;
+
+ if (strlist->index > 0) {
+ pos = strlist->index - 1;
+ strlist->pos = -1;
+ } else {
+ pos = strlist->pos++;
+ }
+
+ if (pos >= (int) array_count(&_testsuite_log_errors)) {
+ strlist->pos = -1;
+ return 0;
+ }
+
+ msg = array_idx(&_testsuite_log_errors, (unsigned int) pos);
+
+ *str_r = t_str_new_const(msg->message, strlen(msg->message));
+ return 1;
+}
+
+static void testsuite_log_stringlist_reset(struct sieve_stringlist *_strlist)
+{
+ struct testsuite_log_stringlist *strlist =
+ (struct testsuite_log_stringlist *) _strlist;
+
+ strlist->pos = 0;
+}
diff --git a/pigeonhole/src/testsuite/testsuite-log.h b/pigeonhole/src/testsuite/testsuite-log.h
new file mode 100644
index 0000000..335d044
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-log.h
@@ -0,0 +1,26 @@
+#ifndef TESTSUITE_LOG_H
+#define TESTSUITE_LOG_H
+
+#include "sieve-common.h"
+
+extern struct sieve_error_handler *testsuite_log_ehandler;
+extern struct sieve_error_handler *testsuite_log_main_ehandler;
+
+/*
+ * Initialization
+ */
+
+void testsuite_log_init(bool log_stdout);
+void testsuite_log_deinit(void);
+
+/*
+ * Access
+ */
+
+void testsuite_log_clear_messages(void);
+
+struct sieve_stringlist *
+testsuite_log_stringlist_create(const struct sieve_runtime_env *renv,
+ int index);
+
+#endif
diff --git a/pigeonhole/src/testsuite/testsuite-mailstore.c b/pigeonhole/src/testsuite/testsuite-mailstore.c
new file mode 100644
index 0000000..7762d50
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-mailstore.c
@@ -0,0 +1,349 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "mempool.h"
+#include "imem.h"
+#include "array.h"
+#include "strfuncs.h"
+#include "str-sanitize.h"
+#include "path-util.h"
+#include "unlink-directory.h"
+#include "env-util.h"
+#include "mail-namespace.h"
+#include "mail-storage.h"
+#include "imap-metadata.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-actions.h"
+#include "sieve-interpreter.h"
+
+#include "testsuite-message.h"
+#include "testsuite-common.h"
+#include "testsuite-smtp.h"
+
+#include "testsuite-mailstore.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+struct testsuite_mailstore_mail {
+ struct testsuite_mailstore_mail *next;
+
+ char *folder;
+ struct mailbox *box;
+ struct mailbox_transaction_context *trans;
+ struct mail *mail;
+};
+
+/*
+ * Forward declarations
+ */
+
+static void testsuite_mailstore_free(bool all);
+
+/*
+ * State
+ */
+
+static struct mail_user *testsuite_mailstore_user = NULL;
+
+static struct testsuite_mailstore_mail *testsuite_mailstore_mail = NULL;
+
+static char *testsuite_mailstore_location = NULL;
+static char *testsuite_mailstore_attrs = NULL;
+
+/*
+ * Initialization
+ */
+
+void testsuite_mailstore_init(void)
+{
+ struct mail_user *mail_user_dovecot, *mail_user;
+ struct mail_namespace *ns;
+ struct mail_namespace_settings *ns_set;
+ struct mail_storage_settings *mail_set;
+ const char *tmpdir, *error, *cwd;
+
+ tmpdir = testsuite_tmp_dir_get();
+ testsuite_mailstore_location =
+ i_strconcat(tmpdir, "/mailstore", NULL);
+ testsuite_mailstore_attrs =
+ i_strconcat(tmpdir, "/mail-attrs.dict", NULL);
+
+ if (mkdir(testsuite_mailstore_location, 0700) < 0) {
+ i_fatal("failed to create temporary directory '%s': %m.",
+ testsuite_mailstore_location);
+ }
+
+ mail_user_dovecot = sieve_tool_get_mail_user(sieve_tool);
+ mail_user = mail_user_alloc(NULL, "testsuite-mail-user@example.org",
+ mail_user_dovecot->set_info,
+ mail_user_dovecot->unexpanded_set);
+ mail_user->autocreated = TRUE;
+ if (t_get_working_dir(&cwd, &error) < 0)
+ i_fatal("Failed to get working directory: %s", error);
+ mail_user_set_home(mail_user, cwd);
+ if (mail_user_init(mail_user, &error) < 0)
+ i_fatal("Testsuite user initialization failed: %s", error);
+
+ ns_set = p_new(mail_user->pool, struct mail_namespace_settings, 1);
+ ns_set->location = testsuite_mailstore_location;
+ ns_set->separator = ".";
+
+ ns = mail_namespaces_init_empty(mail_user);
+ ns->flags |= NAMESPACE_FLAG_INBOX_USER;
+ ns->set = ns_set;
+ /* absolute paths are ok with raw storage */
+ mail_set = p_new(mail_user->pool, struct mail_storage_settings, 1);
+ *mail_set = *ns->mail_set;
+ mail_set->mail_location = p_strconcat(
+ mail_user->pool, "maildir:",
+ testsuite_mailstore_location, NULL);
+ mail_set->mail_attribute_dict = p_strconcat(
+ mail_user->pool, "file:",
+ testsuite_mailstore_attrs, NULL);
+ ns->mail_set = mail_set;
+
+ if (mail_storage_create(ns, "maildir", 0, &error) < 0)
+ i_fatal("Couldn't create testsuite storage: %s", error);
+ if (mail_namespaces_init_finish(ns, &error) < 0)
+ i_fatal("Couldn't create testsuite namespace: %s", error);
+
+ testsuite_mailstore_user = mail_user;
+}
+
+void testsuite_mailstore_deinit(void)
+{
+ const char *error;
+
+ testsuite_mailstore_free(TRUE);
+
+ if (unlink_directory(testsuite_mailstore_location,
+ UNLINK_DIRECTORY_FLAG_RMDIR, &error) < 0) {
+ i_warning("failed to remove temporary directory '%s': %s.",
+ testsuite_mailstore_location, error);
+ }
+
+ i_free(testsuite_mailstore_location);
+ i_free(testsuite_mailstore_attrs);
+ mail_user_unref(&testsuite_mailstore_user);
+}
+
+/*
+ * Mail user
+ */
+
+struct mail_user *testsuite_mailstore_get_user(void)
+{
+ if (testsuite_mailstore_user == NULL)
+ return sieve_tool_get_mail_user(sieve_tool);
+ return testsuite_mailstore_user;
+}
+
+/*
+ * Mailbox Access
+ */
+
+bool testsuite_mailstore_mailbox_create(
+ const struct sieve_runtime_env *renv ATTR_UNUSED, const char *folder)
+{
+ struct mail_user *mail_user = testsuite_mailstore_user;
+ struct mail_namespace *ns = mail_user->namespaces;
+ struct mailbox *box;
+
+ box = mailbox_alloc(ns->list, folder, 0);
+
+ if (mailbox_create(box, NULL, FALSE) < 0) {
+ mailbox_free(&box);
+ return FALSE;
+ }
+
+ mailbox_free(&box);
+
+ return TRUE;
+}
+
+static struct testsuite_mailstore_mail *
+testsuite_mailstore_open(const char *folder)
+{
+ enum mailbox_flags flags =
+ MAILBOX_FLAG_SAVEONLY | MAILBOX_FLAG_POST_SESSION;
+ struct mail_user *mail_user = testsuite_mailstore_user;
+ struct mail_namespace *ns = mail_user->namespaces;
+ struct mailbox *box;
+ struct mailbox_transaction_context *t;
+ struct testsuite_mailstore_mail *tmail, *tmail_prev;
+ const char *error;
+
+ if (!sieve_mailbox_check_name(folder, &error)) {
+ e_error(testsuite_sieve_instance->event,
+ "testsuite: invalid mailbox name `%s' specified: %s",
+ folder, error);
+ return NULL;
+ }
+
+ tmail = testsuite_mailstore_mail;
+ tmail_prev = NULL;
+ while (tmail != NULL) {
+ if (strcmp(tmail->folder, folder) == 0) {
+ if (tmail_prev != NULL) {
+ /* Remove it from list if it is not first. */
+ tmail_prev->next = tmail->next;
+ }
+ break;
+ }
+ tmail_prev = tmail;
+ tmail = tmail->next;
+ }
+ if (tmail != NULL) {
+ if (tmail != testsuite_mailstore_mail) {
+ /* Bring it to front */
+ tmail->next = testsuite_mailstore_mail;
+ testsuite_mailstore_mail = tmail;
+ }
+ return tmail;
+ }
+
+ box = mailbox_alloc(ns->list, folder, flags);
+ if (mailbox_open(box) < 0) {
+ e_error(testsuite_sieve_instance->event,
+ "testsuite: failed to open mailbox '%s'", folder);
+ mailbox_free(&box);
+ return NULL;
+ }
+
+ /* Sync mailbox */
+
+ if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
+ e_error(testsuite_sieve_instance->event,
+ "testsuite: failed to sync mailbox '%s'", folder);
+ mailbox_free(&box);
+ return NULL;
+ }
+
+ /* Start transaction */
+
+ t = mailbox_transaction_begin(box, 0, __func__);
+
+ tmail = i_new(struct testsuite_mailstore_mail, 1);
+ tmail->next = testsuite_mailstore_mail;
+ testsuite_mailstore_mail = tmail;
+
+ tmail->folder = i_strdup(folder);
+ tmail->box = box;
+ tmail->trans = t;
+ tmail->mail = mail_alloc(t, 0, NULL);
+
+ return tmail;
+}
+
+static void testsuite_mailstore_free(bool all)
+{
+ struct testsuite_mailstore_mail *tmail;
+
+ if (testsuite_mailstore_mail == NULL)
+ return;
+
+ tmail = (all ?
+ testsuite_mailstore_mail : testsuite_mailstore_mail->next);
+ while (tmail != NULL) {
+ struct testsuite_mailstore_mail *tmail_next = tmail->next;
+
+ mail_free(&tmail->mail);
+ mailbox_transaction_rollback(&tmail->trans);
+ mailbox_free(&tmail->box);
+ i_free(tmail->folder);
+ i_free(tmail);
+
+ tmail = tmail_next;
+ }
+ if (all)
+ testsuite_mailstore_mail = NULL;
+ else
+ testsuite_mailstore_mail->next = NULL;
+}
+
+void testsuite_mailstore_flush(void)
+{
+ testsuite_mailstore_free(FALSE);
+}
+
+bool testsuite_mailstore_mail_index(const struct sieve_runtime_env *renv,
+ const char *folder, unsigned int index)
+{
+ struct testsuite_mailstore_mail *tmail;
+ struct mailbox_status status;
+
+ tmail = testsuite_mailstore_open(folder);
+ if (tmail == NULL)
+ return FALSE;
+
+ mailbox_get_open_status(tmail->box, STATUS_MESSAGES, &status);
+ if (index >= status.messages)
+ return FALSE;
+
+ mail_set_seq(tmail->mail, index+1);
+ testsuite_message_set_mail(renv, tmail->mail);
+
+ return TRUE;
+}
+
+/*
+ * IMAP metadata
+ */
+
+int testsuite_mailstore_set_imap_metadata(const char *mailbox,
+ const char *annotation,
+ const char *value)
+{
+ struct imap_metadata_transaction *imtrans;
+ struct mail_attribute_value avalue;
+ struct mailbox *box;
+ enum mail_error error_code;
+ const char *error;
+ int ret;
+
+ if (!imap_metadata_verify_entry_name(annotation, &error)) {
+ e_error(testsuite_sieve_instance->event,
+ "testsuite: imap metadata: "
+ "specified annotation name `%s' is invalid: %s",
+ str_sanitize(annotation, 256), error);
+ return -1;
+ }
+
+ if (mailbox != NULL) {
+ struct mail_namespace *ns;
+ ns = mail_namespace_find(testsuite_mailstore_user->namespaces,
+ mailbox);
+ box = mailbox_alloc(ns->list, mailbox, 0);
+ imtrans = imap_metadata_transaction_begin(box);
+ } else {
+ box = NULL;
+ imtrans = imap_metadata_transaction_begin_server(
+ testsuite_mailstore_user);
+ }
+
+ i_zero(&avalue);
+ avalue.value = value;
+ if ((ret = imap_metadata_set(imtrans, annotation, &avalue)) < 0) {
+ error = imap_metadata_transaction_get_last_error(
+ imtrans, &error_code);
+ imap_metadata_transaction_rollback(&imtrans);
+ } else {
+ ret = imap_metadata_transaction_commit(&imtrans,
+ &error_code, &error);
+ }
+ if (box != NULL)
+ mailbox_free(&box);
+
+ if (ret < 0) {
+ e_error(testsuite_sieve_instance->event,
+ "testsuite: imap metadata: "
+ "failed to assign annotation `%s': %s",
+ str_sanitize(annotation, 256), error);
+ return -1;
+ }
+ return 0;
+}
diff --git a/pigeonhole/src/testsuite/testsuite-mailstore.h b/pigeonhole/src/testsuite/testsuite-mailstore.h
new file mode 100644
index 0000000..07b0ab0
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-mailstore.h
@@ -0,0 +1,40 @@
+#ifndef TESTSUITE_MAILSTORE_H
+#define TESTSUITE_MAILSTORE_H
+
+#include "lib.h"
+
+#include "sieve-common.h"
+
+/*
+ * Initialization
+ */
+
+void testsuite_mailstore_init(void);
+void testsuite_mailstore_deinit(void);
+void testsuite_mailstore_flush(void);
+
+/*
+ * Mail user
+ */
+
+struct mail_user *testsuite_mailstore_get_user(void);
+
+/*
+ * Mailbox Access
+ */
+
+bool testsuite_mailstore_mailbox_create(
+ const struct sieve_runtime_env *renv ATTR_UNUSED, const char *folder);
+
+bool testsuite_mailstore_mail_index(const struct sieve_runtime_env *renv,
+ const char *folder, unsigned int index);
+
+/*
+ * IMAP metadata
+ */
+
+int testsuite_mailstore_set_imap_metadata(const char *mailbox,
+ const char *annotation,
+ const char *value);
+
+#endif
diff --git a/pigeonhole/src/testsuite/testsuite-message.c b/pigeonhole/src/testsuite/testsuite-message.c
new file mode 100644
index 0000000..68e20eb
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-message.c
@@ -0,0 +1,339 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "istream.h"
+#include "smtp-params.h"
+#include "message-address.h"
+#include "mail-storage.h"
+#include "master-service.h"
+#include "mail-raw.h"
+
+#include "sieve-common.h"
+#include "sieve-address.h"
+#include "sieve-error.h"
+#include "sieve-message.h"
+#include "sieve-interpreter.h"
+
+#include "sieve-tool.h"
+
+#include "testsuite-common.h"
+#include "testsuite-message.h"
+
+/*
+ * Testsuite message environment
+ */
+
+struct testsuite_message {
+ struct testsuite_message *next;
+
+ struct mail_raw *mail_raw;
+};
+
+struct sieve_message_data testsuite_msgdata;
+static struct smtp_params_rcpt testsuite_rcpt_params;
+
+static struct testsuite_message *testsuite_msg;
+
+static const char *_default_message_data =
+"From: sender@example.com\n"
+"To: recipient@example.org\n"
+"Subject: Frop!\n"
+"\n"
+"Friep!\n";
+
+static struct smtp_address *testsuite_env_mail_from = NULL;
+static struct smtp_address *testsuite_env_rcpt_to = NULL;
+static struct smtp_address *testsuite_env_orig_rcpt_to = NULL;
+static char *testsuite_env_auth = NULL;
+
+static pool_t testsuite_msg_pool;
+static char *testsuite_msg_id = NULL;
+
+static const struct smtp_address *
+testsuite_message_get_address(struct mail *mail, const char *header)
+{
+ struct message_address *addr;
+ struct smtp_address *smtp_addr;
+ const char *str;
+
+ if (mail_get_first_header(mail, header, &str) <= 0)
+ return NULL;
+ addr = message_address_parse(pool_datastack_create(),
+ (const unsigned char *)str,
+ strlen(str), 1, 0);
+ if (addr == NULL || addr->mailbox == NULL || *addr->mailbox == '\0')
+ return NULL;
+ if (smtp_address_create_from_msg_temp(addr, &smtp_addr) < 0)
+ return NULL;
+ return smtp_addr;
+}
+
+static void testsuite_message_set_data(struct mail *mail)
+{
+ const struct smtp_address *recipient = NULL, *sender = NULL;
+ const char *msg_id;
+
+ static const struct smtp_address default_recipient = {
+ .localpart = "recipient",
+ .domain = "example.com",
+ };
+ static const struct smtp_address default_sender = {
+ .localpart = "sender",
+ .domain = "example.com",
+ };
+
+ i_free(testsuite_env_mail_from);
+ i_free(testsuite_env_rcpt_to);
+ i_free(testsuite_env_orig_rcpt_to);
+ i_free(testsuite_env_auth);
+ i_free(testsuite_msg_id);
+
+ /*
+ * Collect necessary message data
+ */
+
+ /* Get recipient address */
+ recipient = testsuite_message_get_address(mail, "Envelope-To");
+ if (recipient == NULL)
+ recipient = testsuite_message_get_address(mail, "To");
+ if (recipient == NULL)
+ recipient = &default_recipient;
+
+ /* Get sender address */
+ sender = testsuite_message_get_address(mail, "Return-path");
+ if (sender == NULL)
+ sender = testsuite_message_get_address(mail, "Sender");
+ if (sender == NULL)
+ sender = testsuite_message_get_address(mail, "From");
+ if (sender == NULL)
+ sender = &default_sender;
+
+ testsuite_env_mail_from = smtp_address_clone(default_pool, sender);
+ testsuite_env_rcpt_to = smtp_address_clone(default_pool, recipient);
+ testsuite_env_orig_rcpt_to = smtp_address_clone(default_pool, recipient);
+
+ (void)mail_get_message_id(mail, &msg_id);
+ testsuite_msg_id = i_strdup(msg_id);
+
+ i_zero(&testsuite_msgdata);
+ testsuite_msgdata.mail = mail;
+ testsuite_msgdata.auth_user = sieve_tool_get_username(sieve_tool);
+ testsuite_msgdata.envelope.mail_from = testsuite_env_mail_from;
+ testsuite_msgdata.envelope.rcpt_to = testsuite_env_rcpt_to;
+ testsuite_msgdata.id = testsuite_msg_id;
+
+ i_zero(&testsuite_rcpt_params);
+ testsuite_rcpt_params.orcpt.addr = testsuite_env_orig_rcpt_to;
+
+ testsuite_msgdata.envelope.rcpt_params = &testsuite_rcpt_params;
+}
+
+static struct testsuite_message *testsuite_message_new(void)
+{
+ struct testsuite_message *msg;
+
+ msg = i_new(struct testsuite_message, 1);
+ msg->next = testsuite_msg;
+ testsuite_msg = msg;
+
+ return msg;
+}
+
+static void testsuite_message_new_string(string_t *mail_str)
+{
+ struct mail_user *mail_raw_user =
+ sieve_tool_get_mail_raw_user(sieve_tool);
+ struct testsuite_message *msg;
+
+ msg = testsuite_message_new();
+ msg->mail_raw = mail_raw_open_data(mail_raw_user, mail_str);
+
+ testsuite_message_set_data(msg->mail_raw->mail);
+}
+
+static void testsuite_message_new_file(const char *mail_path)
+{
+ struct mail_user *mail_raw_user =
+ sieve_tool_get_mail_raw_user(sieve_tool);
+ struct testsuite_message *msg;
+
+ msg = testsuite_message_new();
+ msg->mail_raw = mail_raw_open_file(mail_raw_user, mail_path);
+
+ testsuite_message_set_data(msg->mail_raw->mail);
+}
+
+static void testsuite_message_free(bool all)
+{
+ struct testsuite_message *msg;
+
+ if (testsuite_msg == NULL)
+ return;
+
+ msg = (all ? testsuite_msg : testsuite_msg->next);
+ while (msg != NULL) {
+ struct testsuite_message *msg_next = msg->next;
+
+ mail_raw_close(&msg->mail_raw);
+ i_free(msg);
+
+ msg = msg_next;
+ }
+ if (all)
+ testsuite_msg = NULL;
+ else
+ testsuite_msg->next = NULL;
+}
+
+void testsuite_message_flush(void)
+{
+ testsuite_message_free(FALSE);
+}
+
+void testsuite_message_init(void)
+{
+ testsuite_msg_pool = pool_alloconly_create("testsuite_message", 6096);
+
+ string_t *default_message = str_new(testsuite_msg_pool, 1024);
+ str_append(default_message, _default_message_data);
+
+ testsuite_message_new_string(default_message);
+}
+
+void testsuite_message_set_string(const struct sieve_runtime_env *renv,
+ string_t *message)
+{
+ sieve_message_context_reset(renv->msgctx);
+
+ testsuite_message_new_string(message);
+}
+
+void testsuite_message_set_file(const struct sieve_runtime_env *renv,
+ const char *file_path)
+{
+ sieve_message_context_reset(renv->msgctx);
+
+ testsuite_message_new_file(file_path);
+}
+
+void testsuite_message_set_mail(const struct sieve_runtime_env *renv,
+ struct mail *mail)
+{
+ sieve_message_context_reset(renv->msgctx);
+
+ testsuite_message_set_data(mail);
+}
+
+void testsuite_message_deinit(void)
+{
+ testsuite_message_free(TRUE);
+
+ i_free(testsuite_env_mail_from);
+ i_free(testsuite_env_rcpt_to);
+ i_free(testsuite_env_orig_rcpt_to);
+ i_free(testsuite_env_auth);
+ pool_unref(&testsuite_msg_pool);
+ i_free(testsuite_msg_id);
+}
+
+void testsuite_envelope_set_sender_address(const struct sieve_runtime_env *renv,
+ const struct smtp_address *address)
+{
+ sieve_message_context_reset(renv->msgctx);
+
+ i_free(testsuite_env_mail_from);
+
+ testsuite_env_mail_from = smtp_address_clone(default_pool, address);
+ testsuite_msgdata.envelope.mail_from = testsuite_env_mail_from;
+}
+
+void testsuite_envelope_set_sender(const struct sieve_runtime_env *renv,
+ const char *value)
+{
+ struct smtp_address *address = NULL;
+ const char *error;
+
+ if (smtp_address_parse_path(pool_datastack_create(), value,
+ (SMTP_ADDRESS_PARSE_FLAG_ALLOW_EMPTY |
+ SMTP_ADDRESS_PARSE_FLAG_BRACKETS_OPTIONAL),
+ &address, &error) < 0) {
+ e_error(testsuite_sieve_instance->event,
+ "testsuite: envelope sender address "
+ "`%s' is invalid: %s", value, error);
+ }
+ testsuite_envelope_set_sender_address(renv, address);
+}
+
+void testsuite_envelope_set_recipient_address(
+ const struct sieve_runtime_env *renv,
+ const struct smtp_address *address)
+{
+ sieve_message_context_reset(renv->msgctx);
+
+ i_free(testsuite_env_rcpt_to);
+ i_free(testsuite_env_orig_rcpt_to);
+
+ testsuite_env_rcpt_to = smtp_address_clone(default_pool, address);
+ testsuite_env_orig_rcpt_to = smtp_address_clone(default_pool, address);
+ testsuite_msgdata.envelope.rcpt_to = testsuite_env_rcpt_to;
+ testsuite_rcpt_params.orcpt.addr = testsuite_env_orig_rcpt_to;
+}
+
+void testsuite_envelope_set_recipient(const struct sieve_runtime_env *renv,
+ const char *value)
+{
+ struct smtp_address *address = NULL;
+ const char *error;
+
+ if (smtp_address_parse_path(pool_datastack_create(), value,
+ (SMTP_ADDRESS_PARSE_FLAG_ALLOW_LOCALPART |
+ SMTP_ADDRESS_PARSE_FLAG_BRACKETS_OPTIONAL),
+ &address, &error) < 0) {
+ e_error(testsuite_sieve_instance->event,
+ "testsuite: envelope recipient address "
+ "`%s' is invalid: %s", value, error);
+ }
+ testsuite_envelope_set_recipient_address(renv, address);
+}
+
+void testsuite_envelope_set_orig_recipient_address(
+ const struct sieve_runtime_env *renv,
+ const struct smtp_address *address)
+{
+ sieve_message_context_reset(renv->msgctx);
+
+ i_free(testsuite_env_orig_rcpt_to);
+
+ testsuite_env_orig_rcpt_to = smtp_address_clone(default_pool, address);
+ testsuite_rcpt_params.orcpt.addr = testsuite_env_orig_rcpt_to;
+}
+
+void testsuite_envelope_set_orig_recipient(const struct sieve_runtime_env *renv,
+ const char *value)
+{
+ struct smtp_address *address = NULL;
+ const char *error;
+
+ if (smtp_address_parse_path(pool_datastack_create(), value,
+ (SMTP_ADDRESS_PARSE_FLAG_ALLOW_LOCALPART |
+ SMTP_ADDRESS_PARSE_FLAG_BRACKETS_OPTIONAL),
+ &address, &error) < 0) {
+ e_error(testsuite_sieve_instance->event,
+ "testsuite: envelope recipient address "
+ "`%s' is invalid: %s", value, error);
+ }
+ testsuite_envelope_set_orig_recipient_address(renv, address);
+}
+
+void testsuite_envelope_set_auth_user(const struct sieve_runtime_env *renv,
+ const char *value)
+{
+ sieve_message_context_reset(renv->msgctx);
+
+ i_free(testsuite_env_auth);
+
+ testsuite_env_auth = i_strdup(value);
+ testsuite_msgdata.auth_user = testsuite_env_auth;
+}
diff --git a/pigeonhole/src/testsuite/testsuite-message.h b/pigeonhole/src/testsuite/testsuite-message.h
new file mode 100644
index 0000000..2a4d3b4
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-message.h
@@ -0,0 +1,44 @@
+#ifndef TESTSUITE_MESSAGE_H
+#define TESTSUITE_MESSAGE_H
+
+#include "lib.h"
+#include "master-service.h"
+
+#include "sieve-common.h"
+#include "sieve-tool.h"
+
+extern struct sieve_message_data testsuite_msgdata;
+
+void testsuite_message_init(void);
+void testsuite_message_deinit(void);
+
+void testsuite_message_flush(void);
+
+void testsuite_message_set_string(const struct sieve_runtime_env *renv,
+ string_t *message);
+void testsuite_message_set_file(const struct sieve_runtime_env *renv,
+ const char *file_path);
+void testsuite_message_set_mail(const struct sieve_runtime_env *renv,
+ struct mail *mail);
+
+void testsuite_envelope_set_sender_address(const struct sieve_runtime_env *renv,
+ const struct smtp_address *address);
+void testsuite_envelope_set_sender(const struct sieve_runtime_env *renv,
+ const char *value);
+
+void testsuite_envelope_set_recipient_address(
+ const struct sieve_runtime_env *renv,
+ const struct smtp_address *address);
+void testsuite_envelope_set_recipient(const struct sieve_runtime_env *renv,
+ const char *value);
+
+void testsuite_envelope_set_orig_recipient_address(
+ const struct sieve_runtime_env *renv,
+ const struct smtp_address *address);
+void testsuite_envelope_set_orig_recipient(const struct sieve_runtime_env *renv,
+ const char *value);
+
+void testsuite_envelope_set_auth_user(const struct sieve_runtime_env *renv,
+ const char *value);
+
+#endif
diff --git a/pigeonhole/src/testsuite/testsuite-objects.c b/pigeonhole/src/testsuite/testsuite-objects.c
new file mode 100644
index 0000000..4c09c85
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-objects.c
@@ -0,0 +1,369 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "string.h"
+#include "ostream.h"
+#include "hash.h"
+#include "mail-storage.h"
+
+#include "sieve.h"
+#include "sieve-code.h"
+#include "sieve-commands.h"
+#include "sieve-extensions.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+
+#include "testsuite-common.h"
+#include "testsuite-objects.h"
+#include "testsuite-message.h"
+
+/*
+ * Testsuite core objects
+ */
+
+enum testsuite_object_code {
+ TESTSUITE_OBJECT_MESSAGE,
+ TESTSUITE_OBJECT_ENVELOPE
+};
+
+const struct testsuite_object_def *testsuite_core_objects[] = {
+ &message_testsuite_object, &envelope_testsuite_object
+};
+
+const unsigned int testsuite_core_objects_count =
+ N_ELEMENTS(testsuite_core_objects);
+
+/*
+ * Testsuite object registry
+ */
+
+static inline struct sieve_validator_object_registry *_get_object_registry
+(struct sieve_validator *valdtr)
+{
+ struct testsuite_validator_context *ctx =
+ testsuite_validator_context_get(valdtr);
+
+ return ctx->object_registrations;
+}
+
+void testsuite_object_register
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ const struct testsuite_object_def *tobj_def)
+{
+ struct sieve_validator_object_registry *regs = _get_object_registry(valdtr);
+
+ sieve_validator_object_registry_add(regs, ext, &tobj_def->obj_def);
+}
+
+static const struct testsuite_object *testsuite_object_create
+(struct sieve_validator *valdtr, struct sieve_command *cmd,
+ const char *identifier)
+{
+ struct sieve_validator_object_registry *regs = _get_object_registry(valdtr);
+ struct sieve_object object;
+ struct testsuite_object *tobj;
+
+ if ( !sieve_validator_object_registry_find(regs, identifier, &object) )
+ return NULL;
+
+ tobj = p_new(sieve_command_pool(cmd), struct testsuite_object, 1);
+ tobj->object = object;
+ tobj->def = (const struct testsuite_object_def *) object.def;
+
+ return tobj;
+}
+
+void testsuite_register_core_objects
+(struct testsuite_validator_context *ctx)
+{
+ struct sieve_validator_object_registry *regs = ctx->object_registrations;
+ unsigned int i;
+
+ /* Register core testsuite objects */
+ for ( i = 0; i < testsuite_core_objects_count; i++ ) {
+ const struct testsuite_object_def *tobj_def = testsuite_core_objects[i];
+
+ sieve_validator_object_registry_add
+ (regs, testsuite_ext, &tobj_def->obj_def);
+ }
+}
+
+/*
+ * Testsuite object code
+ */
+
+const struct sieve_operand_class sieve_testsuite_object_operand_class =
+ { "testsuite object" };
+
+static const struct sieve_extension_objects core_testsuite_objects =
+ SIEVE_EXT_DEFINE_OBJECTS(testsuite_core_objects);
+
+const struct sieve_operand_def testsuite_object_operand = {
+ .name = "testsuite-object",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERAND_OBJECT,
+ .class = &sieve_testsuite_object_operand_class,
+ .interface = &core_testsuite_objects
+};
+
+static void testsuite_object_emit
+(struct sieve_binary_block *sblock, const struct testsuite_object *tobj,
+ int member_id)
+{
+ sieve_opr_object_emit(sblock, tobj->object.ext, tobj->object.def);
+
+ if ( tobj->def != NULL && tobj->def->get_member_id != NULL ) {
+ (void) sieve_binary_emit_byte(sblock, (unsigned char) member_id);
+ }
+}
+
+bool testsuite_object_read
+(struct sieve_binary_block *sblock, sieve_size_t *address,
+ struct testsuite_object *tobj)
+{
+ struct sieve_operand oprnd;
+
+ if ( !sieve_operand_read(sblock, address, NULL, &oprnd) )
+ return FALSE;
+
+ if ( !sieve_opr_object_read_data
+ (sblock, &oprnd, &sieve_testsuite_object_operand_class, address,
+ &tobj->object) )
+ return FALSE;
+
+ tobj->def = (const struct testsuite_object_def *) tobj->object.def;
+ i_assert(tobj->def != NULL);
+ return TRUE;
+}
+
+bool testsuite_object_read_member
+(struct sieve_binary_block *sblock, sieve_size_t *address,
+ struct testsuite_object *tobj, int *member_id_r)
+{
+ if ( !testsuite_object_read(sblock, address, tobj) )
+ return FALSE;
+
+ *member_id_r = -1;
+ if ( tobj->def->get_member_id != NULL ) {
+ if ( !sieve_binary_read_code(sblock, address, member_id_r) )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+const char *testsuite_object_member_name
+(const struct testsuite_object *object, int member_id)
+{
+ const struct testsuite_object_def *obj_def = object->def;
+ const char *member = NULL;
+
+ if ( obj_def->get_member_id != NULL ) {
+ if ( obj_def->get_member_name != NULL )
+ member = obj_def->get_member_name(member_id);
+ } else
+ return obj_def->obj_def.identifier;
+
+ if ( member == NULL )
+ return t_strdup_printf("%s.%d", obj_def->obj_def.identifier, member_id);
+
+ return t_strdup_printf("%s.%s", obj_def->obj_def.identifier, member);
+}
+
+bool testsuite_object_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ struct testsuite_object object;
+ int member_id;
+
+ sieve_code_mark(denv);
+
+ if ( !testsuite_object_read_member
+ (denv->sblock, address, &object, &member_id) )
+ return FALSE;
+
+ sieve_code_dumpf(denv, "%s: %s",
+ sieve_testsuite_object_operand_class.name,
+ testsuite_object_member_name(&object, member_id));
+
+ return TRUE;
+}
+
+/*
+ * Testsuite object argument
+ */
+
+static bool arg_testsuite_object_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd);
+
+const struct sieve_argument_def testsuite_object_argument = {
+ .identifier = "testsuite-object",
+ .generate = arg_testsuite_object_generate
+};
+
+struct testsuite_object_argctx {
+ const struct testsuite_object *object;
+ int member;
+};
+
+bool testsuite_object_argument_activate
+(struct sieve_validator *valdtr, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd)
+{
+ const char *objname = sieve_ast_argument_strc(arg);
+ const struct testsuite_object *tobj;
+ int member_id;
+ const char *member;
+ struct testsuite_object_argctx *ctx;
+
+ /* Parse the object specifier */
+
+ member = strchr(objname, '.');
+ if ( member != NULL ) {
+ objname = t_strdup_until(objname, member);
+ member++;
+ }
+
+ /* Find the object */
+
+ tobj = testsuite_object_create(valdtr, cmd, objname);
+ if ( tobj == NULL ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "unknown testsuite object '%s'", objname);
+ return FALSE;
+ }
+
+ /* Find the object member */
+
+ member_id = -1;
+ if ( member != NULL ) {
+ if ( tobj->def == NULL || tobj->def->get_member_id == NULL ||
+ (member_id=tobj->def->get_member_id(member)) == -1 ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "member '%s' does not exist for testsuite object '%s'", member, objname);
+ return FALSE;
+ }
+ }
+
+ /* Assign argument context */
+
+ ctx = p_new(sieve_command_pool(cmd), struct testsuite_object_argctx, 1);
+ ctx->object = tobj;
+ ctx->member = member_id;
+
+ arg->argument = sieve_argument_create
+ (arg->ast, &testsuite_object_argument, testsuite_ext, 0);
+ arg->argument->data = (void *) ctx;
+
+ return TRUE;
+}
+
+static bool arg_testsuite_object_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd ATTR_UNUSED)
+{
+ struct testsuite_object_argctx *ctx =
+ (struct testsuite_object_argctx *) arg->argument->data;
+
+ testsuite_object_emit(cgenv->sblock, ctx->object, ctx->member);
+
+ return TRUE;
+}
+
+/*
+ * Testsuite core object implementation
+ */
+
+static bool tsto_message_set_member
+ (const struct sieve_runtime_env *renv, int id, string_t *value);
+
+static int tsto_envelope_get_member_id(const char *identifier);
+static const char *tsto_envelope_get_member_name(int id);
+static bool tsto_envelope_set_member
+ (const struct sieve_runtime_env *renv, int id, string_t *value);
+
+const struct testsuite_object_def message_testsuite_object = {
+ SIEVE_OBJECT("message",
+ &testsuite_object_operand, TESTSUITE_OBJECT_MESSAGE),
+ .set_member = tsto_message_set_member
+};
+
+const struct testsuite_object_def envelope_testsuite_object = {
+ SIEVE_OBJECT("envelope",
+ &testsuite_object_operand, TESTSUITE_OBJECT_ENVELOPE),
+ .get_member_id = tsto_envelope_get_member_id,
+ .get_member_name = tsto_envelope_get_member_name,
+ .set_member = tsto_envelope_set_member
+};
+
+enum testsuite_object_envelope_field {
+ TESTSUITE_OBJECT_ENVELOPE_FROM,
+ TESTSUITE_OBJECT_ENVELOPE_TO,
+ TESTSUITE_OBJECT_ENVELOPE_ORIG_TO,
+ TESTSUITE_OBJECT_ENVELOPE_AUTH_USER
+};
+
+static bool tsto_message_set_member
+(const struct sieve_runtime_env *renv, int id, string_t *value)
+{
+ if ( id != -1 ) return FALSE;
+
+ testsuite_message_set_string(renv, value);
+
+ return TRUE;
+}
+
+static int tsto_envelope_get_member_id(const char *identifier)
+{
+ if ( strcasecmp(identifier, "from") == 0 )
+ return TESTSUITE_OBJECT_ENVELOPE_FROM;
+ if ( strcasecmp(identifier, "to") == 0 )
+ return TESTSUITE_OBJECT_ENVELOPE_TO;
+ if ( strcasecmp(identifier, "orig_to") == 0 )
+ return TESTSUITE_OBJECT_ENVELOPE_ORIG_TO;
+ if ( strcasecmp(identifier, "auth") == 0 )
+ return TESTSUITE_OBJECT_ENVELOPE_AUTH_USER;
+
+ return -1;
+}
+
+static const char *tsto_envelope_get_member_name(int id)
+{
+ switch ( id ) {
+ case TESTSUITE_OBJECT_ENVELOPE_FROM:
+ return "from";
+ case TESTSUITE_OBJECT_ENVELOPE_TO:
+ return "to";
+ case TESTSUITE_OBJECT_ENVELOPE_ORIG_TO:
+ return "orig_to";
+ case TESTSUITE_OBJECT_ENVELOPE_AUTH_USER:
+ return "auth";
+ }
+
+ return NULL;
+}
+
+static bool tsto_envelope_set_member
+(const struct sieve_runtime_env *renv, int id, string_t *value)
+{
+ switch ( id ) {
+ case TESTSUITE_OBJECT_ENVELOPE_FROM:
+ testsuite_envelope_set_sender(renv, str_c(value));
+ return TRUE;
+ case TESTSUITE_OBJECT_ENVELOPE_TO:
+ testsuite_envelope_set_recipient(renv, str_c(value));
+ return TRUE;
+ case TESTSUITE_OBJECT_ENVELOPE_ORIG_TO:
+ testsuite_envelope_set_orig_recipient(renv, str_c(value));
+ return TRUE;
+ case TESTSUITE_OBJECT_ENVELOPE_AUTH_USER:
+ testsuite_envelope_set_auth_user(renv, str_c(value));
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/pigeonhole/src/testsuite/testsuite-objects.h b/pigeonhole/src/testsuite/testsuite-objects.h
new file mode 100644
index 0000000..0aa6f4f
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-objects.h
@@ -0,0 +1,83 @@
+#ifndef TESTSUITE_OBJECTS_H
+#define TESTSUITE_OBJECTS_H
+
+#include "sieve-common.h"
+#include "sieve-objects.h"
+
+#include "testsuite-common.h"
+
+/*
+ * Testsuite object operand
+ */
+
+struct testsuite_object_operand_interface {
+ struct sieve_extension_objects testsuite_objects;
+};
+
+extern const struct sieve_operand_class testsuite_object_oprclass;
+
+/*
+ * Testsuite object access
+ */
+
+struct testsuite_object_def {
+ struct sieve_object_def obj_def;
+
+ int (*get_member_id)(const char *identifier);
+ const char *(*get_member_name)(int id);
+
+ bool (*set_member)
+ (const struct sieve_runtime_env *renv, int id, string_t *value);
+ string_t *(*get_member)
+ (const struct sieve_runtime_env *renv, int id);
+};
+
+struct testsuite_object {
+ struct sieve_object object;
+
+ const struct testsuite_object_def *def;
+};
+
+/*
+ * Testsuite object registration
+ */
+
+void testsuite_register_core_objects
+ (struct testsuite_validator_context *ctx);
+void testsuite_object_register
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ const struct testsuite_object_def *tobj_def);
+
+/*
+ * Testsuite object argument
+ */
+
+bool testsuite_object_argument_activate
+ (struct sieve_validator *valdtr, struct sieve_ast_argument *arg,
+ struct sieve_command *cmd);
+
+/*
+ * Testsuite object code
+ */
+
+bool testsuite_object_read
+ (struct sieve_binary_block *sblock, sieve_size_t *address,
+ struct testsuite_object *tobj);
+bool testsuite_object_read_member
+ (struct sieve_binary_block *sblock, sieve_size_t *address,
+ struct testsuite_object *tobj, int *member_id_r);
+
+bool testsuite_object_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+
+const char *testsuite_object_member_name
+ (const struct testsuite_object *object, int member_id);
+
+/*
+ * Testsuite core objects
+ */
+
+extern const struct testsuite_object_def message_testsuite_object;
+extern const struct testsuite_object_def envelope_testsuite_object;
+
+#endif
diff --git a/pigeonhole/src/testsuite/testsuite-result.c b/pigeonhole/src/testsuite/testsuite-result.c
new file mode 100644
index 0000000..51be3ff
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-result.c
@@ -0,0 +1,206 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "ostream.h"
+#include "str.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-stringlist.h"
+#include "sieve-actions.h"
+#include "sieve-interpreter.h"
+#include "sieve-result.h"
+
+#include "testsuite-common.h"
+#include "testsuite-log.h"
+#include "testsuite-message.h"
+#include "testsuite-mailstore.h"
+
+#include "testsuite-result.h"
+
+struct sieve_execute_env testsuite_execute_env;
+
+static pool_t testsuite_execute_pool = NULL;
+static struct sieve_result *_testsuite_result = NULL;
+static struct sieve_result_execution *_testsuite_rexec = NULL;
+
+void testsuite_result_init(void)
+{
+ struct sieve_instance *svinst = testsuite_sieve_instance;
+
+ testsuite_execute_pool = pool_alloconly_create("sieve execution", 4096);
+
+ sieve_execute_init(&testsuite_execute_env, testsuite_sieve_instance,
+ testsuite_execute_pool, &testsuite_msgdata,
+ testsuite_scriptenv, 0);
+
+ _testsuite_result = sieve_result_create(svinst, testsuite_execute_pool,
+ &testsuite_execute_env);
+}
+
+void testsuite_result_deinit(void)
+{
+ sieve_result_execution_destroy(&_testsuite_rexec);
+ if (_testsuite_result != NULL)
+ sieve_result_unref(&_testsuite_result);
+ sieve_execute_deinit(&testsuite_execute_env);
+ pool_unref(&testsuite_execute_pool);
+}
+
+void testsuite_result_reset(const struct sieve_runtime_env *renv)
+{
+ struct sieve_instance *svinst = testsuite_sieve_instance;
+
+ if (_testsuite_result != NULL) {
+ sieve_result_execution_destroy(&_testsuite_rexec);
+ sieve_result_unref(&_testsuite_result);
+ pool_unref(&testsuite_execute_pool);
+ }
+
+ testsuite_message_flush();
+ testsuite_mailstore_flush();
+ i_zero(testsuite_execute_env.exec_status);
+
+ testsuite_execute_pool = pool_alloconly_create("sieve execution", 4096);
+ _testsuite_result = sieve_result_create(svinst, testsuite_execute_pool,
+ &testsuite_execute_env);
+ sieve_interpreter_set_result(renv->interp, _testsuite_result);
+}
+
+struct sieve_result *testsuite_result_get(void)
+{
+ return _testsuite_result;
+}
+
+struct sieve_result_iterate_context *testsuite_result_iterate_init(void)
+{
+ if (_testsuite_result == NULL)
+ return NULL;
+
+ return sieve_result_iterate_init(_testsuite_result);
+}
+
+bool testsuite_result_execute(const struct sieve_runtime_env *renv)
+{
+ int ret;
+
+ if (_testsuite_result == NULL) {
+ sieve_runtime_error(renv, NULL, "testsuite: "
+ "trying to execute result, "
+ "but no result evaluated yet");
+ return FALSE;
+ }
+
+ testsuite_log_clear_messages();
+
+ if (_testsuite_rexec == NULL) {
+ _testsuite_rexec = sieve_result_execution_create(
+ _testsuite_result, testsuite_execute_pool);
+ }
+
+ /* Execute the result */
+ ret = sieve_result_execute(_testsuite_rexec, SIEVE_EXEC_OK, TRUE,
+ testsuite_log_ehandler, NULL);
+
+ return (ret > 0);
+}
+
+void testsuite_result_print(const struct sieve_runtime_env *renv)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ struct ostream *out;
+
+ out = o_stream_create_fd(1, 0);
+ o_stream_set_no_error_handling(out, TRUE);
+
+ o_stream_nsend_str(out, "\n--");
+ sieve_result_print(_testsuite_result, eenv->scriptenv, out, NULL);
+ o_stream_nsend_str(out, "--\n\n");
+
+ o_stream_destroy(&out);
+}
+
+/*
+ * Result stringlist
+ */
+
+/* Forward declarations */
+
+static int
+testsuite_result_stringlist_next_item(struct sieve_stringlist *_strlist,
+ string_t **str_r);
+static void
+testsuite_result_stringlist_reset(struct sieve_stringlist *_strlist);
+
+/* Stringlist object */
+
+struct testsuite_result_stringlist {
+ struct sieve_stringlist strlist;
+
+ struct sieve_result_iterate_context *result_iter;
+ int pos, index;
+};
+
+struct sieve_stringlist *
+testsuite_result_stringlist_create(const struct sieve_runtime_env *renv,
+ int index)
+{
+ struct testsuite_result_stringlist *strlist;
+
+ strlist = t_new(struct testsuite_result_stringlist, 1);
+ strlist->strlist.runenv = renv;
+ strlist->strlist.exec_status = SIEVE_EXEC_OK;
+ strlist->strlist.next_item = testsuite_result_stringlist_next_item;
+ strlist->strlist.reset = testsuite_result_stringlist_reset;
+
+ strlist->result_iter = testsuite_result_iterate_init();
+ strlist->index = index;
+ strlist->pos = 0;
+
+ return &strlist->strlist;
+}
+
+static int
+testsuite_result_stringlist_next_item(struct sieve_stringlist *_strlist,
+ string_t **str_r)
+{
+ struct testsuite_result_stringlist *strlist =
+ (struct testsuite_result_stringlist *)_strlist;
+ const struct sieve_action *action;
+ const char *act_name;
+ bool keep;
+
+ *str_r = NULL;
+
+ if (strlist->index > 0 && strlist->pos > 0)
+ return 0;
+
+ do {
+ if ((action = sieve_result_iterate_next(strlist->result_iter,
+ &keep)) == NULL)
+ return 0;
+
+ strlist->pos++;
+ } while (strlist->pos < strlist->index);
+
+ if (keep)
+ act_name = "keep";
+ else {
+ act_name = ((action == NULL || action->def == NULL ||
+ action->def->name == NULL) ?
+ "" : action->def->name);
+ }
+
+ *str_r = t_str_new_const(act_name, strlen(act_name));
+ return 1;
+}
+
+static void testsuite_result_stringlist_reset(struct sieve_stringlist *_strlist)
+{
+ struct testsuite_result_stringlist *strlist =
+ (struct testsuite_result_stringlist *)_strlist;
+
+ strlist->result_iter = testsuite_result_iterate_init();
+ strlist->pos = 0;
+}
diff --git a/pigeonhole/src/testsuite/testsuite-result.h b/pigeonhole/src/testsuite/testsuite-result.h
new file mode 100644
index 0000000..3e232d2
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-result.h
@@ -0,0 +1,25 @@
+#ifndef TESTSUITE_RESULT_H
+#define TESTSUITE_RESULT_H
+
+#include "sieve-execute.h"
+
+extern struct sieve_execute_env testsuite_execute_env;
+
+void testsuite_result_init(void);
+void testsuite_result_deinit(void);
+
+void testsuite_result_reset(const struct sieve_runtime_env *renv);
+
+struct sieve_result *testsuite_result_get(void);
+
+struct sieve_result_iterate_context *testsuite_result_iterate_init(void);
+
+bool testsuite_result_execute(const struct sieve_runtime_env *renv);
+
+void testsuite_result_print(const struct sieve_runtime_env *renv ATTR_UNUSED);
+
+struct sieve_stringlist *
+testsuite_result_stringlist_create(const struct sieve_runtime_env *renv,
+ int index);
+
+#endif
diff --git a/pigeonhole/src/testsuite/testsuite-script.c b/pigeonhole/src/testsuite/testsuite-script.c
new file mode 100644
index 0000000..b6edd9b
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-script.c
@@ -0,0 +1,256 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve.h"
+#include "sieve-common.h"
+#include "sieve-script.h"
+#include "sieve-binary.h"
+#include "sieve-interpreter.h"
+#include "sieve-runtime-trace.h"
+#include "sieve-result.h"
+
+#include "testsuite-common.h"
+#include "testsuite-settings.h"
+#include "testsuite-log.h"
+#include "testsuite-smtp.h"
+#include "testsuite-result.h"
+
+#include "testsuite-script.h"
+
+/*
+ * Tested script environment
+ */
+
+void testsuite_script_init(void)
+{
+}
+
+void testsuite_script_deinit(void)
+{
+}
+
+static struct sieve_binary *
+_testsuite_script_compile(const struct sieve_runtime_env *renv,
+ const char *script)
+{
+ struct sieve_instance *svinst = testsuite_sieve_instance;
+ struct sieve_binary *sbin;
+ const char *script_path;
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "compile script `%s'", script);
+
+ script_path = sieve_file_script_get_dirpath(renv->script);
+ if (script_path == NULL)
+ return NULL;
+
+ script_path = t_strconcat(script_path, "/", script, NULL);
+ if ((sbin = sieve_compile(svinst, script_path, NULL,
+ testsuite_log_ehandler, 0, NULL)) == NULL)
+ return NULL;
+
+ return sbin;
+}
+
+bool testsuite_script_compile(const struct sieve_runtime_env *renv,
+ const char *script)
+{
+ struct testsuite_interpreter_context *ictx =
+ testsuite_interpreter_context_get(renv->interp, testsuite_ext);
+ struct sieve_binary *sbin;
+
+ i_assert(ictx != NULL);
+ testsuite_log_clear_messages();
+
+ if ((sbin = _testsuite_script_compile(renv, script)) == NULL)
+ return FALSE;
+
+ sieve_binary_unref(&ictx->compiled_script);
+
+ ictx->compiled_script = sbin;
+ return TRUE;
+}
+
+bool testsuite_script_is_subtest(const struct sieve_runtime_env *renv)
+{
+ struct testsuite_interpreter_context *ictx =
+ testsuite_interpreter_context_get(renv->interp, testsuite_ext);
+
+ i_assert(ictx != NULL);
+ if (ictx->compiled_script == NULL)
+ return FALSE;
+
+ return (sieve_binary_extension_get_index(ictx->compiled_script,
+ testsuite_ext) >= 0);
+}
+
+bool testsuite_script_run(const struct sieve_runtime_env *renv)
+{
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ struct testsuite_interpreter_context *ictx =
+ testsuite_interpreter_context_get(renv->interp, testsuite_ext);
+ struct sieve_script_env scriptenv;
+ struct sieve_exec_status exec_status;
+ struct sieve_result *result;
+ struct sieve_interpreter *interp;
+ pool_t pool;
+ struct sieve_execute_env exec_env;
+ const char *error;
+ int ret;
+
+ i_assert(ictx != NULL);
+
+ if (ictx->compiled_script == NULL) {
+ sieve_runtime_error(renv, NULL, "testsuite: "
+ "trying to run script, but no script compiled yet");
+ return FALSE;
+ }
+
+ testsuite_log_clear_messages();
+
+ i_zero(&exec_status);
+
+ /* Compose script execution environment */
+ if (sieve_script_env_init(&scriptenv, senv->user, &error) < 0) {
+ sieve_runtime_error(renv, NULL, "testsuite: "
+ "failed to initialize script execution: %s", error);
+ return FALSE;
+ }
+ scriptenv.default_mailbox = "INBOX";
+ scriptenv.smtp_start = testsuite_smtp_start;
+ scriptenv.smtp_add_rcpt = testsuite_smtp_add_rcpt;
+ scriptenv.smtp_send = testsuite_smtp_send;
+ scriptenv.smtp_abort = testsuite_smtp_abort;
+ scriptenv.smtp_finish = testsuite_smtp_finish;
+ scriptenv.duplicate_mark = NULL;
+ scriptenv.duplicate_check = NULL;
+ scriptenv.trace_log = eenv->scriptenv->trace_log;
+ scriptenv.trace_config = eenv->scriptenv->trace_config;
+
+ result = testsuite_result_get();
+
+ pool = pool_alloconly_create("sieve execution", 4096);
+ sieve_execute_init(&exec_env, eenv->svinst, pool, eenv->msgdata,
+ &scriptenv, eenv->flags);
+ pool_unref(&pool);
+
+ /* Execute the script */
+ interp = sieve_interpreter_create(ictx->compiled_script, NULL,
+ &exec_env, testsuite_log_ehandler);
+
+ if (interp == NULL) {
+ sieve_execute_deinit(&exec_env);
+ return FALSE;
+ }
+
+ ret = sieve_interpreter_run(interp, result);
+ sieve_interpreter_free(&interp);
+
+ sieve_execute_finish(&exec_env, ret);
+ sieve_execute_deinit(&exec_env);
+
+ return (ret > 0 ||
+ sieve_binary_extension_get_index(ictx->compiled_script,
+ testsuite_ext) >= 0);
+}
+
+struct sieve_binary *
+testsuite_script_get_binary(const struct sieve_runtime_env *renv)
+{
+ struct testsuite_interpreter_context *ictx =
+ testsuite_interpreter_context_get(renv->interp, testsuite_ext);
+
+ i_assert(ictx != NULL);
+ return ictx->compiled_script;
+}
+
+void testsuite_script_set_binary(const struct sieve_runtime_env *renv,
+ struct sieve_binary *sbin)
+{
+ struct testsuite_interpreter_context *ictx =
+ testsuite_interpreter_context_get(renv->interp, testsuite_ext);
+
+ i_assert(ictx != NULL);
+
+ sieve_binary_unref(&ictx->compiled_script);
+
+ ictx->compiled_script = sbin;
+ sieve_binary_ref(sbin);
+}
+
+/*
+ * Multiscript
+ */
+
+bool testsuite_script_multiscript(const struct sieve_runtime_env *renv,
+ ARRAY_TYPE (const_string) *scriptfiles)
+{
+ struct sieve_instance *svinst = testsuite_sieve_instance;
+ const struct sieve_execute_env *eenv = renv->exec_env;
+ const struct sieve_script_env *senv = eenv->scriptenv;
+ struct sieve_script_env scriptenv;
+ struct sieve_exec_status exec_status;
+ struct sieve_multiscript *mscript;
+ const char *const *scripts;
+ const char *error;
+ unsigned int count, i;
+ bool more = TRUE;
+ bool result = TRUE;
+
+ testsuite_log_clear_messages();
+
+ /* Compose script execution environment */
+ if (sieve_script_env_init(&scriptenv, senv->user, &error) < 0) {
+ sieve_runtime_error(renv, NULL,
+ "testsuite: failed to initialize script execution: %s",
+ error);
+ return FALSE;
+ }
+ scriptenv.default_mailbox = "INBOX";
+ scriptenv.smtp_start = testsuite_smtp_start;
+ scriptenv.smtp_add_rcpt = testsuite_smtp_add_rcpt;
+ scriptenv.smtp_send = testsuite_smtp_send;
+ scriptenv.smtp_abort = testsuite_smtp_abort;
+ scriptenv.smtp_finish = testsuite_smtp_finish;
+ scriptenv.duplicate_mark = NULL;
+ scriptenv.duplicate_check = NULL;
+ scriptenv.trace_log = eenv->scriptenv->trace_log;
+ scriptenv.trace_config = eenv->scriptenv->trace_config;
+ scriptenv.exec_status = &exec_status;
+
+ /* Start execution */
+
+ mscript = sieve_multiscript_start_execute(svinst, eenv->msgdata,
+ &scriptenv);
+
+ /* Execute scripts before main script */
+
+ scripts = array_get(scriptfiles, &count);
+ for (i = 0; i < count && more; i++) {
+ struct sieve_binary *sbin = NULL;
+ const char *script = scripts[i];
+
+ /* Open */
+ if ((sbin = _testsuite_script_compile(renv, script)) == NULL) {
+ result = FALSE;
+ break;
+ }
+
+ /* Execute */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "run script `%s'", script);
+
+ more = sieve_multiscript_run(mscript, sbin,
+ testsuite_log_ehandler,
+ testsuite_log_ehandler, 0);
+
+ sieve_close(&sbin);
+ }
+
+ return (sieve_multiscript_finish(&mscript, testsuite_log_ehandler,
+ 0, SIEVE_EXEC_OK) > 0 && result);
+}
diff --git a/pigeonhole/src/testsuite/testsuite-script.h b/pigeonhole/src/testsuite/testsuite-script.h
new file mode 100644
index 0000000..547fdfc
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-script.h
@@ -0,0 +1,22 @@
+#ifndef TESTSUITE_SCRIPT_H
+#define TESTSUITE_SCRIPT_H
+
+#include "sieve-common.h"
+
+void testsuite_script_init(void);
+void testsuite_script_deinit(void);
+
+bool testsuite_script_is_subtest(const struct sieve_runtime_env *renv);
+
+bool testsuite_script_compile(const struct sieve_runtime_env *renv,
+ const char *script);
+bool testsuite_script_run(const struct sieve_runtime_env *renv);
+bool testsuite_script_multiscript(const struct sieve_runtime_env *renv,
+ ARRAY_TYPE (const_string) *scriptfiles);
+
+struct sieve_binary *
+testsuite_script_get_binary(const struct sieve_runtime_env *renv);
+void testsuite_script_set_binary(const struct sieve_runtime_env *renv,
+ struct sieve_binary *sbin);
+
+#endif
diff --git a/pigeonhole/src/testsuite/testsuite-settings.c b/pigeonhole/src/testsuite/testsuite-settings.c
new file mode 100644
index 0000000..9d3c872
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-settings.c
@@ -0,0 +1,96 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "hash.h"
+#include "imem.h"
+#include "strfuncs.h"
+#include "mail-user.h"
+
+#include "sieve-common.h"
+
+#include "testsuite-common.h"
+#include "testsuite-mailstore.h"
+#include "testsuite-settings.h"
+
+struct testsuite_setting {
+ char *identifier;
+ char *value;
+};
+
+static HASH_TABLE(const char *, struct testsuite_setting *) settings;
+
+static const char *testsuite_setting_get
+ (void *context, const char *identifier);
+
+void testsuite_settings_init(void)
+{
+ hash_table_create(&settings, default_pool, 0, str_hash, strcmp);
+
+ sieve_tool_set_setting_callback(sieve_tool, testsuite_setting_get, NULL);
+}
+
+void testsuite_settings_deinit(void)
+{
+ struct hash_iterate_context *itx =
+ hash_table_iterate_init(settings);
+ const char *key;
+ struct testsuite_setting *setting;
+
+ while ( hash_table_iterate(itx, settings, &key, &setting) ) {
+ i_free(setting->identifier);
+ i_free(setting->value);
+ i_free(setting);
+ }
+
+ hash_table_iterate_deinit(&itx);
+
+ hash_table_destroy(&settings);
+}
+
+static const char *testsuite_setting_get
+(void *context ATTR_UNUSED, const char *identifier)
+{
+ struct testsuite_setting *setting;
+ struct mail_user *user;
+
+ setting = hash_table_lookup(settings, identifier);
+ if ( setting != NULL )
+ return setting->value;
+
+ user = testsuite_mailstore_get_user();
+ if ( user == NULL )
+ return NULL;
+ return mail_user_plugin_getenv(user, identifier);
+}
+
+void testsuite_setting_set(const char *identifier, const char *value)
+{
+ struct testsuite_setting *setting =
+ hash_table_lookup(settings, identifier);
+
+ if ( setting != NULL ) {
+ i_free(setting->value);
+ setting->value = i_strdup(value);
+ } else {
+ setting = i_new(struct testsuite_setting, 1);
+ setting->identifier = i_strdup(identifier);
+ setting->value = i_strdup(value);
+
+ hash_table_insert(settings, identifier, setting);
+ }
+}
+
+void testsuite_setting_unset(const char *identifier)
+{
+ struct testsuite_setting *setting =
+ hash_table_lookup(settings, identifier);
+
+ if ( setting != NULL ) {
+ i_free(setting->identifier);
+ i_free(setting->value);
+ i_free(setting);
+
+ hash_table_remove(settings, identifier);
+ }
+}
diff --git a/pigeonhole/src/testsuite/testsuite-settings.h b/pigeonhole/src/testsuite/testsuite-settings.h
new file mode 100644
index 0000000..b84e620
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-settings.h
@@ -0,0 +1,12 @@
+#ifndef TESTSUITE_SETTINGS_H
+#define TESTSUITE_SETTINGS_H
+
+#include "sieve-common.h"
+
+void testsuite_settings_init(void);
+void testsuite_settings_deinit(void);
+
+void testsuite_setting_set(const char *identifier, const char *value);
+void testsuite_setting_unset(const char *identifier);
+
+#endif
diff --git a/pigeonhole/src/testsuite/testsuite-smtp.c b/pigeonhole/src/testsuite/testsuite-smtp.c
new file mode 100644
index 0000000..0eb40ac
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-smtp.c
@@ -0,0 +1,176 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "ostream.h"
+#include "unlink-directory.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-interpreter.h"
+
+#include "testsuite-message.h"
+#include "testsuite-common.h"
+#include "testsuite-smtp.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+struct testsuite_smtp_message {
+ const struct smtp_address *envelope_from, *envelope_to;
+ const char *file;
+};
+
+static pool_t testsuite_smtp_pool;
+static const char *testsuite_smtp_tmp;
+static ARRAY(struct testsuite_smtp_message) testsuite_smtp_messages;
+
+/*
+ * Initialize
+ */
+
+void testsuite_smtp_init(void)
+{
+ pool_t pool;
+
+ testsuite_smtp_pool = pool = pool_alloconly_create("testsuite_smtp", 8192);
+
+ testsuite_smtp_tmp = p_strconcat
+ (pool, testsuite_tmp_dir_get(), "/smtp", NULL);
+
+ if ( mkdir(testsuite_smtp_tmp, 0700) < 0 ) {
+ i_fatal("failed to create temporary directory '%s': %m.",
+ testsuite_smtp_tmp);
+ }
+
+ p_array_init(&testsuite_smtp_messages, pool, 16);
+}
+
+void testsuite_smtp_deinit(void)
+{
+ const char *error;
+
+ if ( unlink_directory(testsuite_smtp_tmp, UNLINK_DIRECTORY_FLAG_RMDIR, &error) < 0 )
+ i_warning("failed to remove temporary directory '%s': %s.",
+ testsuite_smtp_tmp, error);
+
+ pool_unref(&testsuite_smtp_pool);
+}
+
+void testsuite_smtp_reset(void)
+{
+ testsuite_smtp_deinit();
+ testsuite_smtp_init();
+}
+
+/*
+ * Simulated SMTP out
+ */
+
+struct testsuite_smtp {
+ char *msg_file;
+ struct smtp_address *mail_from;
+ struct ostream *output;
+};
+
+void *testsuite_smtp_start
+(const struct sieve_script_env *senv ATTR_UNUSED,
+ const struct smtp_address *mail_from)
+{
+ struct testsuite_smtp *smtp;
+ unsigned int smtp_count = array_count(&testsuite_smtp_messages);
+ int fd;
+
+ smtp = i_new(struct testsuite_smtp, 1);
+
+ smtp->msg_file = i_strdup_printf("%s/%d.eml", testsuite_smtp_tmp, smtp_count);
+ smtp->mail_from = smtp_address_clone(default_pool, mail_from);
+
+ if ( (fd=open(smtp->msg_file, O_WRONLY | O_CREAT, 0600)) < 0 ) {
+ i_fatal("failed create tmp file for SMTP simulation: open(%s) failed: %m",
+ smtp->msg_file);
+ }
+
+ smtp->output = o_stream_create_fd_autoclose(&fd, (size_t)-1);
+
+ return (void *) smtp;
+}
+
+void testsuite_smtp_add_rcpt
+(const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle, const struct smtp_address *rcpt_to)
+{
+ struct testsuite_smtp *smtp = (struct testsuite_smtp *) handle;
+ struct testsuite_smtp_message *msg;
+
+ msg = array_append_space(&testsuite_smtp_messages);
+
+ msg->file = p_strdup(testsuite_smtp_pool, smtp->msg_file);
+ msg->envelope_from = smtp_address_clone(testsuite_smtp_pool, smtp->mail_from);
+ msg->envelope_to = smtp_address_clone(testsuite_smtp_pool, rcpt_to);
+}
+
+struct ostream *testsuite_smtp_send
+(const struct sieve_script_env *senv ATTR_UNUSED, void *handle)
+{
+ struct testsuite_smtp *smtp = (struct testsuite_smtp *) handle;
+
+ return smtp->output;
+}
+
+void testsuite_smtp_abort
+(const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle)
+{
+ struct testsuite_smtp *smtp = (struct testsuite_smtp *) handle;
+
+ o_stream_ignore_last_errors(smtp->output);
+ o_stream_unref(&smtp->output);
+ i_unlink(smtp->msg_file);
+ i_free(smtp->msg_file);
+ i_free(smtp->mail_from);
+ i_free(smtp);
+}
+
+int testsuite_smtp_finish
+(const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle, const char **error_r ATTR_UNUSED)
+{
+ struct testsuite_smtp *smtp = (struct testsuite_smtp *) handle;
+ int ret = 1;
+
+ if (o_stream_finish(smtp->output) < 0) {
+ i_error("write(%s) failed: %s", smtp->msg_file,
+ o_stream_get_error(smtp->output));
+ ret = -1;
+ }
+ o_stream_unref(&smtp->output);
+ i_free(smtp->msg_file);
+ i_free(smtp->mail_from);
+ i_free(smtp);
+ return ret;
+}
+
+/*
+ * Access
+ */
+
+bool testsuite_smtp_get
+(const struct sieve_runtime_env *renv, unsigned int index)
+{
+ const struct testsuite_smtp_message *smtp_msg;
+
+ if ( index >= array_count(&testsuite_smtp_messages) )
+ return FALSE;
+
+ smtp_msg = array_idx(&testsuite_smtp_messages, index);
+
+ testsuite_message_set_file(renv, smtp_msg->file);
+ testsuite_envelope_set_sender_address(renv, smtp_msg->envelope_from);
+ testsuite_envelope_set_recipient_address(renv, smtp_msg->envelope_to);
+
+ return TRUE;
+}
diff --git a/pigeonhole/src/testsuite/testsuite-smtp.h b/pigeonhole/src/testsuite/testsuite-smtp.h
new file mode 100644
index 0000000..0b120b2
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-smtp.h
@@ -0,0 +1,35 @@
+#ifndef TESTSUITE_SMTP_H
+#define TESTSUITE_SMTP_H
+
+void testsuite_smtp_init(void);
+void testsuite_smtp_deinit(void);
+void testsuite_smtp_reset(void);
+
+/*
+ * Simulated SMTP out
+ */
+
+void *testsuite_smtp_start
+ (const struct sieve_script_env *senv ATTR_UNUSED,
+ const struct smtp_address *mail_from);
+void testsuite_smtp_add_rcpt
+ (const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle, const struct smtp_address *rcpt_to);
+struct ostream *testsuite_smtp_send
+ (const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle);
+void testsuite_smtp_abort
+ (const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle);
+int testsuite_smtp_finish
+ (const struct sieve_script_env *senv ATTR_UNUSED,
+ void *handle, const char **error_r);
+
+/*
+ * Access
+ */
+
+bool testsuite_smtp_get
+ (const struct sieve_runtime_env *renv, unsigned int index);
+
+#endif
diff --git a/pigeonhole/src/testsuite/testsuite-substitutions.c b/pigeonhole/src/testsuite/testsuite-substitutions.c
new file mode 100644
index 0000000..b165587
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-substitutions.c
@@ -0,0 +1,253 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve.h"
+#include "sieve-code.h"
+#include "sieve-commands.h"
+#include "sieve-binary.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "testsuite-common.h"
+#include "testsuite-substitutions.h"
+
+/*
+ * Forward declarations
+ */
+
+void testsuite_opr_substitution_emit
+ (struct sieve_binary_block *sblock, const struct testsuite_substitution *tsub,
+ const char *param);
+
+/*
+ * Testsuite substitutions
+ */
+
+/* FIXME: make this extendible */
+
+enum {
+ TESTSUITE_SUBSTITUTION_FILE,
+};
+
+static const struct testsuite_substitution_def testsuite_file_substitution;
+
+static const struct testsuite_substitution_def *substitutions[] = {
+ &testsuite_file_substitution,
+};
+
+static const unsigned int substitutions_count = N_ELEMENTS(substitutions);
+
+static inline const struct testsuite_substitution_def *
+testsuite_substitution_get
+(unsigned int code)
+{
+ if ( code >= substitutions_count )
+ return NULL;
+
+ return substitutions[code];
+}
+
+static const struct testsuite_substitution *testsuite_substitution_create
+(struct sieve_ast *ast, const char *identifier)
+{
+ unsigned int i;
+
+ for ( i = 0; i < substitutions_count; i++ ) {
+ if ( strcasecmp(substitutions[i]->obj_def.identifier, identifier) == 0 ) {
+ const struct testsuite_substitution_def *tsub_def = substitutions[i];
+ struct testsuite_substitution *tsub;
+
+ tsub = p_new(sieve_ast_pool(ast), struct testsuite_substitution, 1);
+ tsub->object.def = &tsub_def->obj_def;
+ tsub->object.ext = testsuite_ext;
+ tsub->def = tsub_def;
+
+ return tsub;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Substitution argument
+ */
+
+static bool arg_testsuite_substitution_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *context);
+
+struct _testsuite_substitution_context {
+ const struct testsuite_substitution *tsub;
+ const char *param;
+};
+
+const struct sieve_argument_def testsuite_substitution_argument = {
+ .identifier = "@testsuite-substitution",
+ .generate = arg_testsuite_substitution_generate
+};
+
+struct sieve_ast_argument *testsuite_substitution_argument_create
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_ast *ast,
+ unsigned int source_line, const char *substitution, const char *param)
+{
+ const struct testsuite_substitution *tsub;
+ struct _testsuite_substitution_context *tsctx;
+ struct sieve_ast_argument *arg;
+ pool_t pool;
+
+ tsub = testsuite_substitution_create(ast, substitution);
+ if ( tsub == NULL )
+ return NULL;
+
+ arg = sieve_ast_argument_create(ast, source_line);
+ arg->type = SAAT_STRING;
+
+ pool = sieve_ast_pool(ast);
+ tsctx = p_new(pool, struct _testsuite_substitution_context, 1);
+ tsctx->tsub = tsub;
+ tsctx->param = p_strdup(pool, param);
+
+ arg->argument = sieve_argument_create
+ (ast, &testsuite_substitution_argument, testsuite_ext, 0);
+ arg->argument->data = (void *) tsctx;
+
+ return arg;
+}
+
+static bool arg_testsuite_substitution_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
+ struct sieve_command *context ATTR_UNUSED)
+{
+ struct _testsuite_substitution_context *tsctx =
+ (struct _testsuite_substitution_context *) arg->argument->data;
+
+ testsuite_opr_substitution_emit(cgenv->sblock, tsctx->tsub, tsctx->param);
+
+ return TRUE;
+}
+
+/*
+ * Substitution operand
+ */
+
+static bool opr_substitution_dump
+ (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address);
+static int opr_substitution_read_value
+ (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
+ sieve_size_t *address, string_t **str);
+
+const struct sieve_opr_string_interface testsuite_substitution_interface = {
+ opr_substitution_dump,
+ opr_substitution_read_value
+};
+
+const struct sieve_operand_def testsuite_substitution_operand = {
+ .name = "test-substitution",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERAND_SUBSTITUTION,
+ .class = &string_class,
+ .interface = &testsuite_substitution_interface
+};
+
+void testsuite_opr_substitution_emit
+(struct sieve_binary_block *sblock, const struct testsuite_substitution *tsub,
+ const char *param)
+{
+ /* Default variable storage */
+ (void) sieve_operand_emit
+ (sblock, testsuite_ext, &testsuite_substitution_operand);
+ (void) sieve_binary_emit_unsigned(sblock, tsub->object.def->code);
+ (void) sieve_binary_emit_cstring(sblock, param);
+}
+
+static bool opr_substitution_dump
+(const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
+ sieve_size_t *address)
+{
+ unsigned int code = 0;
+ const struct testsuite_substitution_def *tsub;
+ string_t *param;
+
+ if ( !sieve_binary_read_unsigned(denv->sblock, address, &code) )
+ return FALSE;
+
+ tsub = testsuite_substitution_get(code);
+ if ( tsub == NULL )
+ return FALSE;
+
+ if ( !sieve_binary_read_string(denv->sblock, address, &param) )
+ return FALSE;
+
+ if ( oprnd->field_name != NULL )
+ sieve_code_dumpf(denv, "%s: TEST_SUBS %%{%s:%s}",
+ oprnd->field_name, tsub->obj_def.identifier, str_c(param));
+ else
+ sieve_code_dumpf(denv, "TEST_SUBS %%{%s:%s}",
+ tsub->obj_def.identifier, str_c(param));
+ return TRUE;
+}
+
+static int opr_substitution_read_value
+(const struct sieve_runtime_env *renv,
+ const struct sieve_operand *oprnd ATTR_UNUSED, sieve_size_t *address,
+ string_t **str_r)
+{
+ const struct testsuite_substitution_def *tsub;
+ unsigned int code = 0;
+ string_t *param;
+
+ if ( !sieve_binary_read_unsigned(renv->sblock, address, &code) )
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ tsub = testsuite_substitution_get(code);
+ if ( tsub == NULL )
+ return SIEVE_EXEC_FAILURE;
+
+ /* Parameter str can be NULL if we are requested to only skip and not
+ * actually read the argument.
+ */
+ if ( str_r == NULL ) {
+ if ( !sieve_binary_read_string(renv->sblock, address, NULL) )
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ return SIEVE_EXEC_OK;
+ }
+
+ if ( !sieve_binary_read_string(renv->sblock, address, &param) )
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ if ( !tsub->get_value(str_c(param), str_r) )
+ return SIEVE_EXEC_FAILURE;
+
+ return SIEVE_EXEC_OK;
+}
+
+/*
+ * Testsuite substitution definitions
+ */
+
+static bool testsuite_file_substitution_get_value
+ (const char *param, string_t **result);
+
+static const struct testsuite_substitution_def
+testsuite_file_substitution = {
+ SIEVE_OBJECT("file",
+ &testsuite_substitution_operand,
+ TESTSUITE_SUBSTITUTION_FILE),
+ .get_value = testsuite_file_substitution_get_value
+};
+
+static bool testsuite_file_substitution_get_value
+(const char *param, string_t **result)
+{
+ *result = t_str_new(256);
+
+ str_printfa(*result, "[FILE: %s]", param);
+ return TRUE;
+}
+
diff --git a/pigeonhole/src/testsuite/testsuite-substitutions.h b/pigeonhole/src/testsuite/testsuite-substitutions.h
new file mode 100644
index 0000000..8b256d0
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-substitutions.h
@@ -0,0 +1,23 @@
+#ifndef TESTSUITE_SUBSTITUTIONS_H
+#define TESTSUITE_SUBSTITUTIONS_H
+
+#include "sieve-common.h"
+#include "sieve-objects.h"
+
+struct testsuite_substitution_def {
+ struct sieve_object_def obj_def;
+
+ bool (*get_value)(const char *param, string_t **result);
+};
+
+struct testsuite_substitution {
+ struct sieve_object object;
+
+ const struct testsuite_substitution_def *def;
+};
+
+struct sieve_ast_argument *testsuite_substitution_argument_create
+ (struct sieve_validator *valdtr, struct sieve_ast *ast,
+ unsigned int source_line, const char *substitution, const char *param);
+
+#endif
diff --git a/pigeonhole/src/testsuite/testsuite-variables.c b/pigeonhole/src/testsuite/testsuite-variables.c
new file mode 100644
index 0000000..f644393
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-variables.c
@@ -0,0 +1,183 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-ast.h"
+#include "sieve-binary.h"
+#include "sieve-code.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+
+#include "sieve-ext-variables.h"
+
+#include "testsuite-common.h"
+#include "testsuite-variables.h"
+
+/*
+ *
+ */
+
+static const struct sieve_extension *testsuite_ext_variables = NULL;
+
+/*
+ *
+ */
+
+bool testsuite_varnamespace_validate
+ (struct sieve_validator *valdtr, const struct sieve_variables_namespace *nspc,
+ struct sieve_ast_argument *arg, struct sieve_command *cmd,
+ ARRAY_TYPE(sieve_variable_name) *var_name, void **var_data,
+ bool assignment);
+bool testsuite_varnamespace_generate
+ (const struct sieve_codegen_env *cgenv,
+ const struct sieve_variables_namespace *nspc,
+ struct sieve_ast_argument *arg, struct sieve_command *cmd, void *var_data);
+bool testsuite_varnamespace_dump_variable
+ (const struct sieve_dumptime_env *denv,
+ const struct sieve_variables_namespace *nspc,
+ const struct sieve_operand *oprnd, sieve_size_t *address);
+int testsuite_varnamespace_read_variable
+ (const struct sieve_runtime_env *renv,
+ const struct sieve_variables_namespace *nspc,
+ const struct sieve_operand *oprnd, sieve_size_t *address, string_t **str_r);
+
+static const struct sieve_variables_namespace_def testsuite_namespace = {
+ SIEVE_OBJECT("tst", &testsuite_namespace_operand, 0),
+ testsuite_varnamespace_validate,
+ testsuite_varnamespace_generate,
+ testsuite_varnamespace_dump_variable,
+ testsuite_varnamespace_read_variable
+};
+
+bool testsuite_varnamespace_validate
+(struct sieve_validator *valdtr,
+ const struct sieve_variables_namespace *nspc ATTR_UNUSED,
+ struct sieve_ast_argument *arg, struct sieve_command *cmd ATTR_UNUSED,
+ ARRAY_TYPE(sieve_variable_name) *var_name, void **var_data,
+ bool assignment)
+{
+ struct sieve_ast *ast = arg->ast;
+ const struct sieve_variable_name *name_element;
+ const char *variable;
+
+ /* Check variable name */
+
+ if ( array_count(var_name) != 2 ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "testsuite: invalid variable name within testsuite namespace: "
+ "encountered sub-namespace");
+ return FALSE;
+ }
+
+ name_element = array_idx(var_name, 1);
+ if ( name_element->num_variable >= 0 ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "testsuite: invalid variable name within testsuite namespace 'tst.%d': "
+ "encountered numeric variable name", name_element->num_variable);
+ return FALSE;
+ }
+
+ variable = str_c(name_element->identifier);
+
+ if ( assignment ) {
+ sieve_argument_validate_error(valdtr, arg,
+ "testsuite: cannot assign to testsuite variable 'tst.%s'", variable);
+ return FALSE;
+ }
+
+ *var_data = (void *) p_strdup(sieve_ast_pool(ast), variable);
+
+ return TRUE;
+}
+
+bool testsuite_varnamespace_generate
+(const struct sieve_codegen_env *cgenv,
+ const struct sieve_variables_namespace *nspc,
+ struct sieve_ast_argument *arg ATTR_UNUSED,
+ struct sieve_command *cmd ATTR_UNUSED, void *var_data)
+{
+ const struct sieve_extension *this_ext = SIEVE_OBJECT_EXTENSION(nspc);
+ const char *variable = (const char *) var_data;
+
+ if ( this_ext == NULL )
+ return FALSE;
+
+ sieve_variables_opr_namespace_variable_emit
+ (cgenv->sblock, testsuite_ext_variables, this_ext, &testsuite_namespace);
+ sieve_binary_emit_cstring(cgenv->sblock, variable);
+
+ return TRUE;
+}
+
+bool testsuite_varnamespace_dump_variable
+(const struct sieve_dumptime_env *denv,
+ const struct sieve_variables_namespace *nspc ATTR_UNUSED,
+ const struct sieve_operand *oprnd, sieve_size_t *address)
+{
+ string_t *var_name;
+
+ if ( !sieve_binary_read_string(denv->sblock, address, &var_name) )
+ return FALSE;
+
+ if ( oprnd->field_name != NULL )
+ sieve_code_dumpf(denv, "%s: VAR ${tst.%s}",
+ oprnd->field_name, str_c(var_name));
+ else
+ sieve_code_dumpf(denv, "VAR ${tst.%s}",
+ str_c(var_name));
+
+ return TRUE;
+}
+
+int testsuite_varnamespace_read_variable
+(const struct sieve_runtime_env *renv,
+ const struct sieve_variables_namespace *nspc ATTR_UNUSED,
+ const struct sieve_operand *oprnd, sieve_size_t *address,
+ string_t **str_r)
+{
+ string_t *var_name;
+
+ if ( !sieve_binary_read_string(renv->sblock, address, &var_name) ) {
+ sieve_runtime_trace_operand_error(renv, oprnd,
+ "testsuite variable operand corrupt: invalid name");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+
+ if ( str_r != NULL ) {
+ if ( strcmp(str_c(var_name), "path") == 0 )
+ *str_r = t_str_new_const(testsuite_test_path, strlen(testsuite_test_path));
+ else
+ *str_r = NULL;
+ }
+ return SIEVE_EXEC_OK;
+}
+
+
+/*
+ * Namespace registration
+ */
+
+static const struct sieve_extension_objects testsuite_namespaces =
+ SIEVE_VARIABLES_DEFINE_NAMESPACE(testsuite_namespace);
+
+const struct sieve_operand_def testsuite_namespace_operand = {
+ .name = "testsuite-namespace",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERAND_NAMESPACE,
+ .class = &sieve_variables_namespace_operand_class,
+ .interface = &testsuite_namespaces
+};
+
+void testsuite_variables_init
+(const struct sieve_extension *this_ext, struct sieve_validator *valdtr)
+{
+ testsuite_ext_variables = sieve_ext_variables_get_extension(this_ext->svinst);
+
+ sieve_variables_namespace_register
+ (testsuite_ext_variables, valdtr, this_ext, &testsuite_namespace);
+}
diff --git a/pigeonhole/src/testsuite/testsuite-variables.h b/pigeonhole/src/testsuite/testsuite-variables.h
new file mode 100644
index 0000000..60f6b18
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite-variables.h
@@ -0,0 +1,11 @@
+#ifndef TESTSUITE_VARIABLES_H
+#define TESTSUITE_VARIABLES_H
+
+extern const struct sieve_operand_def testsuite_namespace_operand;
+
+void testsuite_variables_init
+ (const struct sieve_extension *this_ext, struct sieve_validator *valdtr);
+
+#endif
+
+
diff --git a/pigeonhole/src/testsuite/testsuite.c b/pigeonhole/src/testsuite/testsuite.c
new file mode 100644
index 0000000..2a6b82e
--- /dev/null
+++ b/pigeonhole/src/testsuite/testsuite.c
@@ -0,0 +1,256 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "lib-signals.h"
+#include "ioloop.h"
+#include "env-util.h"
+#include "ostream.h"
+#include "hostpid.h"
+#include "path-util.h"
+
+#include "sieve.h"
+#include "sieve-extensions.h"
+#include "sieve-script.h"
+#include "sieve-binary.h"
+#include "sieve-result.h"
+#include "sieve-interpreter.h"
+
+#include "sieve-tool.h"
+
+#include "testsuite-common.h"
+#include "testsuite-log.h"
+#include "testsuite-settings.h"
+#include "testsuite-result.h"
+#include "testsuite-message.h"
+#include "testsuite-smtp.h"
+#include "testsuite-mailstore.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <sysexits.h>
+
+const struct sieve_script_env *testsuite_scriptenv;
+
+/*
+ * Configuration
+ */
+
+#define DEFAULT_SENDMAIL_PATH "/usr/lib/sendmail"
+
+/*
+ * Testsuite execution
+ */
+
+static void print_help(void)
+{
+ printf(
+"Usage: testsuite [-D] [-E] [-F] [-d <dump-filename>]\n"
+" [-t <trace-filename>] [-T <trace-option>]\n"
+" [-P <plugin>] [-x <extensions>]\n"
+" <scriptfile>\n"
+ );
+}
+
+static int
+testsuite_run(struct sieve_binary *sbin, struct sieve_error_handler *ehandler)
+{
+ struct sieve_interpreter *interp;
+ struct sieve_result *result;
+ int ret = 0;
+
+ /* Create the interpreter */
+ interp = sieve_interpreter_create(sbin, NULL, &testsuite_execute_env,
+ ehandler);
+ if (interp == NULL)
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ /* Run the interpreter */
+ result = testsuite_result_get();
+ ret = sieve_interpreter_run(interp, result);
+
+ /* Free the interpreter */
+ sieve_interpreter_free(&interp);
+
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ struct sieve_instance *svinst;
+ const char *scriptfile, *dumpfile, *tracefile;
+ struct sieve_trace_config trace_config;
+ struct sieve_binary *sbin;
+ const char *sieve_dir, *cwd, *error;
+ bool log_stdout = FALSE, expect_failure = FALSE;
+ int ret, c;
+
+ sieve_tool = sieve_tool_init("testsuite", &argc, &argv,
+ "d:t:T:EFDP:", TRUE);
+
+ /* Parse arguments */
+ dumpfile = tracefile = NULL;
+ i_zero(&trace_config);
+ trace_config.level = SIEVE_TRLVL_ACTIONS;
+ while ((c = sieve_tool_getopt(sieve_tool)) > 0) {
+ switch (c) {
+ case 'd':
+ /* destination address */
+ dumpfile = optarg;
+ break;
+ case 't':
+ /* trace file */
+ tracefile = optarg;
+ break;
+ case 'T':
+ sieve_tool_parse_trace_option(&trace_config, optarg);
+ break;
+ case 'E':
+ log_stdout = TRUE;
+ break;
+ case 'F':
+ expect_failure = TRUE;
+ break;
+ default:
+ print_help();
+ i_fatal_status(EX_USAGE, "Unknown argument: %c", c);
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ scriptfile = t_strdup(argv[optind++]);
+ } else {
+ print_help();
+ i_fatal_status(EX_USAGE, "Missing <scriptfile> argument");
+ }
+
+ if (optind != argc) {
+ print_help();
+ i_fatal_status(EX_USAGE, "Unknown argument: %s", argv[optind]);
+ }
+
+ // FIXME: very very ugly
+ master_service_parse_option(
+ master_service, 'o',
+ "postmaster_address=postmaster@example.com");
+
+ /* Initialize mail user */
+ if (t_get_working_dir(&cwd, &error) < 0)
+ i_fatal("Failed to get working directory: %s", error);
+ sieve_tool_set_homedir(sieve_tool, cwd);
+
+ /* Initialize settings environment */
+ testsuite_settings_init();
+
+ /* Currently needed for include (FIXME) */
+ sieve_dir = strrchr(scriptfile, '/');
+ if (sieve_dir == NULL)
+ sieve_dir = "./";
+ else
+ sieve_dir = t_strdup_until(scriptfile, sieve_dir+1);
+
+ testsuite_setting_set("sieve_dir",
+ t_strconcat(sieve_dir, "included", NULL));
+ testsuite_setting_set("sieve_global_dir",
+ t_strconcat(sieve_dir, "included-global", NULL));
+
+ /* Finish testsuite initialization */
+ svinst = sieve_tool_init_finish(sieve_tool, FALSE, FALSE);
+ testsuite_init(svinst, sieve_dir, log_stdout);
+
+ printf("Test case: %s:\n\n", scriptfile);
+
+ /* Compile sieve script */
+ if ((sbin = sieve_compile(svinst, scriptfile, NULL,
+ testsuite_log_main_ehandler,
+ 0, NULL)) != NULL) {
+ struct sieve_trace_log *trace_log = NULL;
+ struct sieve_exec_status exec_status;
+ struct sieve_script_env scriptenv;
+
+ /* Dump script */
+ sieve_tool_dump_binary_to(sbin, dumpfile, FALSE);
+
+ if (tracefile != NULL) {
+ (void)sieve_trace_log_create(
+ svinst, (strcmp(tracefile, "-") == 0 ?
+ NULL : tracefile), &trace_log);
+ }
+
+ testsuite_mailstore_init();
+ testsuite_message_init();
+
+ if (sieve_script_env_init(&scriptenv,
+ testsuite_mailstore_get_user(),
+ &error) < 0) {
+ i_fatal("Failed to initialize script execution: %s",
+ error);
+ }
+
+ i_zero(&exec_status);
+
+ scriptenv.default_mailbox = "INBOX";
+ scriptenv.smtp_start = testsuite_smtp_start;
+ scriptenv.smtp_add_rcpt = testsuite_smtp_add_rcpt;
+ scriptenv.smtp_send = testsuite_smtp_send;
+ scriptenv.smtp_abort = testsuite_smtp_abort;
+ scriptenv.smtp_finish = testsuite_smtp_finish;
+ scriptenv.trace_log = trace_log;
+ scriptenv.trace_config = trace_config;
+ scriptenv.exec_status = &exec_status;
+
+ testsuite_scriptenv = &scriptenv;
+
+ testsuite_result_init();
+
+ /* Run the test */
+ ret = testsuite_run(sbin, testsuite_log_main_ehandler);
+
+ switch (ret) {
+ case SIEVE_EXEC_OK:
+ break;
+ case SIEVE_EXEC_FAILURE:
+ case SIEVE_EXEC_KEEP_FAILED:
+ case SIEVE_EXEC_TEMP_FAILURE:
+ testsuite_testcase_fail(
+ "test script execution aborted due to error");
+ break;
+ case SIEVE_EXEC_BIN_CORRUPT:
+ testsuite_testcase_fail(
+ "compiled test script binary is corrupt");
+ break;
+ case SIEVE_EXEC_RESOURCE_LIMIT:
+ testsuite_testcase_fail(
+ "resource limit exceeded");
+ break;
+ }
+
+ sieve_close(&sbin);
+
+ /* De-initialize message environment */
+ testsuite_result_deinit();
+ testsuite_message_deinit();
+ testsuite_mailstore_deinit();
+
+ if (trace_log != NULL)
+ sieve_trace_log_free(&trace_log);
+
+ testsuite_scriptenv = NULL;
+ } else {
+ testsuite_testcase_fail("failed to compile testcase script");
+ }
+
+ /* De-initialize testsuite */
+ testsuite_deinit();
+ testsuite_settings_deinit();
+
+ sieve_tool_deinit(&sieve_tool);
+
+ if (!testsuite_testcase_result(expect_failure))
+ return EXIT_FAILURE;
+
+ return EXIT_SUCCESS;
+}
diff --git a/pigeonhole/src/testsuite/tst-test-error.c b/pigeonhole/src/testsuite/tst-test-error.c
new file mode 100644
index 0000000..f2f2eb9
--- /dev/null
+++ b/pigeonhole/src/testsuite/tst-test-error.c
@@ -0,0 +1,273 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-script.h"
+#include "sieve-commands.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+#include "sieve-match.h"
+
+#include "testsuite-common.h"
+#include "testsuite-log.h"
+
+/*
+ * Test_error command
+ *
+ * Syntax:
+ * test [MATCH-TYPE] [COMPARATOR] [:index number] <key-list: string-list>
+ */
+
+static bool tst_test_error_registered
+ (struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool tst_test_error_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool tst_test_error_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+const struct sieve_command_def tst_test_error = {
+ .identifier = "test_error",
+ .type = SCT_TEST,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_test_error_registered,
+ .validate = tst_test_error_validate,
+ .generate = tst_test_error_generate
+};
+
+/*
+ * Operation
+ */
+
+static bool tst_test_error_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int tst_test_error_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def test_error_operation = {
+ .mnemonic = "TEST_ERROR",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_ERROR,
+ .dump = tst_test_error_operation_dump,
+ .execute = tst_test_error_operation_execute
+};
+
+/*
+ * Tagged arguments
+ */
+
+/* NOTE: This will be merged with the date-index extension when it is
+ * implemented.
+ */
+
+static bool tst_test_error_validate_index_tag
+ (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+static const struct sieve_argument_def test_error_index_tag = {
+ .identifier = "index",
+ .validate = tst_test_error_validate_index_tag
+};
+
+enum tst_test_error_optional {
+ OPT_INDEX = SIEVE_MATCH_OPT_LAST,
+};
+
+
+/*
+ * Argument implementation
+ */
+
+static bool tst_test_error_validate_index_tag
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ /* Check syntax:
+ * :index number
+ */
+ if ( !sieve_validate_tag_parameter
+ (valdtr, cmd, tag, *arg, NULL, 0, SAAT_NUMBER, FALSE) ) {
+ return FALSE;
+ }
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+ return TRUE;
+}
+
+
+/*
+ * Command registration
+ */
+
+static bool tst_test_error_registered
+(struct sieve_validator *valdtr, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ /* The order of these is not significant */
+ sieve_comparators_link_tag(valdtr, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
+ sieve_match_types_link_tags(valdtr, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
+
+ sieve_validator_register_tag
+ (valdtr, cmd_reg, ext, &test_error_index_tag, OPT_INDEX);
+
+ return TRUE;
+}
+
+/*
+ * Validation
+ */
+
+static bool tst_test_error_validate
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+ struct sieve_comparator cmp_default =
+ SIEVE_COMPARATOR_DEFAULT(i_octet_comparator);
+ struct sieve_match_type mcht_default =
+ SIEVE_COMPARATOR_DEFAULT(is_match_type);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "key list", 2, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ /* Validate the key argument to a specified match type */
+ return sieve_match_type_validate
+ (valdtr, tst, arg, &mcht_default, &cmp_default);
+}
+
+/*
+ * Code generation
+ */
+
+static bool tst_test_error_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
+{
+ sieve_operation_emit(cgenv->sblock, tst->ext, &test_error_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, tst, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool tst_test_error_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "TEST_ERROR:");
+ sieve_code_descend(denv);
+
+ /* Handle any optional arguments */
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_match_opr_optional_dump(denv, address, &opt_code))
+ < 0 )
+ return FALSE;
+
+ if ( opt == 0 ) break;
+
+ if ( opt_code == OPT_INDEX ) {
+ if ( !sieve_opr_number_dump(denv, address, "index") )
+ return FALSE;
+ } else {
+ return FALSE;
+ }
+ }
+
+ return sieve_opr_stringlist_dump(denv, address, "key list");
+}
+
+/*
+ * Intepretation
+ */
+
+static int tst_test_error_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ int opt_code = 0;
+ struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_octet_comparator);
+ struct sieve_match_type mcht = SIEVE_COMPARATOR_DEFAULT(is_match_type);
+ struct sieve_stringlist *value_list, *key_list;
+ int index = -1;
+ int match, ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Read optional operands */
+ for (;;) {
+ sieve_number_t number;
+ int opt;
+
+ if ( (opt=sieve_match_opr_optional_read
+ (renv, address, &opt_code, &ret, &cmp, &mcht)) < 0 )
+ return ret;
+
+ if ( opt == 0 ) break;
+
+ if ( opt_code == OPT_INDEX ) {
+ if ( (ret=sieve_opr_number_read(renv, address, "index", &number)) <= 0 )
+ return ret;
+ index = (int) number;
+ } else {
+ sieve_runtime_trace_error(renv, "invalid optional operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ }
+
+ /* Read key-list */
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "key_list", &key_list))
+ <= 0 )
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ if ( index > 0 )
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "testsuite: test_error test; match error message [index=%d]", index);
+ else
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "testsuite: test_error test; match error messages");
+
+ /* Create value stringlist */
+ value_list = testsuite_log_stringlist_create(renv, index);
+
+ /* Perform match */
+ if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret)) < 0 )
+ return ret;
+
+ /* Set test result for subsequent conditional jump */
+ sieve_interpreter_set_test_result(renv->interp, match > 0);
+ return SIEVE_EXEC_OK;
+}
+
+
+
+
diff --git a/pigeonhole/src/testsuite/tst-test-multiscript.c b/pigeonhole/src/testsuite/tst-test-multiscript.c
new file mode 100644
index 0000000..b4b2a0e
--- /dev/null
+++ b/pigeonhole/src/testsuite/tst-test-multiscript.c
@@ -0,0 +1,155 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-script.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+#include "sieve.h"
+
+#include "testsuite-common.h"
+#include "testsuite-script.h"
+
+/*
+ * Test_multiscript command
+ *
+ * Syntax:
+ * test_multiscript <scripts: string-list>
+ */
+
+static bool tst_test_multiscript_validate
+ (struct sieve_validator *validator, struct sieve_command *cmd);
+static bool tst_test_multiscript_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *tst);
+
+const struct sieve_command_def tst_test_multiscript = {
+ .identifier = "test_multiscript",
+ .type = SCT_TEST,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = tst_test_multiscript_validate,
+ .generate = tst_test_multiscript_generate,
+};
+
+/*
+ * Operation
+ */
+
+static bool tst_test_multiscript_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int tst_test_multiscript_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def test_multiscript_operation = {
+ .mnemonic = "TEST_MULTISCRIPT",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_MULTISCRIPT,
+ .dump = tst_test_multiscript_operation_dump,
+ .execute = tst_test_multiscript_operation_execute
+};
+
+/*
+ * Validation
+ */
+
+static bool tst_test_multiscript_validate
+(struct sieve_validator *valdtr, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "scripts", 1, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ return sieve_validator_argument_activate(valdtr, tst, arg, FALSE);
+}
+
+/*
+ * Code generation
+ */
+
+static bool tst_test_multiscript_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
+{
+ sieve_operation_emit(cgenv->sblock, tst->ext, &test_multiscript_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, tst, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool tst_test_multiscript_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "TEST_MULTISCRIPT:");
+ sieve_code_descend(denv);
+
+ if ( !sieve_opr_stringlist_dump(denv, address, "scripts") )
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Intepretation
+ */
+
+static int tst_test_multiscript_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ struct sieve_stringlist *scripts_list;
+ string_t *script_name;
+ ARRAY_TYPE (const_string) scriptfiles;
+ bool result = TRUE;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "scripts", &scripts_list))
+ <= 0 )
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "testsuite: test_multiscript test");
+ sieve_runtime_trace_descend(renv);
+
+ t_array_init(&scriptfiles, 16);
+
+ script_name = NULL;
+ while ( result &&
+ (ret=sieve_stringlist_next_item(scripts_list, &script_name)) > 0 ) {
+ const char *script = t_strdup(str_c(script_name));
+
+ array_append(&scriptfiles, &script, 1);
+ }
+
+ result = result && (ret >= 0) &&
+ testsuite_script_multiscript(renv, &scriptfiles);
+
+ /* Set result */
+ sieve_interpreter_set_test_result(renv->interp, result);
+
+ return SIEVE_EXEC_OK;
+}
+
+
+
+
diff --git a/pigeonhole/src/testsuite/tst-test-result-action.c b/pigeonhole/src/testsuite/tst-test-result-action.c
new file mode 100644
index 0000000..75d4a2f
--- /dev/null
+++ b/pigeonhole/src/testsuite/tst-test-result-action.c
@@ -0,0 +1,268 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-script.h"
+#include "sieve-commands.h"
+#include "sieve-actions.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-result.h"
+#include "sieve-dump.h"
+#include "sieve-match.h"
+
+#include "testsuite-common.h"
+#include "testsuite-result.h"
+
+/*
+ * test_result_action command
+ *
+ * Syntax:
+ * test_result_action [MATCH-TYPE] [COMPARATOR] [:index number]
+ * <key-list: string-list>
+ */
+
+static bool tst_test_result_action_registered
+ (struct sieve_validator *validator, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool tst_test_result_action_validate
+ (struct sieve_validator *validator, struct sieve_command *cmd);
+static bool tst_test_result_action_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
+
+const struct sieve_command_def tst_test_result_action = {
+ .identifier = "test_result_action",
+ .type = SCT_TEST,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_test_result_action_registered,
+ .validate = tst_test_result_action_validate,
+ .generate = tst_test_result_action_generate
+};
+
+/*
+ * Operation
+ */
+
+static bool tst_test_result_action_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int tst_test_result_action_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def test_result_action_operation = {
+ .mnemonic = "TEST_RESULT_ACTION",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_RESULT_ACTION,
+ .dump = tst_test_result_action_operation_dump,
+ .execute = tst_test_result_action_operation_execute
+};
+
+/*
+ * Tagged arguments
+ */
+
+/* FIXME: merge this with the test_error version of this tag */
+
+static bool tst_test_result_action_validate_index_tag
+ (struct sieve_validator *validator, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd);
+
+static const struct sieve_argument_def test_result_action_index_tag = {
+ .identifier = "index",
+ .validate = tst_test_result_action_validate_index_tag
+};
+
+enum tst_test_result_action_optional {
+ OPT_INDEX = SIEVE_MATCH_OPT_LAST,
+};
+
+/*
+ * Argument implementation
+ */
+
+static bool tst_test_result_action_validate_index_tag
+(struct sieve_validator *validator, struct sieve_ast_argument **arg,
+ struct sieve_command *cmd)
+{
+ struct sieve_ast_argument *tag = *arg;
+
+ /* Detach the tag itself */
+ *arg = sieve_ast_arguments_detach(*arg,1);
+
+ /* Check syntax:
+ * :index number
+ */
+ if ( !sieve_validate_tag_parameter
+ (validator, cmd, tag, *arg, NULL, 0, SAAT_NUMBER, FALSE) ) {
+ return FALSE;
+ }
+
+ /* Skip parameter */
+ *arg = sieve_ast_argument_next(*arg);
+ return TRUE;
+}
+
+
+/*
+ * Command registration
+ */
+
+static bool tst_test_result_action_registered
+(struct sieve_validator *validator, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ /* The order of these is not significant */
+ sieve_comparators_link_tag(validator, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
+ sieve_match_types_link_tags(validator, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
+
+ sieve_validator_register_tag
+ (validator, cmd_reg, ext, &test_result_action_index_tag, OPT_INDEX);
+
+ return TRUE;
+}
+
+/*
+ * Validation
+ */
+
+static bool tst_test_result_action_validate
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+ struct sieve_comparator cmp_default =
+ SIEVE_COMPARATOR_DEFAULT(i_octet_comparator);
+ struct sieve_match_type mcht_default =
+ SIEVE_COMPARATOR_DEFAULT(is_match_type);
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "key list", 2, SAAT_STRING_LIST) ) {
+ return FALSE;
+ }
+
+ if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
+ return FALSE;
+
+ /* Validate the key argument to a specified match type */
+ return sieve_match_type_validate
+ (valdtr, tst, arg, &mcht_default, &cmp_default);
+}
+
+/*
+ * Code generation
+ */
+
+static bool tst_test_result_action_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
+{
+ sieve_operation_emit(cgenv->sblock, tst->ext, &test_result_action_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, tst, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool tst_test_result_action_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "TEST_RESULT_ACTION:");
+ sieve_code_descend(denv);
+
+ /* Handle any optional arguments */
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_match_opr_optional_dump(denv, address, &opt_code))
+ < 0 )
+ return FALSE;
+
+ if ( opt == 0 ) break;
+
+ if ( opt_code == OPT_INDEX ) {
+ if ( !sieve_opr_number_dump(denv, address, "index") )
+ return FALSE;
+ } else {
+ return FALSE;
+ }
+ }
+
+ return sieve_opr_stringlist_dump(denv, address, "key list");
+}
+
+/*
+ * Intepretation
+ */
+
+static int tst_test_result_action_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ int opt_code = 0;
+ struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_octet_comparator);
+ struct sieve_match_type mcht = SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
+ struct sieve_stringlist *value_list, *key_list;
+ int index = 0;
+ int match, ret;
+
+ /*
+ * Read operands
+ */
+
+ /* Read optional operands */
+ for (;;) {
+ sieve_number_t number;
+ int opt;
+
+ if ( (opt=sieve_match_opr_optional_read
+ (renv, address, &opt_code, &ret, &cmp, &mcht)) < 0 )
+ return ret;
+
+ if ( opt == 0 ) break;
+
+ if ( opt_code == OPT_INDEX ) {
+ if ( (ret=sieve_opr_number_read(renv, address, "index", &number)) <= 0 )
+ return ret;
+ index = (int) number;
+ } else {
+ sieve_runtime_trace_error(renv, "invalid optional operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ }
+
+ /* Read key-list */
+ if ( (ret=sieve_opr_stringlist_read(renv, address, "key-list", &key_list))
+ <= 0 )
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "testsuite: test_result_action test; match result name (index: %d)", index);
+
+ /* Create value stringlist */
+ value_list = testsuite_result_stringlist_create(renv, index);
+
+ /* Perform match */
+ if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret)) < 0 )
+ return ret;
+
+ /* Set test result for subsequent conditional jump */
+ sieve_interpreter_set_test_result(renv->interp, match > 0);
+ return SIEVE_EXEC_OK;
+}
+
+
+
diff --git a/pigeonhole/src/testsuite/tst-test-result-execute.c b/pigeonhole/src/testsuite/tst-test-result-execute.c
new file mode 100644
index 0000000..1b9a7ee
--- /dev/null
+++ b/pigeonhole/src/testsuite/tst-test-result-execute.c
@@ -0,0 +1,96 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-script.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+#include "sieve.h"
+
+#include "testsuite-common.h"
+#include "testsuite-result.h"
+
+/*
+ * Test_result_execute command
+ *
+ * Syntax:
+ * test_result_execute
+ */
+
+static bool tst_test_result_execute_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
+
+const struct sieve_command_def tst_test_result_execute = {
+ .identifier = "test_result_execute",
+ .type = SCT_TEST,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .generate = tst_test_result_execute_generate
+};
+
+/*
+ * Operation
+ */
+
+static int tst_test_result_execute_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def test_result_execute_operation = {
+ .mnemonic = "TEST_RESULT_EXECUTE",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_RESULT_EXECUTE,
+ .execute = tst_test_result_execute_operation_execute
+};
+
+/*
+ * Code generation
+ */
+
+static bool tst_test_result_execute_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
+{
+ sieve_operation_emit(cgenv->sblock, tst->ext, &test_result_execute_operation);
+
+ return TRUE;
+}
+
+/*
+ * Intepretation
+ */
+
+static int tst_test_result_execute_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address ATTR_UNUSED)
+{
+ bool result = TRUE;
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "testsuite: test_result_execute test");
+
+ result = testsuite_result_execute(renv);
+
+ if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_TESTS) ) {
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(renv, 0, "execution of result %s",
+ ( result ? "succeeded" : "failed" ));
+ }
+
+ /* Set result */
+ sieve_interpreter_set_test_result(renv->interp, result);
+
+ return SIEVE_EXEC_OK;
+}
+
+
+
+
diff --git a/pigeonhole/src/testsuite/tst-test-script-compile.c b/pigeonhole/src/testsuite/tst-test-script-compile.c
new file mode 100644
index 0000000..c053486
--- /dev/null
+++ b/pigeonhole/src/testsuite/tst-test-script-compile.c
@@ -0,0 +1,144 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-script.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+#include "sieve.h"
+
+#include "testsuite-common.h"
+#include "testsuite-script.h"
+
+/*
+ * Test_script_compile command
+ *
+ * Syntax:
+ * test_script_compile <scriptpath: string>
+ */
+
+static bool tst_test_script_compile_validate
+ (struct sieve_validator *valdtr, struct sieve_command *cmd);
+static bool tst_test_script_compile_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
+
+const struct sieve_command_def tst_test_script_compile = {
+ .identifier = "test_script_compile",
+ .type = SCT_TEST,
+ .positional_args = 1,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .validate = tst_test_script_compile_validate,
+ .generate = tst_test_script_compile_generate
+};
+
+/*
+ * Operation
+ */
+
+static bool tst_test_script_compile_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int tst_test_script_compile_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def test_script_compile_operation = {
+ .mnemonic = "TEST_SCRIPT_COMPILE",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_SCRIPT_COMPILE,
+ .dump = tst_test_script_compile_operation_dump,
+ .execute = tst_test_script_compile_operation_execute
+};
+
+/*
+ * Validation
+ */
+
+static bool tst_test_script_compile_validate
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *tst)
+{
+ struct sieve_ast_argument *arg = tst->first_positional;
+
+ if ( !sieve_validate_positional_argument
+ (valdtr, tst, arg, "script", 1, SAAT_STRING) ) {
+ return FALSE;
+ }
+
+ return sieve_validator_argument_activate(valdtr, tst, arg, FALSE);
+}
+
+/*
+ * Code generation
+ */
+
+static bool tst_test_script_compile_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
+{
+ sieve_operation_emit(cgenv->sblock, tst->ext, &test_script_compile_operation);
+
+ /* Generate arguments */
+ return sieve_generate_arguments(cgenv, tst, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool tst_test_script_compile_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ sieve_code_dumpf(denv, "TEST_SCRIPT_COMPILE:");
+ sieve_code_descend(denv);
+
+ if ( !sieve_opr_string_dump(denv, address, "script-name") )
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Intepretation
+ */
+
+static int tst_test_script_compile_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ string_t *script_name;
+ bool result = TRUE;
+ int ret;
+
+ /*
+ * Read operands
+ */
+
+ if ( (ret=sieve_opr_string_read(renv, address, "script-name", &script_name))
+ <= 0 )
+ return ret;
+
+ /*
+ * Perform operation
+ */
+
+ if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_TESTS) ) {
+ sieve_runtime_trace(renv, 0, "testsuite: test_script_compile test");
+ sieve_runtime_trace_descend(renv);
+ }
+
+ /* Attempt script compile */
+
+ result = testsuite_script_compile(renv, str_c(script_name));
+
+ /* Set result */
+ sieve_interpreter_set_test_result(renv->interp, result);
+
+ return SIEVE_EXEC_OK;
+}
+
+
+
+
diff --git a/pigeonhole/src/testsuite/tst-test-script-run.c b/pigeonhole/src/testsuite/tst-test-script-run.c
new file mode 100644
index 0000000..214a5c6
--- /dev/null
+++ b/pigeonhole/src/testsuite/tst-test-script-run.c
@@ -0,0 +1,198 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-script.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+#include "sieve.h"
+
+#include "testsuite-common.h"
+#include "testsuite-script.h"
+#include "testsuite-result.h"
+
+/*
+ * Test_script_run command
+ *
+ * Syntax:
+ * test_script_run
+ */
+
+static bool tst_test_script_run_registered
+(struct sieve_validator *validator, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg);
+static bool tst_test_script_run_generate
+ (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
+
+const struct sieve_command_def tst_test_script_run = {
+ .identifier = "test_script_run",
+ .type = SCT_TEST,
+ .positional_args = 0,
+ .subtests = 0,
+ .block_allowed = FALSE,
+ .block_required = FALSE,
+ .registered = tst_test_script_run_registered,
+ .generate = tst_test_script_run_generate
+};
+
+/*
+ * Operation
+ */
+
+static bool tst_test_script_run_operation_dump
+ (const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static int tst_test_script_run_operation_execute
+ (const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation_def test_script_run_operation = {
+ .mnemonic = "TEST_SCRIPT_RUN",
+ .ext_def = &testsuite_extension,
+ .code = TESTSUITE_OPERATION_TEST_SCRIPT_RUN,
+ .dump = tst_test_script_run_operation_dump,
+ .execute = tst_test_script_run_operation_execute
+};
+
+/*
+ * Tagged arguments
+ */
+
+/* Codes for optional arguments */
+
+enum cmd_vacation_optional {
+ OPT_END,
+ OPT_APPEND_RESULT
+};
+
+/* Tags */
+
+static const struct sieve_argument_def append_result_tag = {
+ .identifier = "append_result"
+};
+
+static bool tst_test_script_run_registered
+(struct sieve_validator *validator, const struct sieve_extension *ext,
+ struct sieve_command_registration *cmd_reg)
+{
+ sieve_validator_register_tag
+ (validator, cmd_reg, ext, &append_result_tag, OPT_APPEND_RESULT);
+
+ return TRUE;
+}
+
+
+/*
+ * Code generation
+ */
+
+static bool tst_test_script_run_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
+{
+ sieve_operation_emit(cgenv->sblock, tst->ext, &test_script_run_operation);
+
+ return sieve_generate_arguments(cgenv, tst, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool tst_test_script_run_operation_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+ int opt_code = 0;
+
+ sieve_code_dumpf(denv, "TEST_SCRIPT_RUN");
+ sieve_code_descend(denv);
+
+ /* Dump optional operands */
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_opr_optional_dump(denv, address, &opt_code)) < 0 )
+ return FALSE;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_APPEND_RESULT:
+ sieve_code_dumpf(denv, "append_result");
+ break;
+ default:
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Intepretation
+ */
+
+static int tst_test_script_run_operation_execute
+(const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+ bool append_result = FALSE;
+ int opt_code = 0;
+ bool result = TRUE;
+
+ /*
+ * Read operands
+ */
+
+ /* Optional operands */
+ for (;;) {
+ int opt;
+
+ if ( (opt=sieve_opr_optional_read(renv, address, &opt_code)) < 0 )
+ return SIEVE_EXEC_BIN_CORRUPT;
+
+ if ( opt == 0 ) break;
+
+ switch ( opt_code ) {
+ case OPT_APPEND_RESULT:
+ append_result = TRUE;
+ break;
+ default:
+ sieve_runtime_trace_error(renv,
+ "unknown optional operand");
+ return SIEVE_EXEC_BIN_CORRUPT;
+ }
+ }
+
+ /*
+ * Perform operation
+ */
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
+ "testsuite: run compiled script [append_result=%s]",
+ ( append_result ? "yes" : "no" ));
+
+ /* Reset result object */
+ if ( !append_result )
+ testsuite_result_reset(renv);
+
+ /* Run script */
+ result = testsuite_script_run(renv);
+
+ if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_TESTS) ) {
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(renv, 0, "execution of script %s",
+ ( result ? "succeeded" : "failed" ));
+ }
+
+ /* Indicate test status */
+ sieve_interpreter_set_test_result(renv->interp, result);
+
+ return SIEVE_EXEC_OK;
+}
+
+
+
+
diff --git a/pigeonhole/stamp.h.in b/pigeonhole/stamp.h.in
new file mode 100644
index 0000000..4bd8276
--- /dev/null
+++ b/pigeonhole/stamp.h.in
@@ -0,0 +1 @@
+// empty file
diff --git a/pigeonhole/tests/comparators/i-ascii-casemap.svtest b/pigeonhole/tests/comparators/i-ascii-casemap.svtest
new file mode 100644
index 0000000..0891f3e
--- /dev/null
+++ b/pigeonhole/tests/comparators/i-ascii-casemap.svtest
@@ -0,0 +1,39 @@
+require "vnd.dovecot.testsuite";
+
+test_set "message" text:
+From: stephan@example.org
+Cc: frop@example.com
+To: test@dovecot.example.net
+X-A: This is a TEST header
+Subject: Test Message
+
+Test!
+.
+;
+
+test "i;ascii-casemap :contains (1)" {
+ if not header :contains :comparator "i;ascii-casemap" "X-A" "TEST" {
+ test_fail "should have matched";
+ }
+}
+
+test "i;ascii-casemap :contains (2)" {
+ if not header :contains :comparator "i;ascii-casemap" "X-A" "test" {
+ test_fail "should have matched";
+ }
+}
+
+test "i;ascii-casemap :matches (1)" {
+ if not header :matches :comparator "i;ascii-casemap" "X-A" "This*TEST*r" {
+ test_fail "should have matched";
+ }
+}
+
+test "i;ascii-casemap :matches (2)" {
+ if not header :matches :comparator "i;ascii-casemap" "X-A" "ThIs*tEsT*R" {
+ test_fail "should have matched";
+ }
+}
+
+
+
diff --git a/pigeonhole/tests/comparators/i-octet.svtest b/pigeonhole/tests/comparators/i-octet.svtest
new file mode 100644
index 0000000..b6041bc
--- /dev/null
+++ b/pigeonhole/tests/comparators/i-octet.svtest
@@ -0,0 +1,37 @@
+require "vnd.dovecot.testsuite";
+
+test_set "message" text:
+From: stephan@example.org
+Cc: frop@example.com
+To: test@dovecot.example.net
+X-A: This is a TEST header
+Subject: Test Message
+
+Test!
+.
+;
+
+test "i;octet :contains" {
+ if not header :contains :comparator "i;octet" "X-A" "TEST" {
+ test_fail "should have matched";
+ }
+}
+
+test "i;octet not :contains" {
+ if header :contains :comparator "i;octet" "X-A" "test" {
+ test_fail "should not have matched";
+ }
+}
+
+test "i;octet :matches" {
+ if not header :matches :comparator "i;octet" "X-A" "This*TEST*r" {
+ test_fail "should have matched";
+ }
+}
+
+test "i;octet not :matches" {
+ if header :matches :comparator "i;octet" "X-A" "ThIs*tEsT*R" {
+ test_fail "should not have matched";
+ }
+}
+
diff --git a/pigeonhole/tests/compile/compile.svtest b/pigeonhole/tests/compile/compile.svtest
new file mode 100644
index 0000000..7abda7f
--- /dev/null
+++ b/pigeonhole/tests/compile/compile.svtest
@@ -0,0 +1,16 @@
+require "vnd.dovecot.testsuite";
+
+# Just test whether valid scripts will compile without problems
+
+test "Trivial" {
+ if not test_script_compile "trivial.sieve" {
+ test_fail "could not compile";
+ }
+}
+
+test "Redirect" {
+ if not test_script_compile "redirect.sieve" {
+ test_fail "could not compile";
+ }
+}
+
diff --git a/pigeonhole/tests/compile/errors.svtest b/pigeonhole/tests/compile/errors.svtest
new file mode 100644
index 0000000..f17ea3f
--- /dev/null
+++ b/pigeonhole/tests/compile/errors.svtest
@@ -0,0 +1,395 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Errors triggered in the compiled scripts are pretty reduntant over the
+ * tested commands, but we want to be thorough.
+ */
+
+/*
+ * Lexer errors
+ */
+
+test "Lexer errors (FIXME: count only)" {
+ if test_script_compile "errors/lexer.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "9" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Parser errors
+ */
+
+test "Parser errors (FIXME: count only)" {
+ if test_script_compile "errors/parser.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "9" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Header test
+ */
+
+test "Header errors" {
+ if test_script_compile "errors/header.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "10" {
+ test_fail "wrong number of errors reported";
+ }
+
+ if not test_error :index 1 :matches
+ "unknown * ':all' for * header test *" {
+ test_fail "error 1 is invalid";
+ }
+
+ if not test_error :index 2 :matches
+ "*header test * string list * 1 (header names), but * number *" {
+ test_fail "error 2 is invalid";
+ }
+
+ if not test_error :index 3 :matches
+ "*header test * string list * 2 (key list), * number *" {
+ test_fail "error 3 is invalid";
+ }
+
+ if not test_error :index 4 :matches
+ "unknown tagged argument ':tag' for the header test *" {
+ test_fail "error 4 is invalid";
+ }
+
+ if not test_error :index 5 :matches
+ "* header test requires 2 *, but 1 *" {
+ test_fail "error 5 is invalid";
+ }
+
+ if not test_error :index 6 :matches
+ "* header test requires 2 *, but 0 *" {
+ test_fail "error 6 is invalid";
+ }
+
+ if not test_error :index 7 :matches
+ "*header test accepts no sub-tests* specified*" {
+ test_fail "error 7 is invalid";
+ }
+
+ if not test_error :index 8 :matches
+ "* use test 'header' * command*" {
+ test_fail "error 8 is invalid";
+ }
+
+ if not test_error :index 9 :matches
+ "* use test 'header' * command*" {
+ test_fail "error 9 is invalid";
+ }
+
+ if test_error :index 4 :contains "radish" {
+ test_fail "error test matched nonsense";
+ }
+}
+
+/*
+ * Address test
+ */
+
+
+test "Address errors" {
+ if test_script_compile "errors/address.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "9" {
+ test_fail "wrong number of errors reported";
+ }
+
+ if not test_error :index 1 :matches
+ "*unknown * ':nonsense' * address test*" {
+ test_fail "error 1 is invalid";
+ }
+
+ if not test_error :index 2 :matches
+ "*address test expects *string list * 1 (header list),* number * found*" {
+ test_fail "error 2 is invalid";
+ }
+
+ if not test_error :index 3 :matches
+ "*address test expects *string list * 2 (key list),* number * found*" {
+ test_fail "error 3 is invalid";
+ }
+
+ if not test_error :index 4 :matches
+ "*unexpected *':is' * address test*" {
+ test_fail "error 4 is invalid";
+ }
+
+ if not test_error :index 5 :matches
+ "*address test * 2 positional arg*, but 1*" {
+ test_fail "error 5 is invalid";
+ }
+
+ if not test_error :index 6 :matches
+ "*address test * 2 positional arg*, but 0*" {
+ test_fail "error 6 is invalid";
+ }
+
+ if not test_error :index 7 :matches
+ "*'frop' *not allowed *address test*" {
+ test_fail "error 7 is invalid";
+ }
+
+ if not test_error :index 8 :matches
+ "*'frop' *not allowed *address test*" {
+ test_fail "error 8 is invalid";
+ }
+
+ if test_error :index 23 :contains "radish" {
+ test_fail "error test matched nonsense";
+ }
+}
+
+/*
+ * If command
+ */
+
+test "If errors (FIXME: count only)" {
+ if test_script_compile "errors/if.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "12" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Require command
+ */
+
+test "Require errors (FIXME: count only)" {
+ if test_script_compile "errors/require.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "15" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Size test
+ */
+
+test "Size errors (FIXME: count only)" {
+ if test_script_compile "errors/size.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "7" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Envelope test
+ */
+
+test "Envelope errors (FIXME: count only)" {
+ if test_script_compile "errors/envelope.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Stop command
+ */
+
+test "Stop errors (FIXME: count only)" {
+ if test_script_compile "errors/stop.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "9" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Keep command
+ */
+
+test "Keep errors (FIXME: count only)" {
+ if test_script_compile "errors/keep.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Fileinto command
+ */
+
+test "Fileinto errors (FIXME: count only)" {
+ if test_script_compile "errors/fileinto.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "10" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * COMPARATOR errors
+ */
+
+test "COMPARATOR errors (FIXME: count only)" {
+ if test_script_compile "errors/comparator.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "6" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * ADDRESS-PART errors
+ */
+
+test "ADDRESS-PART errors (FIXME: count only)" {
+ if test_script_compile "errors/address-part.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * MATCH-TYPE errors
+ */
+
+test "MATCH-TYPE errors (FIXME: count only)" {
+ if test_script_compile "errors/match-type.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "2" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Encoded-character errors
+ */
+
+test "Encoded-character errors (FIXME: count only)" {
+ if test_script_compile "errors/encoded-character.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Outgoing address errors
+ */
+
+test "Outgoing address errors (FIXME: count only)" {
+ if test_script_compile "errors/out-address.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "16" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Tagged argument errors
+ */
+
+test "Tagged argument errors (FIXME: count only)" {
+ if test_script_compile "errors/tag.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Typos
+ */
+
+test "Typos" {
+ if test_script_compile "errors/typos.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "6" {
+ test_fail "wrong number of errors reported";
+ }
+
+ if not test_error :index 1 :matches
+ "missing semicolon * fileinto *" {
+ test_fail "error 1 is invalid";
+ }
+
+ if not test_error :index 2 :matches
+ "*fileinto command * no *tests* specified*" {
+ test_fail "error 2 is invalid";
+ }
+
+ if not test_error :index 3 :matches
+ "missing semicolon * fileinto *" {
+ test_fail "error 3 is invalid";
+ }
+
+ if not test_error :index 4 :matches
+ "*address test requires 2 * 0 * specified" {
+ test_fail "error 4 is invalid";
+ }
+
+ if not test_error :index 5 :matches
+ "missing colon *matches* tag * address test" {
+ test_fail "error 5 is invalid";
+ }
+}
+
+
+/*
+ * Unsupported language features
+ */
+
+test "Unsupported language features (FIXME: count only)" {
+ if test_script_compile "errors/unsupported.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
diff --git a/pigeonhole/tests/compile/errors/address-part.sieve b/pigeonhole/tests/compile/errors/address-part.sieve
new file mode 100644
index 0000000..1d10cbf
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/address-part.sieve
@@ -0,0 +1,17 @@
+/*
+ * Address part errors
+ *
+ * Total errors: 2 (+1 = 3)
+ */
+
+# Duplicate address part (1)
+if address :all :comparator "i;octet" :domain "from" "STEPHAN" {
+
+ # Duplicate address part (2)
+ if address :domain :localpart :comparator "i;octet" "from" "friep.example.com" {
+ keep;
+ }
+
+ stop;
+}
+
diff --git a/pigeonhole/tests/compile/errors/address.sieve b/pigeonhole/tests/compile/errors/address.sieve
new file mode 100644
index 0000000..f7d3b26
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/address.sieve
@@ -0,0 +1,71 @@
+require "comparator-i;ascii-numeric";
+
+/*
+ * Address test errors
+ *
+ * Total count: 8 (+1 = 9)
+ */
+
+/*
+ * Command structure
+ */
+
+# Invalid tag
+if address :nonsense :comparator "i;ascii-casemap" :localpart "From" "nico" {
+ discard;
+}
+
+# Invalid first argument
+if address :is :comparator "i;ascii-numeric" :localpart 45 "nico" {
+ discard;
+}
+
+# Invalid second argument
+if address :is :comparator "i;ascii-numeric" :localpart "From" 45 {
+ discard;
+}
+
+# Invalid second argument
+if address :comparator "i;ascii-numeric" :localpart "From" :is {
+ discard;
+}
+
+# Missing second argument
+if address :is :comparator "i;ascii-numeric" :localpart "From" {
+ discard;
+}
+
+# Missing arguments
+if address :is :comparator "i;ascii-numeric" :localpart {
+ discard;
+}
+
+# Not an error
+if address :localpart :is :comparator "i;ascii-casemap" "from" ["frop", "frop"] {
+ discard;
+}
+
+/*
+ * Specified headers must contain addresses
+ */
+
+# Invalid header
+if address :is "frop" "frml" {
+ keep;
+}
+
+# Not an error
+if address :is "reply-to" "frml" {
+ keep;
+}
+
+# Invalid header (#2)
+if address :is ["to", "frop"] "frml" {
+ keep;
+}
+
+# Not an error
+if address :is ["to", "reply-to"] "frml" {
+ keep;
+}
+
diff --git a/pigeonhole/tests/compile/errors/comparator.sieve b/pigeonhole/tests/compile/errors/comparator.sieve
new file mode 100644
index 0000000..368b56b
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/comparator.sieve
@@ -0,0 +1,21 @@
+/*
+ * Address part errors
+ *
+ * Total errors: 5 (+1 = 6)
+ */
+
+# 1: No argument
+if address :comparator { }
+
+# 2: Number argument
+if address :comparator 1 "from" "frop" { }
+
+# 3: String list argument
+if address :comparator ["a", "b"] "from" "frop" { }
+
+# 4: Unknown tag
+if address :comparator :frop "from" "frop" { }
+
+# 5: Known tag
+if address :comparator :all "from" "frop" { }
+
diff --git a/pigeonhole/tests/compile/errors/encoded-character.sieve b/pigeonhole/tests/compile/errors/encoded-character.sieve
new file mode 100644
index 0000000..04d9de4
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/encoded-character.sieve
@@ -0,0 +1,23 @@
+/*
+ * Encoded-character errors
+ *
+ * Total errors: 2 (+1 = 3)
+ */
+
+require "encoded-character";
+require "fileinto";
+
+# Invalid unicode character (1)
+fileinto "INBOX.${unicode:200000}";
+
+# Not an error
+fileinto "INBOX.${unicode:200000";
+
+# Invalid unicode character (2)
+fileinto "INBOX.${Unicode:DF01}";
+
+# Not an error
+fileinto "INBOX.${Unicode:DF01";
+
+
+
diff --git a/pigeonhole/tests/compile/errors/envelope.sieve b/pigeonhole/tests/compile/errors/envelope.sieve
new file mode 100644
index 0000000..9639846
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/envelope.sieve
@@ -0,0 +1,23 @@
+/*
+ * Envelope test errors
+ *
+ * Total errors: 2 (+1 = 3)
+ */
+
+require "envelope";
+
+# Not an error
+if envelope :is "to" "frop@example.org" {
+}
+
+# Unknown envelope part (1)
+if envelope :is "frop" "frop@example.org" {
+}
+
+# Not an error
+if envelope :is ["to","from"] "frop@example.org" {
+}
+
+# Unknown envelope part (2)
+if envelope :is ["to","frop"] "frop@example.org" {
+}
diff --git a/pigeonhole/tests/compile/errors/fileinto.sieve b/pigeonhole/tests/compile/errors/fileinto.sieve
new file mode 100644
index 0000000..0598557
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/fileinto.sieve
@@ -0,0 +1,38 @@
+require "fileinto";
+require "encoded-character";
+
+/*
+ * Fileinto errors
+ *
+ * Total erors: 9 (+1 = 10)
+ */
+
+# Missing string argument
+fileinto;
+
+# Spurious test
+fileinto true;
+
+# Spurious test
+fileinto "Frop" true;
+
+# Spurious number argument
+fileinto 33;
+
+# Spurious tag argument
+fileinto :frop;
+
+# Spurious additional string argument
+fileinto "Frop" "Friep";
+
+# Spurious additional number argument
+fileinto "Frop" 123;
+
+# Spurious additional tag argument
+fileinto "Frop" :frop;
+
+# Bad mailbox name
+fileinto "${hex:ff}rop";
+
+# Not an error
+fileinto "Frop";
diff --git a/pigeonhole/tests/compile/errors/header.sieve b/pigeonhole/tests/compile/errors/header.sieve
new file mode 100644
index 0000000..1c87f94
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/header.sieve
@@ -0,0 +1,57 @@
+require "comparator-i;ascii-numeric";
+
+/*
+ * Compile errors for the header test
+ *
+ * Total errors: 9 (+1 validation failed msg = 10)
+ */
+
+# Unknown tagged argument
+if header :all :comparator "i;ascii-casemap" "From" "nico" {
+ keep;
+}
+
+# Wrong first argument
+if header :is :comparator "i;ascii-numeric" 45 "nico" {
+ keep;
+}
+
+# Wrong second argument
+if header :is :comparator "i;ascii-numeric" "From" 45 {
+ discard;
+}
+
+# Wrong second argument
+if header :is :comparator "i;ascii-numeric" "From" :tag {
+ stop;
+}
+
+# Missing second argument
+if header :is :comparator "i;ascii-numeric" "From" {
+ stop;
+}
+
+# Missing arguments
+if header :is :comparator "i;ascii-numeric" {
+ keep;
+}
+
+# Not an error
+if header :is :comparator "i;ascii-casemap" "frop" ["frop", "frop"] {
+ discard;
+}
+
+# Spurious sub-test
+if header "frop" "frop" true {
+ discard;
+}
+
+# Test used as command with block
+header "frop" "frop" {
+ discard;
+}
+
+# Test used as command
+header "frop" "frop";
+
+
diff --git a/pigeonhole/tests/compile/errors/if.sieve b/pigeonhole/tests/compile/errors/if.sieve
new file mode 100644
index 0000000..6a8537b
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/if.sieve
@@ -0,0 +1,78 @@
+/*
+ * If command errors
+ *
+ * Total errors: 11 (+1 = 12)
+ */
+
+# Spurious argument
+if "frop" true {}
+
+# Spurious argument
+elsif "frop" true {}
+
+# Spurious string list
+if [ "false", "false", "false" ] false {
+ stop;
+}
+
+# No block
+if true;
+
+# No test
+if {
+ keep;
+}
+
+# Spurious test list
+if ( false, false, true ) {
+ keep;
+}
+
+stop;
+
+# If-less else
+else {
+ keep;
+}
+
+# Not an error
+if true {
+ keep;
+}
+
+stop;
+
+# If-less if structure (should produce only one error)
+elsif true {
+ keep;
+}
+elsif true {
+ keep;
+}
+else {
+}
+
+# Elsif after else
+if true {
+ keep;
+} else {
+ stop;
+} elsif true {
+ stop;
+}
+
+# If used as test
+if if true {
+}
+
+# Else if instead of elsif
+
+if true {
+ stop;
+} else if false {
+ keep;
+}
+
+
+
+
diff --git a/pigeonhole/tests/compile/errors/keep.sieve b/pigeonhole/tests/compile/errors/keep.sieve
new file mode 100644
index 0000000..7b3397c
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/keep.sieve
@@ -0,0 +1,14 @@
+/*
+ * Keep errors
+ *
+ * Total erors: 2 (+1 = 3)
+ */
+
+# Spurious string argument
+keep "frop";
+
+# Spurious test
+keep true;
+
+# Not an error
+keep;
diff --git a/pigeonhole/tests/compile/errors/lexer.sieve b/pigeonhole/tests/compile/errors/lexer.sieve
new file mode 100644
index 0000000..9675db1
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/lexer.sieve
@@ -0,0 +1,68 @@
+/*
+ * Lexer tests
+ *
+ * Total errors: 8 (+1 = 9)
+ */
+
+/*
+ * Number limits
+ */
+
+# 1: Number too large
+if size :under 18446744073709551617 {
+ stop;
+}
+
+# 2: Number too large
+if size :under 18446744073709551616 {
+ stop;
+}
+
+# 3: Number too large
+if size :over 180143985094819840k {
+ stop;
+}
+
+# 4: Number too large
+if size :over 1006622342342296M {
+ stop;
+}
+
+# 5: Number too large
+if size :over 34359738368G {
+ stop;
+}
+
+# 6: Number far too large
+if size :over 49834598293485814273947921734981723971293741923 {
+ stop;
+}
+
+# Not an error
+if size :under 18446744073709551615 {
+ stop;
+}
+
+# Not an error
+if size :under 18446744073709551614 {
+ stop;
+}
+
+# Not an error
+if size :under 800G {
+ stop;
+}
+
+/*
+ * Identifier limits
+ */
+
+# 7: Identifier too long
+if this_is_a_rediculously_long_test_name {
+ stop;
+}
+
+# 8: Identifier way too long
+if test :this_is_an_even_more_rediculously_long_tagged_argument_name {
+ stop;
+}
diff --git a/pigeonhole/tests/compile/errors/match-type.sieve b/pigeonhole/tests/compile/errors/match-type.sieve
new file mode 100644
index 0000000..d8e1681
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/match-type.sieve
@@ -0,0 +1,7 @@
+require "comparator-i;ascii-numeric";
+
+if header :contains :comparator "i;ascii-numeric" "from" "friep.example.com" {
+ keep;
+}
+
+keep;
diff --git a/pigeonhole/tests/compile/errors/out-address.sieve b/pigeonhole/tests/compile/errors/out-address.sieve
new file mode 100644
index 0000000..3e39599
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/out-address.sieve
@@ -0,0 +1,33 @@
+require "vacation";
+
+# Error
+
+redirect "@wrong.example.com";
+redirect "error";
+redirect "error@";
+redirect "Stephan Bosch error@example.org";
+redirect "Stephan Bosch <error@example.org";
+redirect " more error @ example.com ";
+redirect "@";
+redirect "<>";
+redirect "Error <";
+redirect "Error <stephan";
+redirect "Error <stephan@";
+redirect "stephan@example.org,tss@example.net";
+redirect "stephan@example.org,%&^&!!~";
+redirect "rüdiger@example.com";
+
+vacation :from "Error" "Ik ben er niet.";
+
+# Ok
+
+redirect "Ok Good <stephan@example.org>";
+redirect "ok@example.com";
+redirect " more @ example.com ";
+
+redirect ".japanese@example.com";
+redirect "japanese.@example.com";
+redirect "japanese...localpart@example.com";
+redirect "..japanese...localpart..@example.com";
+
+vacation :from "good@voorbeeld.nl.example.com" "Ik ben weg!";
diff --git a/pigeonhole/tests/compile/errors/parser.sieve b/pigeonhole/tests/compile/errors/parser.sieve
new file mode 100644
index 0000000..26a1e53
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/parser.sieve
@@ -0,0 +1,78 @@
+/*
+ * Parser errors
+ *
+ * Total errors: 8 (+1 = 9)
+ */
+
+# Too many arguments (1)
+frop :this "is" "a" 2 :long "argument" "list" :and :it :should "fail" :during "parsing" :but "it" "should" "be"
+ "recoverable" "." :this "is" "a" 2 :long "argument" "list" :and :it :should "fail" :during "parsing" :but
+ "it" "should" "be" "recoverable" {
+ stop;
+}
+
+# Garbage argument (2)
+friep $$$;
+
+# Deep block nesting (1)
+if true { if true { if true { if true { if true { if true { if true { if true {
+ if true { if true { if true { if true { if true { if true { if true { if true {
+ if true { if true { if true { if true { if true { if true { if true { if true {
+ if true { if true { if true { if true { if true { if true { if true { if true {
+ if true { if true { if true { if true { if true { if true { if true { if true {
+ stop;
+ } } } } } } } }
+ } } } } } } } }
+ } } } } } } } }
+ } } } } } } } }
+} } } } } } } }
+
+# Deepest block and too deep test (list) nesting (1)
+if true { if true { if true { if true { if true { if true { if true { if true {
+ if true { if true { if true { if true { if true { if true { if true { if true {
+ if true { if true { if true { if true { if true { if true { if true { if true {
+ if true { if true { if true { if true { if true { if true {
+ if
+ anyof ( anyof ( anyof ( anyof ( anyof ( anyof ( anyof ( anyof (
+ anyof ( anyof ( anyof ( anyof ( anyof ( anyof ( anyof ( anyof (
+ anyof ( anyof ( anyof ( anyof ( anyof ( anyof ( anyof ( anyof (
+ anyof ( anyof ( anyof ( anyof ( anyof ( anyof ( anyof ( anyof (
+ anyof ( anyof ( anyof ( anyof ( anyof ( anyof ( anyof ( anyof (
+ true
+ ))))))))
+ ))))))))
+ ))))))))
+ ))))))))
+ ))))))))
+ {
+ stop;
+ }
+ } } } } } }
+ } } } } } } } }
+ } } } } } } } }
+} } } } } } } }
+
+# Deepest block and too deep test nesting (1)
+if true { if true { if true { if true { if true { if true { if true { if true {
+ if true { if true { if true { if true { if true { if true { if true { if true {
+ if true { if true { if true { if true { if true { if true { if true { if true {
+ if true { if true { if true { if true { if true { if true {
+ if
+ not not not not not not not not
+ not not not not not not not not
+ not not not not not not not not
+ not not not not not not not not
+ not not not not not not not not false
+ {
+ stop;
+ }
+ } } } } } }
+ } } } } } } } }
+ } } } } } } } }
+} } } } } } } }
+
+
+# Garbage command; test wether previous errors were resolved (2)
+frop $$$$;
+
+
diff --git a/pigeonhole/tests/compile/errors/require.sieve b/pigeonhole/tests/compile/errors/require.sieve
new file mode 100644
index 0000000..ecbd7a2
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/require.sieve
@@ -0,0 +1,42 @@
+/*
+ * Require errors
+ *
+ * Total errors: 11 (+1 = 12)
+ */
+
+# Not an error
+require "fileinto";
+
+# Missing argument
+require;
+
+# Too many arguments
+require "fileinto" "vacation";
+
+# Invalid argument
+require 45;
+
+# Invalid extensions (3 errors)
+require ["_frop", "_friep", "_frml"];
+
+# Core commands required
+require ["redirect", "keep", "discard"];
+
+# Invalid arguments
+require "dovecot.test" true;
+
+# Invalid extension
+require "_frop";
+
+# Spurious command block
+require "fileinto" {
+ keep;
+}
+
+# Nested require
+if true {
+ require "relional";
+}
+
+# Require after other command than require
+require "copy";
diff --git a/pigeonhole/tests/compile/errors/size.sieve b/pigeonhole/tests/compile/errors/size.sieve
new file mode 100644
index 0000000..14dbee5
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/size.sieve
@@ -0,0 +1,47 @@
+/*
+ * Size test errors
+ *
+ * Total errors: 6 (+1 = 7)
+ */
+
+# Used as command (1)
+size :under 23;
+
+# Missing argument (2)
+if size {
+}
+
+# Missing :over/:under (3)
+if size 45 {
+ discard;
+}
+
+# No error
+if size :over 34K {
+ stop;
+}
+
+# No error
+if size :under 34M {
+ stop;
+}
+
+# Conflicting tags (4)
+if size :under :over 34 {
+ keep;
+}
+
+# Duplicate tags (5)
+if size :over :over 45M {
+ stop;
+}
+
+# Wrong argument order (6)
+if size 34M :over {
+ stop;
+}
+
+# No error; but worthy of a warning
+if size :under 0 {
+ stop;
+}
diff --git a/pigeonhole/tests/compile/errors/stop.sieve b/pigeonhole/tests/compile/errors/stop.sieve
new file mode 100644
index 0000000..75a3d76
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/stop.sieve
@@ -0,0 +1,33 @@
+/*
+ * Stop command errors
+ *
+ * Total errors: 7 (+1 = 8)
+ */
+
+# Spurious string argument
+stop "frop";
+
+# Spurious number argument
+stop 13;
+
+# Spurious string list argument
+stop [ "frop", "frop" ];
+
+# Spurious test
+stop true;
+
+# Spurious test list
+stop ( true, false );
+
+# Spurious command block
+stop {
+ keep;
+}
+
+# Spurious argument and test
+stop "frop" true {
+ stop;
+}
+
+# Not an error
+stop;
diff --git a/pigeonhole/tests/compile/errors/tag.sieve b/pigeonhole/tests/compile/errors/tag.sieve
new file mode 100644
index 0000000..7fa65e9
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/tag.sieve
@@ -0,0 +1,16 @@
+/*
+ * Tag errors
+ *
+ * Total errors: 2 (+1 = 3)
+ */
+
+# Unknown tag (1)
+if envelope :isnot :comparator "i;ascii-casemap" :localpart "From" "nico" {
+ discard;
+}
+
+# Spurious tag (1)
+if true :comparator "i;ascii-numeric" {
+ keep;
+}
+
diff --git a/pigeonhole/tests/compile/errors/typos.sieve b/pigeonhole/tests/compile/errors/typos.sieve
new file mode 100644
index 0000000..3d65b26
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/typos.sieve
@@ -0,0 +1,29 @@
+/*
+ * This test is primarily meant to check the compiler's handling of typos
+ * at various locations.
+ */
+
+require "fileinto";
+
+/*
+ * Missing semicolon
+ */
+
+fileinto "frop"
+keep;
+
+/* Other situations */
+
+fileinto "frup"
+true;
+
+fileinto "friep"
+snot;
+
+/*
+ * Forgot tag colon
+ */
+
+if address matches "from" "*frop*" {
+ stop;
+}
diff --git a/pigeonhole/tests/compile/errors/unsupported.sieve b/pigeonhole/tests/compile/errors/unsupported.sieve
new file mode 100644
index 0000000..9943f7b
--- /dev/null
+++ b/pigeonhole/tests/compile/errors/unsupported.sieve
@@ -0,0 +1,30 @@
+/*
+ * Handling of unsupported language features.
+ *
+ * Total errors: 3 (+1 = 4)
+ */
+
+require "variables";
+require "include";
+require "regex";
+
+/*
+ * Unsupported use of variables
+ */
+
+/* Comparator argument */
+
+set "comp" "i;ascii-numeric";
+
+if address :comparator "${comp}" "from" "stephan@example.org" {
+ stop;
+}
+
+/* Included script */
+
+set "script" "blacklist";
+
+include "${blacklist}";
+
+
+
diff --git a/pigeonhole/tests/compile/recover.svtest b/pigeonhole/tests/compile/recover.svtest
new file mode 100644
index 0000000..9c24c11
--- /dev/null
+++ b/pigeonhole/tests/compile/recover.svtest
@@ -0,0 +1,50 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Test parser's recover capability
+ */
+
+/*
+ * Commands
+ */
+
+/* Missing semicolon */
+
+test "Missing semicolons" {
+ if test_script_compile "recover/commands-semicolon.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/* End of block recovery*/
+
+test "Missing semicolon at end of block" {
+ if test_script_compile "recover/commands-endblock.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "4" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Tests
+ */
+
+test "Spurious comma at end of test list" {
+ if test_script_compile "recover/tests-endcomma.sieve" {
+ test_fail "compile should have failed.";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
diff --git a/pigeonhole/tests/compile/recover/commands-endblock.sieve b/pigeonhole/tests/compile/recover/commands-endblock.sieve
new file mode 100644
index 0000000..c06e218
--- /dev/null
+++ b/pigeonhole/tests/compile/recover/commands-endblock.sieve
@@ -0,0 +1,27 @@
+if true {
+ if true {
+ # Missing semicolon
+ keep
+ }
+}
+
+if true {
+ # Erroneous syntax
+ keep,
+ keep
+}
+
+if true {
+ if anyof(true,true,false) {
+ keep;
+ }
+}
+
+if true {
+ if anyof(true,true,false) {
+ keep;
+ # Missing semicolon
+ discard
+ }
+}
+
diff --git a/pigeonhole/tests/compile/recover/commands-semicolon.sieve b/pigeonhole/tests/compile/recover/commands-semicolon.sieve
new file mode 100644
index 0000000..effb389
--- /dev/null
+++ b/pigeonhole/tests/compile/recover/commands-semicolon.sieve
@@ -0,0 +1,16 @@
+
+keep;
+
+discard;
+
+# Missing semicolon
+keep
+
+redirect "frop@nl.example.com";
+
+discard;
+
+# Missing semicolon
+keep
+
+redirect "frml@nl.example.com";
diff --git a/pigeonhole/tests/compile/recover/tests-endcomma.sieve b/pigeonhole/tests/compile/recover/tests-endcomma.sieve
new file mode 100644
index 0000000..54c93ec
--- /dev/null
+++ b/pigeonhole/tests/compile/recover/tests-endcomma.sieve
@@ -0,0 +1,17 @@
+if true {
+ if true {
+ # Spurious comma
+ if anyof(true,true,true,) {
+ }
+ }
+}
+
+if true {
+ if anyof(true,true) {
+ # Spurious comma
+ if anyof(true,true,true,) {
+ if anyof(true,true,true) {
+ }
+ }
+ }
+}
diff --git a/pigeonhole/tests/compile/redirect.sieve b/pigeonhole/tests/compile/redirect.sieve
new file mode 100644
index 0000000..fb9f23d
--- /dev/null
+++ b/pigeonhole/tests/compile/redirect.sieve
@@ -0,0 +1,23 @@
+# Test various white space occurrences
+redirect "stephan@example.org";
+redirect " stephan@example.org";
+redirect "stephan @example.org";
+redirect "stephan@ example.org";
+redirect "stephan@example.org ";
+redirect " stephan @ example.org ";
+redirect "Stephan Bosch<stephan@example.org>";
+redirect " Stephan Bosch<stephan@example.org>";
+redirect "Stephan Bosch <stephan@example.org>";
+redirect "Stephan Bosch< stephan@example.org>";
+redirect "Stephan Bosch<stephan @example.org>";
+redirect "Stephan Bosch<stephan@ example.org>";
+redirect "Stephan Bosch<stephan@example.org >";
+redirect "Stephan Bosch<stephan@example.org> ";
+redirect " Stephan Bosch < stephan @ example.org > ";
+
+# Test address syntax
+redirect "\"Stephan Bosch\"@example.org";
+redirect "Stephan.Bosch@eXamPle.oRg";
+redirect "Stephan.Bosch@example.org";
+redirect "Stephan Bosch <stephan@example.org>";
+
diff --git a/pigeonhole/tests/compile/trivial.sieve b/pigeonhole/tests/compile/trivial.sieve
new file mode 100644
index 0000000..a3dcbc1
--- /dev/null
+++ b/pigeonhole/tests/compile/trivial.sieve
@@ -0,0 +1,17 @@
+# Commands must be case-insensitive
+keep;
+Keep;
+KEEP;
+discard;
+DisCaRD;
+
+# Tags must be case-insensitive
+if size :UNDER 34 {
+}
+
+if header :Is "from" "tukker@example.com" {
+}
+
+# Numbers must be case-insensitive
+if anyof( size :UNDER 34m, size :oVeR 50M ) {
+}
diff --git a/pigeonhole/tests/compile/warnings.svtest b/pigeonhole/tests/compile/warnings.svtest
new file mode 100644
index 0000000..8261551
--- /dev/null
+++ b/pigeonhole/tests/compile/warnings.svtest
@@ -0,0 +1,8 @@
+require "vnd.dovecot.testsuite";
+
+test "EOF Warnings" {
+ if not test_script_compile "warnings/eof.sieve" {
+ test_fail "compile should have succeeded.";
+ }
+}
+
diff --git a/pigeonhole/tests/compile/warnings/eof.sieve b/pigeonhole/tests/compile/warnings/eof.sieve
new file mode 100644
index 0000000..cf906dc
--- /dev/null
+++ b/pigeonhole/tests/compile/warnings/eof.sieve
@@ -0,0 +1,2 @@
+keep;
+# Final comment without newline
diff --git a/pigeonhole/tests/compile/warnings/invalid-headers.sieve b/pigeonhole/tests/compile/warnings/invalid-headers.sieve
new file mode 100644
index 0000000..a6b12a8
--- /dev/null
+++ b/pigeonhole/tests/compile/warnings/invalid-headers.sieve
@@ -0,0 +1,14 @@
+# Header test
+if header "from:" "frop@example.org" {
+ stop;
+}
+
+# Address test
+if address "from:" "frop@example.org" {
+ stop;
+}
+
+# Exists test
+if exists "from:" {
+ stop;
+}
diff --git a/pigeonhole/tests/control-if.svtest b/pigeonhole/tests/control-if.svtest
new file mode 100644
index 0000000..e11de64
--- /dev/null
+++ b/pigeonhole/tests/control-if.svtest
@@ -0,0 +1,292 @@
+require "vnd.dovecot.testsuite";
+
+/*
+ * ## RFC 5228, Section 3.1. Control if (page 21) ##
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: test@dovecot.example.net
+Cc: friep@example.com
+Subject: Test
+
+Test!
+.
+;
+
+/*
+ * Basic functionality
+ */
+
+/* "The semantics are similar to those of any of the many other
+ * programming languages these control structures appear in. When the
+ * interpreter sees an "if", it evaluates the test associated with it.
+ * If the test is true, it executes the block associated with it.
+ *
+ * If the test of the "if" is false, it evaluates the test of the first
+ * "elsif" (if any). If the test of "elsif" is true, it runs the
+ * elsif's block. An elsif may be followed by an elsif, in which case,
+ * the interpreter repeats this process until it runs out of elsifs.
+ *
+ * When the interpreter runs out of elsifs, there may be an "else" case.
+ * If there is, and none of the if or elsif tests were true, the
+ * interpreter runs the else's block.
+ *
+ * This provides a way of performing exactly one of the blocks in the
+ * chain.
+ * "
+ */
+
+/*
+ * TEST: Basic functionality: if true/false
+ */
+
+test "Basic functionality: if true/false" {
+ /* Static */
+ if true {
+ /* Correct */
+ } else {
+ test_fail "executed wrong alternative for static true";
+ }
+
+ if false {
+ test_fail "executed wrong alternative for static false";
+ } else {
+ /* Correct */
+ }
+
+ /* Dynamic */
+ if exists "to" {
+ /* Correct */
+ } else {
+ test_fail "executed wrong alternative for dynamic true";
+ }
+
+ if exists "flierp" {
+ test_fail "executed wrong alternative for dynamic false";
+ } else {
+ /* Correct */
+ }
+}
+
+/*
+ * TEST: Basic functionality: if not true/false
+ */
+
+test "Basic functionality: if not true/false" {
+ /* Static */
+ if not true {
+ test_fail "executed wrong alternative for static not true";
+ } else {
+ /* Correct */
+ }
+
+ if not false {
+ /* Correct */
+ } else {
+ test_fail "executed wrong alternative for static not false";
+ }
+
+ /* Dynamic */
+ if not exists "to" {
+ test_fail "executed wrong alternative for dynamic not true";
+ } else {
+ /* Correct */
+ }
+
+ if not exists "flierp" {
+ /* Correct */
+ } else {
+ test_fail "executed wrong alternative for dynamic not false";
+ }
+}
+
+/*
+ * TEST: Basic functionality: elseif true/false
+ */
+
+test "Basic functionality: elseif true/false" {
+ /* Static */
+ if true {
+ /* Correct */
+ } elsif true {
+ test_fail "executed wrong alternative for static true-true (elsif)";
+ } else {
+ test_fail "executed wrong alternative for static true-true (else)";
+ }
+
+ if true {
+ /* Correct */
+ } elsif false {
+ test_fail "executed wrong alternative for static true-false (elsif)";
+ } else {
+ test_fail "executed wrong alternative for static true-false (else)";
+ }
+
+ if false {
+ test_fail "executed wrong alternative for static false-true (if)";
+ } elsif true {
+ /* Correct */
+ } else {
+ test_fail "executed wrong alternative for static false-false (else)";
+ }
+
+ if false {
+ test_fail "executed wrong alternative for static false-false (if)";
+ } elsif false {
+ test_fail "executed wrong alternative for static false-false (elsif)";
+ } else {
+ /* Correct */
+ }
+
+ /* Dynamic */
+ if address :is "from" "stephan@example.org" {
+ /* Correct */
+ } elsif address :contains "from" "stephan" {
+ test_fail "executed wrong alternative for dynamic true-true (elsif)";
+ } else {
+ test_fail "executed wrong alternative for dynamic true-true (else)";
+ }
+
+ if address :is "from" "stephan@example.org" {
+ /* Correct */
+ } elsif address :is "from" "frop@example.com" {
+ test_fail "executed wrong alternative for dynamic true-false (elsif)";
+ } else {
+ test_fail "executed wrong alternative for dynamic true-false (else)";
+ }
+
+ if address :is "from" "tss@example.net" {
+ test_fail "executed wrong alternative for dynamic false-true (if)";
+ } elsif address :is "from" "stephan@example.org" {
+ /* Correct */
+ } else {
+ test_fail "executed wrong alternative for dynamic false-true(else)";
+ }
+
+ if address :is "from" "tss@example.net" {
+ test_fail "executed wrong alternative for dynamic false-false (if)";
+ } elsif address :is "to" "stephan@example.org" {
+ test_fail "executed wrong alternative for dynamic false-false (elsif)";
+ } else {
+ /* Correct */
+ }
+
+ /* Static/Dynamic */
+
+ if true {
+ /* Correct */
+ } elsif address :contains "from" "stephan" {
+ test_fail "executed wrong alternative for first-static true-true (elsif)";
+ } else {
+ test_fail "executed wrong alternative for first-static true-true (else)";
+ }
+
+ if address :is "from" "stephan@example.org" {
+ /* Correct */
+ } elsif true {
+ test_fail "executed wrong alternative for second-static true-true (elsif)";
+ } else {
+ test_fail "executed wrong alternative for second-static true-true (else)";
+ }
+
+ if true {
+ /* Correct */
+ } elsif address :is "from" "frop@example.com" {
+ test_fail "executed wrong alternative for first-static true-false (elsif)";
+ } else {
+ test_fail "executed wrong alternative for first-static true-false (else)";
+ }
+
+ if address :is "from" "stephan@example.org" {
+ /* Correct */
+ } elsif false {
+ test_fail "executed wrong alternative for second-static true-false (elsif)";
+ } else {
+ test_fail "executed wrong alternative for second-static true-false (else)";
+ }
+
+ if false {
+ test_fail "executed wrong alternative for first-static false-true (if)";
+ } elsif address :is "from" "stephan@example.org" {
+ /* Correct */
+ } else {
+ test_fail "executed wrong alternative for first-static false-true(else)";
+ }
+
+ if address :is "from" "tss@example.net" {
+ test_fail "executed wrong alternative for second-static false-true (if)";
+ } elsif true {
+ /* Correct */
+ } else {
+ test_fail "executed wrong alternative for second-static false-true(else)";
+ }
+
+ if false {
+ test_fail "executed wrong alternative for first-static false-false (if)";
+ } elsif address :is "to" "stephan@example.org" {
+ test_fail "executed wrong alternative for first-static false-false (elsif)";
+ } else {
+ /* Correct */
+ }
+
+ if address :is "from" "tss@example.net" {
+ test_fail "executed wrong alternative for second-static false-false (if)";
+ } elsif false {
+ test_fail "executed wrong alternative for second-static false-false (elsif)";
+ } else {
+ /* Correct */
+ }
+}
+
+/*
+ * TEST: Basic functionality: nesting
+ */
+
+test "Basic functionality: nesting" {
+ /* Static */
+ if true {
+ if true {
+ if false {
+ test_fail "chose wrong static outcome: true->true->false";
+ } else {
+ /* Correct */
+ }
+ } else {
+ test_fail "chose wrong static outcome: true->false";
+ }
+ } elsif true {
+ if false {
+ test_fail "chose wrong static outcome: false->true->false";
+ } elsif true {
+ test_fail "chose wrong static outcome: false->true->true";
+ }
+ } else {
+ test_fail "chose wrong static outcome: false->false";
+ }
+
+ /* Dynamic */
+
+ if exists "to" {
+ if exists "from" {
+ if exists "friep" {
+ test_fail "chose wrong dynamic outcome: true->true->false";
+ } else {
+ /* Correct */
+ }
+ } else {
+ test_fail "chose wrong dynamic outcome: true->false";
+ }
+ } elsif exists "cc" {
+ if exists "frop" {
+ test_fail "chose wrong dynamic outcome: false->true->false";
+ } elsif exists "from" {
+ test_fail "chose wrong dynamic outcome: false->true->true";
+ }
+ } else {
+ test_fail "chose wrong dynamic outcome: false->false";
+ }
+}
+
+
+
diff --git a/pigeonhole/tests/control-stop.svtest b/pigeonhole/tests/control-stop.svtest
new file mode 100644
index 0000000..b49199d
--- /dev/null
+++ b/pigeonhole/tests/control-stop.svtest
@@ -0,0 +1,29 @@
+require "vnd.dovecot.testsuite";
+
+/*
+ * ## RFC 5228, Section 3.3. Control stop (page 22) ##
+ */
+
+/*
+ * TEST: End processing
+ */
+
+/* "The "stop" action ends all processing.
+ * "
+ */
+
+test "End processing" {
+ stop;
+
+ test_fail "continued after stop";
+}
+
+/*
+ * TEST: Implicit keep
+ */
+
+/* "If the implicit keep has not been cancelled, then it is taken.
+ * "
+ */
+
+/* FIXME */
diff --git a/pigeonhole/tests/deprecated/imapflags/errors.svtest b/pigeonhole/tests/deprecated/imapflags/errors.svtest
new file mode 100644
index 0000000..a9d9cde
--- /dev/null
+++ b/pigeonhole/tests/deprecated/imapflags/errors.svtest
@@ -0,0 +1,24 @@
+require "vnd.dovecot.testsuite";
+
+require "comparator-i;ascii-numeric";
+require "relational";
+
+test "Deprecated imapflags extension used with imap4flags" {
+ if test_script_compile "errors/conflict.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "2" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Deprecated imapflags extension used with imap4flags (ihave)" {
+ if test_script_compile "errors/conflict-ihave.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
diff --git a/pigeonhole/tests/deprecated/imapflags/errors/conflict-ihave.sieve b/pigeonhole/tests/deprecated/imapflags/errors/conflict-ihave.sieve
new file mode 100644
index 0000000..e924923
--- /dev/null
+++ b/pigeonhole/tests/deprecated/imapflags/errors/conflict-ihave.sieve
@@ -0,0 +1,6 @@
+require "imap4flags";
+require "ihave";
+
+if ihave "imapflags" {
+ addflags "Frop";
+}
diff --git a/pigeonhole/tests/deprecated/imapflags/errors/conflict.sieve b/pigeonhole/tests/deprecated/imapflags/errors/conflict.sieve
new file mode 100644
index 0000000..1b18a42
--- /dev/null
+++ b/pigeonhole/tests/deprecated/imapflags/errors/conflict.sieve
@@ -0,0 +1,4 @@
+require "imapflags";
+require "imap4flags";
+
+addflag "\\flagged";
diff --git a/pigeonhole/tests/deprecated/imapflags/execute.svtest b/pigeonhole/tests/deprecated/imapflags/execute.svtest
new file mode 100644
index 0000000..ea6657b
--- /dev/null
+++ b/pigeonhole/tests/deprecated/imapflags/execute.svtest
@@ -0,0 +1,92 @@
+require "vnd.dovecot.testsuite";
+require "fileinto";
+require "imap4flags";
+require "relational";
+require "comparator-i;ascii-numeric";
+require "mailbox";
+
+test_set "message" text:
+From: Henry von Flockenstoffen <henry@example.com>
+To: Dieter von Ausburg <dieter@example.com>
+Subject: Test message.
+
+Test message.
+.
+;
+
+test "Mark / Unmark" {
+ if not test_script_compile "execute/mark.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script execute failed";
+ }
+
+ if not test_result_execute {
+ test_fail "failed to execute first result";
+ }
+
+ test_result_reset;
+
+ test_message :folder "Marked" 0;
+
+ if not hasflag "\\flagged" {
+ test_fail "message not marked";
+ }
+
+ test_result_reset;
+
+ test_message :folder "Unmarked" 0;
+
+ if hasflag "\\flagged" {
+ test_fail "message not unmarked";
+ }
+}
+
+test_result_reset;
+test "Setflag / Addflag / Removeflag" {
+ if not test_script_compile "execute/flags.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script execute failed";
+ }
+
+ if not test_result_execute {
+ test_fail "failed to execute first result";
+ }
+
+ test_result_reset;
+
+ test_message :folder "Set" 0;
+
+ if not hasflag "\\draft" {
+ test_fail "flag not set";
+ }
+
+ test_result_reset;
+
+ test_message :folder "Add" 0;
+
+ if not hasflag "\\draft" {
+ test_fail "flag not retained";
+ }
+
+ if not hasflag "\\flagged" {
+ test_fail "flag not added";
+ }
+
+ test_result_reset;
+
+ test_message :folder "Remove" 0;
+
+ if not hasflag "\\flagged" {
+ test_fail "flag not retained";
+ }
+
+ if hasflag "\\draft" {
+ test_fail "flag not removed";
+ }
+}
diff --git a/pigeonhole/tests/deprecated/imapflags/execute/flags.sieve b/pigeonhole/tests/deprecated/imapflags/execute/flags.sieve
new file mode 100644
index 0000000..ba68b44
--- /dev/null
+++ b/pigeonhole/tests/deprecated/imapflags/execute/flags.sieve
@@ -0,0 +1,12 @@
+require "imapflags";
+require "fileinto";
+require "mailbox";
+
+setflag "\\draft";
+fileinto :create "Set";
+
+addflag "\\flagged";
+fileinto :create "Add";
+
+removeflag "\\draft";
+fileinto :create "Remove";
diff --git a/pigeonhole/tests/deprecated/imapflags/execute/mark.sieve b/pigeonhole/tests/deprecated/imapflags/execute/mark.sieve
new file mode 100644
index 0000000..3216ca4
--- /dev/null
+++ b/pigeonhole/tests/deprecated/imapflags/execute/mark.sieve
@@ -0,0 +1,11 @@
+require "imapflags";
+require "fileinto";
+require "mailbox";
+
+mark;
+
+fileinto :create "Marked";
+
+unmark;
+
+fileinto :create "Unmarked";
diff --git a/pigeonhole/tests/deprecated/notify/basic.svtest b/pigeonhole/tests/deprecated/notify/basic.svtest
new file mode 100644
index 0000000..974f8ca
--- /dev/null
+++ b/pigeonhole/tests/deprecated/notify/basic.svtest
@@ -0,0 +1,59 @@
+require "vnd.dovecot.testsuite";
+require "notify";
+require "body";
+
+test "Execute" {
+ /* Test to catch runtime segfaults */
+ notify
+ :message "This is probably very important"
+ :low
+ :method "mailto"
+ :options ["stephan@example.com", "stephan@example.org"];
+
+ if not test_result_execute {
+ test_fail "Execute failed";
+ }
+}
+
+test_result_reset;
+
+test_set "message" text:
+To: user@example.com
+From: stephan@example.org
+Subject: Mail
+
+Test!
+.
+;
+
+test "Substitutions" {
+ notify
+ :message "$from$: $subject$"
+ :options "stephan@example.com";
+ if not test_result_execute {
+ test_fail "Execute failed";
+ }
+ test_message :smtp 0;
+ if not body :contains "stephan@example.org: Mail" {
+ test_fail "Substitution failed";
+ }
+}
+
+test_result_reset;
+
+test_set "message" text:
+To: user@example.com
+
+Test!
+.
+;
+
+test "Empty substitutions" {
+ notify
+ :message "$from$: $subject$"
+ :options "stephan@example.com";
+ if not test_result_execute {
+ test_fail "Execute failed";
+ }
+}
+
diff --git a/pigeonhole/tests/deprecated/notify/denotify.svtest b/pigeonhole/tests/deprecated/notify/denotify.svtest
new file mode 100644
index 0000000..9f752e1
--- /dev/null
+++ b/pigeonhole/tests/deprecated/notify/denotify.svtest
@@ -0,0 +1,279 @@
+require "vnd.dovecot.testsuite";
+require "notify";
+require "envelope";
+
+/*
+ * Denotify all
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "Denotify All" {
+ notify :options "timo@example.com";
+ notify :options "stephan@dovecot.example.net";
+ notify :options "postmaster@frop.example.org";
+ denotify;
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "no notifications should have been sent";
+ }
+}
+
+/*
+ * Denotify First
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "Denotify ID First" {
+ /* #1 */
+ notify :options "timo@example.com" :id "aap";
+
+ /* #2 */
+ notify :options "stephan@dovecot.example.net" :id "noot";
+
+ /* #3 */
+ notify :options "postmaster@frop.example.org" :id "mies";
+
+ denotify :is "aap";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "two notifications should have been sent (#2 missing)";
+ }
+
+ if not envelope "to" "stephan@dovecot.example.net" {
+ test_fail "message #2 unexpectedly missing from output";
+ }
+
+ if not test_message :smtp 1 {
+ test_fail "two notifications should have been sent (#3 missing)";
+ }
+
+ if not envelope "to" "postmaster@frop.example.org" {
+ test_fail "message #3 unexpectedly missing from output";
+ }
+
+ if test_message :smtp 2 {
+ test_fail "too many notifications sent";
+ }
+}
+
+/*
+ * Denotify Middle
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "Denotify ID Middle" {
+ /* #1 */
+ notify :options "timo@example.com" :id "aap";
+
+ /* #2 */
+ notify :options "stephan@dovecot.example.net" :id "noot";
+
+ /* #3 */
+ notify :options "postmaster@frop.example.org" :id "mies";
+
+ denotify :is "noot";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "two notifications should have been sent (#1 missing)";
+ }
+
+ if not envelope "to" "timo@example.com" {
+ test_fail "message #1 unexpectedly missing from output";
+ }
+
+ if not test_message :smtp 1 {
+ test_fail "two notifications should have been sent (#3 missing)";
+ }
+
+ if not envelope "to" "postmaster@frop.example.org" {
+ test_fail "message #3 unexpectedly missing from output";
+ }
+
+ if test_message :smtp 2 {
+ test_fail "too many notifications sent";
+ }
+}
+
+/*
+ * Denotify Last
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "Denotify ID Last" {
+ /* #1 */
+ notify :options "timo@example.com" :id "aap";
+
+ /* #2 */
+ notify :options "stephan@dovecot.example.net" :id "noot";
+
+ /* #3 */
+ notify :options "postmaster@frop.example.org" :id "mies";
+
+ denotify :is "mies";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "two notifications should have been sent (#1 missing)";
+ }
+
+ if not envelope "to" "timo@example.com" {
+ test_fail "message #1 unexpectedly missing from output";
+ }
+
+ if not test_message :smtp 1 {
+ test_fail "two notifications should have been sent (#2 missing)";
+ }
+
+ if not envelope "to" "stephan@dovecot.example.net" {
+ test_fail "message #2 unexpectedly missing from output";
+ }
+
+ if test_message :smtp 2 {
+ test_fail "too many notifications sent";
+ }
+}
+
+
+/*
+ * Denotify Matching
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "Denotify Matching" {
+ /* #1 */
+ notify :options "timo@example.com" :id "frop";
+
+ /* #2 */
+ notify :options "stephan@dovecot.example.net" :id "noot";
+
+ /* #3 */
+ notify :options "postmaster@frop.example.org" :id "friep";
+
+ denotify :matches "fr*";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "one notification should have been sent";
+ }
+
+ if not envelope "to" "stephan@dovecot.example.net" {
+ test_fail "message #2 unexpectedly missing from output";
+ }
+
+ if test_message :smtp 1 {
+ test_fail "too many notifications sent";
+ }
+}
+
+
+/*
+ * Denotify Matching
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "Denotify Matching Importance" {
+ /* #1 */
+ notify :options "timo@example.com" :id "frop" :low;
+
+ /* #2 */
+ notify :options "stephan@dovecot.example.net" :id "frml" :high;
+
+ /* #3 */
+ notify :options "postmaster@frop.example.org" :id "friep" :low;
+
+ denotify :matches "fr*" :low;
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "one notification should have been sent";
+ }
+
+ if not envelope "to" "stephan@dovecot.example.net" {
+ test_fail "message #2 unexpectedly missing from output";
+ }
+
+ if test_message :smtp 1 {
+ test_fail "too many notifications sent";
+ }
+}
+
+
diff --git a/pigeonhole/tests/deprecated/notify/errors.svtest b/pigeonhole/tests/deprecated/notify/errors.svtest
new file mode 100644
index 0000000..549cb6b
--- /dev/null
+++ b/pigeonhole/tests/deprecated/notify/errors.svtest
@@ -0,0 +1,33 @@
+require "vnd.dovecot.testsuite";
+require "comparator-i;ascii-numeric";
+require "relational";
+
+test "Invalid :options argument (FIXME: count only)" {
+ if test_script_compile "errors/options.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Deprecated notify extension used with enotify" {
+ if test_script_compile "errors/conflict.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Deprecated notify extension used with enotify (ihave)" {
+ if test_script_compile "errors/conflict-ihave.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
diff --git a/pigeonhole/tests/deprecated/notify/errors/conflict-ihave.sieve b/pigeonhole/tests/deprecated/notify/errors/conflict-ihave.sieve
new file mode 100644
index 0000000..9686f03
--- /dev/null
+++ b/pigeonhole/tests/deprecated/notify/errors/conflict-ihave.sieve
@@ -0,0 +1,8 @@
+require "enotify";
+require "ihave";
+
+# 1: Conflict
+if ihave "notify" {
+ # 2: Syntax wrong for enotify (and not skipped in compile)
+ notify :options "frop@frop.example.org";
+}
diff --git a/pigeonhole/tests/deprecated/notify/errors/conflict.sieve b/pigeonhole/tests/deprecated/notify/errors/conflict.sieve
new file mode 100644
index 0000000..46a6283
--- /dev/null
+++ b/pigeonhole/tests/deprecated/notify/errors/conflict.sieve
@@ -0,0 +1,4 @@
+require "enotify";
+require "notify";
+
+notify :options "frop@frop.example.org";
diff --git a/pigeonhole/tests/deprecated/notify/errors/options.sieve b/pigeonhole/tests/deprecated/notify/errors/options.sieve
new file mode 100644
index 0000000..c86fea0
--- /dev/null
+++ b/pigeonhole/tests/deprecated/notify/errors/options.sieve
@@ -0,0 +1,11 @@
+require "notify";
+
+# 1: empty option
+notify :options "";
+
+# 2: invalid address syntax
+notify :options "frop#frop.example.org";
+
+# Valid
+notify :options "frop@frop.example.org";
+
diff --git a/pigeonhole/tests/deprecated/notify/execute.svtest b/pigeonhole/tests/deprecated/notify/execute.svtest
new file mode 100644
index 0000000..90fde47
--- /dev/null
+++ b/pigeonhole/tests/deprecated/notify/execute.svtest
@@ -0,0 +1,25 @@
+require "vnd.dovecot.testsuite";
+require "relational";
+
+
+/*
+ * Execution testing (currently just meant to trigger any segfaults)
+ */
+
+test "Duplicate recipients" {
+ if not test_script_compile "execute/duplicates.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script execute failed";
+ }
+
+ if test_result_action :count "ne" "2" {
+ test_fail "second notify action was discarded entirely";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+}
diff --git a/pigeonhole/tests/deprecated/notify/execute/duplicates.sieve b/pigeonhole/tests/deprecated/notify/execute/duplicates.sieve
new file mode 100644
index 0000000..ef3fa5f
--- /dev/null
+++ b/pigeonhole/tests/deprecated/notify/execute/duplicates.sieve
@@ -0,0 +1,4 @@
+require "notify";
+
+notify :message "Incoming stupidity." :options ["stephan@example.org", "stephan@friep.example.com", "idiot@example.org"];
+notify :message "There it is." :options ["tss@example.net", "stephan@example.org", "idiot@example.org", "nico@frop.example.org", "stephan@friep.example.com"];
diff --git a/pigeonhole/tests/deprecated/notify/mailto.svtest b/pigeonhole/tests/deprecated/notify/mailto.svtest
new file mode 100644
index 0000000..1724339
--- /dev/null
+++ b/pigeonhole/tests/deprecated/notify/mailto.svtest
@@ -0,0 +1,317 @@
+require "vnd.dovecot.testsuite";
+
+require "notify";
+require "body";
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Simple test
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "Simple" {
+ notify :method "mailto" :options "stephan@example.org";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not header :matches "Auto-Submitted" "auto-generated*" {
+ test_fail "auto-submitted header set inappropriately";
+ }
+
+ if not exists "X-Sieve" {
+ test_fail "x-sieve header missing from outgoing message";
+ }
+}
+
+/*
+ * Multiple recipients
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "Multiple recipients" {
+ notify :options ["timo@example.com","stephan@dovecot.example.net","postmaster@frop.example.org"];
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not address :is "to" "timo@example.com" {
+ test_fail "first To address missing";
+ }
+
+ test_message :smtp 1;
+
+ if not address :is "to" "stephan@dovecot.example.net" {
+ test_fail "second To address missing";
+ }
+
+ if not header :matches "Auto-Submitted" "auto-generated*" {
+ test_fail "auto-submitted header not found for second message";
+ }
+
+ test_message :smtp 2;
+
+ if not address :is "to" "postmaster@frop.example.org" {
+ test_fail "third To address missing";
+ }
+
+ if not header :matches "Auto-Submitted" "auto-generated*" {
+ test_fail "auto-submitted header not found for third message";
+ }
+
+ if not address :count "eq" :comparator "i;ascii-numeric" "to" "3" {
+ test_fail "wrong number of recipients in To header";
+ }
+
+ if not address :count "eq" :comparator "i;ascii-numeric" "cc" "0" {
+ test_fail "too many recipients in Cc header";
+ }
+}
+
+/*
+ * Duplicate recipients
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "Duplicate recipients" {
+ notify :options ["timo@example.com", "stephan@dovecot.example.net", "stephan@dovecot.example.net"];
+ notify :options ["timo@example.com", "stephan@example.org"];
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 2;
+
+ if address "To" "stephan@dovecot.example.net" {
+ test_fail "duplicate recipient not removed from first message";
+ }
+
+ if address "To" "timo@example.com" {
+ test_fail "duplicate recipient not removed from second message";
+ }
+}
+
+/*
+ * Notifying on automated messages
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Auto-submitted: auto-notify
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "Notifying on automated messages" {
+ notify :options "stephan@example.org";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "notified of auto-submitted message";
+ }
+}
+
+test_result_reset;
+
+test_set "message" text:
+To: nico@frop.example.org
+From: stephan@example.org
+Subject: Test
+
+Test. Test
+Frop!
+.
+;
+
+test "Body; Singular Message" {
+ notify :low :id "frop" :options "stephan@example.org"
+ :message text:
+Received interesting message:
+
+$text$
+
+You have been notified.
+.
+;
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not body :raw :contains "Received interesting message" {
+ test_fail "notification has no heading";
+ }
+
+ if not body :raw :contains "You have been notified" {
+ test_fail "notification has no footer";
+ }
+
+ if not allof(
+ body :raw :contains "Test. Test",
+ body :raw :contains "Frop" ) {
+ test_fail "notification has no original message";
+ }
+}
+
+test_result_reset;
+
+test_set "message" text:
+To: nico@frop.example.org
+From: stephan@example.org
+Subject: Test
+
+Test. Test
+Frop!
+.
+;
+
+test "Body; $text[maxsize]$" {
+ notify :low :id "frop" :options "sirius@example.org"
+ :message text:
+Received interesting message:
+
+$text[5]$
+
+You have been notified.
+.
+;
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not body :raw :contains "Received interesting message" {
+ test_fail "notification has no heading";
+ }
+
+ if not body :raw :contains "You have been notified" {
+ test_fail "notification has no footer";
+ }
+
+ if anyof(
+ body :raw :contains "Test. Test",
+ body :raw :contains "Frop" ) {
+ test_fail "original message in notification is not truncated";
+ }
+
+ if not body :raw :contains "Test." {
+ test_fail "notification does not contain the required message";
+ }
+}
+
+test_result_reset;
+
+test_set "message" text:
+From: Whomever <whoever@example.com>
+To: Someone <someone@example.com>
+Date: Sat, 10 Oct 2009 00:30:04 +0200
+Subject: whatever
+Content-Type: multipart/mixed; boundary=outer
+
+This is a multi-part message in MIME format.
+
+--outer
+Content-Type: multipart/alternative; boundary=inner
+
+This is a nested multi-part message in MIME format.
+
+--inner
+Content-Type: application/sieve; charset="us-ascii"
+
+keep;
+
+--inner
+Content-Type: text/plain; charset="us-ascii"
+
+Friep!
+
+--inner--
+
+This is the end of the inner MIME multipart.
+
+--outer
+Content-Type: message/rfc822
+
+From: Someone Else
+Subject: hello request
+
+Please say Hello
+
+--outer--
+
+This is the end of the outer MIME multipart.
+.
+;
+
+test "Body; Multipart Message" {
+ notify :low :id "frop" :options "stephan@example.org"
+ :message text:
+Received interesting message:
+
+$text$
+
+You have been notified.
+.
+;
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not body :raw :contains "Friep!" {
+ test_fail "notification has incorrect content";
+ }
+}
+
+
+
diff --git a/pigeonhole/tests/execute/actions.svtest b/pigeonhole/tests/execute/actions.svtest
new file mode 100644
index 0000000..3f517fa
--- /dev/null
+++ b/pigeonhole/tests/execute/actions.svtest
@@ -0,0 +1,80 @@
+require "vnd.dovecot.testsuite";
+require "relational";
+require "comparator-i;ascii-numeric";
+
+test_set "message" text:
+To: nico@frop.example.org
+From: stephan@example.org
+Subject: Test
+
+Test.
+.
+;
+
+test_mailbox_create "INBOX.VB";
+test_mailbox_create "INBOX.backup";
+
+test "Fileinto" {
+ if not test_script_compile "actions/fileinto.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script run failed";
+ }
+
+ if not test_result_action :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of actions in result";
+ }
+
+ if not test_result_action :index 1 "store" {
+ test_fail "first action is not 'store'";
+ }
+
+ if not test_result_action :index 2 "store" {
+ test_fail "second action is not 'store'";
+ }
+
+ if not test_result_action :index 3 "keep" {
+ test_fail "third action is not 'keep'";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+}
+
+test "Redirect" {
+ if not test_script_compile "actions/redirect.sieve" {
+ test_fail "compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "execute failed";
+ }
+
+ if not test_result_action :count "eq" :comparator "i;ascii-numeric" "4" {
+ test_fail "wrong number of actions in result";
+ }
+
+ if not test_result_action :index 1 "redirect" {
+ test_fail "first action is not 'redirect'";
+ }
+
+ if not test_result_action :index 2 "keep" {
+ test_fail "second action is not 'keep'";
+ }
+
+ if not test_result_action :index 3 "redirect" {
+ test_fail "third action is not 'redirect'";
+ }
+
+ if not test_result_action :index 4 "redirect" {
+ test_fail "fourth action is not 'redirect'";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+}
+
diff --git a/pigeonhole/tests/execute/actions/fileinto.sieve b/pigeonhole/tests/execute/actions/fileinto.sieve
new file mode 100644
index 0000000..e9c133b
--- /dev/null
+++ b/pigeonhole/tests/execute/actions/fileinto.sieve
@@ -0,0 +1,17 @@
+require "fileinto";
+
+/* Three store actions */
+
+if address :contains "to" "frop.example" {
+ /* #1 */
+ fileinto "INBOX.VB";
+}
+
+/* #2 */
+fileinto "INBOX.backup";
+
+/* #3 */
+keep;
+
+/* Duplicate of keep */
+fileinto "INBOX";
diff --git a/pigeonhole/tests/execute/actions/redirect.sieve b/pigeonhole/tests/execute/actions/redirect.sieve
new file mode 100644
index 0000000..7adc23e
--- /dev/null
+++ b/pigeonhole/tests/execute/actions/redirect.sieve
@@ -0,0 +1,17 @@
+if address :contains "to" "frop.example" {
+ /* #1 */
+ redirect "stephan@example.com";
+
+ /* #2 */
+ keep;
+}
+
+/* #3 */
+redirect "stephan@example.org";
+
+/* #4 */
+redirect "nico@example.nl";
+
+/* Duplicates */
+redirect "Stephan Bosch <stephan@example.com>";
+keep;
diff --git a/pigeonhole/tests/execute/address-normalize.svtest b/pigeonhole/tests/execute/address-normalize.svtest
new file mode 100644
index 0000000..e826bde
--- /dev/null
+++ b/pigeonhole/tests/execute/address-normalize.svtest
@@ -0,0 +1,46 @@
+require "vnd.dovecot.testsuite";
+require "envelope";
+
+test_set "message" text:
+From: tss@example.net
+To: stephan@example.org
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "timo@example.net";
+test_set "envelope.to" "\"sirius\"@example.org";
+
+/*
+ * Mail address normalization - redirect
+ */
+
+test "Mail address normalization - redirect" {
+ redirect "\"S[r]us\"@example.net";
+ redirect "\"Sirius\"@example.net";
+ redirect "\"Stephan Bosch\" <\"S.Bosch\"@example.net>";
+
+ if not test_result_execute {
+ test_fail "failed to execute redirect";
+ }
+
+ test_message :smtp 0;
+
+ if not envelope :is "to" "\"S[r]us\"@example.net" {
+ test_fail "envelope recipient incorrect";
+ }
+
+ test_message :smtp 1;
+
+ if not envelope :is "to" "Sirius@example.net" {
+ test_fail "envelope recipient incorrect";
+ }
+
+ test_message :smtp 2;
+
+ if not envelope :is "to" "S.Bosch@example.net" {
+ test_fail "envelope recipient incorrect";
+ }
+}
diff --git a/pigeonhole/tests/execute/errors-cpu-limit.svtest b/pigeonhole/tests/execute/errors-cpu-limit.svtest
new file mode 100644
index 0000000..4a045bc
--- /dev/null
+++ b/pigeonhole/tests/execute/errors-cpu-limit.svtest
@@ -0,0 +1,363 @@
+require "vnd.dovecot.testsuite";
+
+test_config_set "sieve_max_cpu_time" "2";
+test_config_reload;
+
+test_set "message" text:
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary=
+
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+--
+.
+;
+
+test "CPU limit" {
+ if not test_script_compile "errors/cpu-limit.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if test_script_run {
+ test_fail "script execute should have failed";
+ }
+}
+
diff --git a/pigeonhole/tests/execute/errors.svtest b/pigeonhole/tests/execute/errors.svtest
new file mode 100644
index 0000000..45bc39c
--- /dev/null
+++ b/pigeonhole/tests/execute/errors.svtest
@@ -0,0 +1,152 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+require "fileinto";
+
+test "Action conflicts: reject <-> fileinto" {
+ if not test_script_compile "errors/conflict-reject-fileinto.sieve" {
+ test_fail "compile failed";
+ }
+
+ if test_script_run {
+ test_fail "execution should have failed";
+ }
+
+ if test_error :count "gt" :comparator "i;ascii-numeric" "1" {
+ test_fail "too many runtime errors reported";
+ }
+}
+
+test "Action conflicts: reject <-> keep" {
+ if not test_script_compile "errors/conflict-reject-keep.sieve" {
+ test_fail "compile failed";
+ }
+
+ if test_script_run {
+ test_fail "execution should have failed";
+ }
+
+ if test_error :count "gt" :comparator "i;ascii-numeric" "1" {
+ test_fail "too many runtime errors reported";
+ }
+}
+
+test "Action conflicts: reject <-> redirect" {
+ if not test_script_compile "errors/conflict-reject-redirect.sieve" {
+ test_fail "compile failed";
+ }
+
+ if test_script_run {
+ test_fail "execution should have failed";
+ }
+
+ if test_error :count "gt" :comparator "i;ascii-numeric" "1" {
+ test_fail "too many runtime errors reported";
+ }
+}
+
+test "Action limit" {
+ if not test_script_compile "errors/actions-limit.sieve" {
+ test_fail "compile failed";
+ }
+
+ if test_script_run {
+ test_fail "execution should have failed";
+ }
+
+ if test_error :count "gt" :comparator "i;ascii-numeric" "1" {
+ test_fail "too many runtime errors reported";
+ }
+
+ if not test_error :index 1 :contains "total number of actions exceeds policy limit"{
+ test_fail "unexpected error reported";
+ }
+}
+
+test "Redirect limit" {
+ if not test_script_compile "errors/redirect-limit.sieve" {
+ test_fail "compile failed";
+ }
+
+ if test_script_run {
+ test_fail "execution should have failed";
+ }
+
+ if test_error :count "gt" :comparator "i;ascii-numeric" "1" {
+ test_fail "too many runtime errors reported";
+ }
+
+ if not test_error :index 1 :contains "number of redirect actions exceeds policy limit"{
+ test_fail "unexpected error reported";
+ }
+}
+
+test "Fileinto missing folder" {
+ if not test_script_compile "errors/fileinto.sieve" {
+ test_fail "compile failed";
+ }
+
+ test_mailbox_create "INBOX";
+
+ if not test_script_run {
+ test_fail "execution failed";
+ }
+
+ if test_result_execute {
+ test_fail "execution of result should have failed";
+ }
+
+ if test_error :count "gt" :comparator "i;ascii-numeric" "1" {
+ test_fail "too many runtime errors reported";
+ }
+
+ if not allof (
+ test_error :index 1 :contains "failed to store into mailbox",
+ test_error :index 1 :contains "exist",
+ test_error :index 1 :contains "FROP") {
+ test_fail "unexpected error reported";
+ }
+}
+
+test "Fileinto invalid folder name" {
+ if not test_script_compile "errors/fileinto-invalid-name.sieve" {
+ test_fail "compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "execution failed";
+ }
+
+ if test_result_execute {
+ test_fail "execution of result should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "1" {
+ test_fail "wrong number of runtime errors reported";
+ }
+
+ if not allof (
+ test_error :index 1 :contains "failed to store into mailbox",
+ test_error :index 1 :contains "name") {
+ test_fail "unexpected error reported";
+ }
+}
+
+test "Fileinto bad UTF-8 in folder name" {
+ if not test_script_compile "errors/fileinto-bad-utf8.sieve" {
+ test_fail "compile failed";
+ }
+
+ if test_script_run {
+ test_fail "execution should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "1" {
+ test_fail "wrong number of runtime errors reported";
+ }
+
+ if not test_error :index 1 :contains "invalid folder name" {
+ test_fail "unexpected error reported";
+ }
+}
diff --git a/pigeonhole/tests/execute/errors/action-duplicates.sieve b/pigeonhole/tests/execute/errors/action-duplicates.sieve
new file mode 100644
index 0000000..6d5370d
--- /dev/null
+++ b/pigeonhole/tests/execute/errors/action-duplicates.sieve
@@ -0,0 +1,4 @@
+require "reject";
+
+reject "Message is not appreciated.";
+reject "No, really, it is not appreciated.";
diff --git a/pigeonhole/tests/execute/errors/actions-limit.sieve b/pigeonhole/tests/execute/errors/actions-limit.sieve
new file mode 100644
index 0000000..3ae33a3
--- /dev/null
+++ b/pigeonhole/tests/execute/errors/actions-limit.sieve
@@ -0,0 +1,35 @@
+require "fileinto";
+
+fileinto "box1";
+fileinto "box2";
+fileinto "box3";
+fileinto "box4";
+fileinto "box5";
+fileinto "box6";
+fileinto "box7";
+fileinto "box8";
+fileinto "box9";
+fileinto "box10";
+fileinto "box11";
+fileinto "box12";
+fileinto "box13";
+fileinto "box14";
+fileinto "box15";
+fileinto "box16";
+fileinto "box17";
+fileinto "box18";
+fileinto "box19";
+fileinto "box20";
+fileinto "box21";
+fileinto "box22";
+fileinto "box23";
+fileinto "box24";
+fileinto "box25";
+fileinto "box26";
+fileinto "box27";
+fileinto "box28";
+redirect "address1@example.com";
+redirect "address2@example.com";
+redirect "address3@example.com";
+redirect "address4@example.com";
+keep;
diff --git a/pigeonhole/tests/execute/errors/conflict-reject-fileinto.sieve b/pigeonhole/tests/execute/errors/conflict-reject-fileinto.sieve
new file mode 100644
index 0000000..85ef139
--- /dev/null
+++ b/pigeonhole/tests/execute/errors/conflict-reject-fileinto.sieve
@@ -0,0 +1,5 @@
+require "reject";
+require "fileinto";
+
+reject "No nonsense in my mailbox.";
+fileinto "Spam";
diff --git a/pigeonhole/tests/execute/errors/conflict-reject-keep.sieve b/pigeonhole/tests/execute/errors/conflict-reject-keep.sieve
new file mode 100644
index 0000000..569a4ac
--- /dev/null
+++ b/pigeonhole/tests/execute/errors/conflict-reject-keep.sieve
@@ -0,0 +1,4 @@
+require "reject";
+
+reject "I am not interested in your nonsense.";
+keep;
diff --git a/pigeonhole/tests/execute/errors/conflict-reject-redirect.sieve b/pigeonhole/tests/execute/errors/conflict-reject-redirect.sieve
new file mode 100644
index 0000000..d012269
--- /dev/null
+++ b/pigeonhole/tests/execute/errors/conflict-reject-redirect.sieve
@@ -0,0 +1,4 @@
+require "reject";
+
+reject "I am not interested in your nonsense.";
+redirect "frop@example.com";
diff --git a/pigeonhole/tests/execute/errors/cpu-limit.sieve b/pigeonhole/tests/execute/errors/cpu-limit.sieve
new file mode 100644
index 0000000..8532a4b
--- /dev/null
+++ b/pigeonhole/tests/execute/errors/cpu-limit.sieve
@@ -0,0 +1,145 @@
+require ["mime","foreverypart","fileinto", "variables", "regex"];
+
+# Here we create an inefficient regex with long compilation time
+set "my_exp" "^(((A)|(AB)|(ABC)|(ABCD)|(ABCDE)|(ABCDEF)|(ABCDEFG)|(ABCDEFGH)|(ABCDEFGHI)|(ABCDEFGHIJ)|(ABCDEFGHIJK)|(ABCDEFGHIJKL)|(ABCDEFGHIJKLM)|(ABCDEFGHIJKLMN)|(ABCDEFGHIJKLMNO)|(ABCDEFGHIJKLMNOP)|(ABCDEFGHIJKLMNOPQ)|(ABCDEFGHIJKLMNOPQR))?((B)|(BC)|(BCD)|(BCDE)|(BCDEF)|(BCDEFG)|(BCDEFGH)|(BCDEFGHI)|(BCDEFGHIJ)|(BCDEFGHIJK)|(BCDEFGHIJKL)|(BCDEFGHIJKLM)|(BCDEFGHIJKLMN)|(BCDEFGHIJKLMNO)|(BCDEFGHIJKLMNOP)|(BCDEFGHIJKLMNOPQ)|(BCDEFGHIJKLMNOPQR))?((C)|(CD)|(CDE)|(CDEF)|(CDEFG)|(CDEFGH)|(CDEFGHI)|(CDEFGHIJ)|(CDEFGHIJK)|(CDEFGHIJKL)|(CDEFGHIJKLM)|(CDEFGHIJKLMN)|(CDEFGHIJKLMNO)|(CDEFGHIJKLMNOP)|(CDEFGHIJKLMNOPQ)|(CDEFGHIJKLMNOPQR))?((D)|(DE)|(DEF)|(DEFG)|(DEFGH)|(DEFGHI)|(DEFGHIJ)|(DEFGHIJK)|(DEFGHIJKL)|(DEFGHIJKLM)|(DEFGHIJKLMN)|(DEFGHIJKLMNO)|(DEFGHIJKLMNOP)|(DEFGHIJKLMNOPQ)|(DEFGHIJKLMNOPQR))?((E)|(EF)|(EFG)|(EFGH)|(EFGHI)|(EFGHIJ)|(EFGHIJK)|(EFGHIJKL)|(EFGHIJKLM)|(EFGHIJKLMN)|(EFGHIJKLMNO)|(EFGHIJKLMNOP)|(EFGHIJKLMNOPQ)|(EFGHIJKLMNOPQR))?((F)|(FG)|(FGH)|(FGHI)|(FGHIJ)|(FGHIJK)|(FGHIJKL)|(FGHIJKLM)|(FGHIJKLMN)|(FGHIJKLMNO)|(FGHIJKLMNOP)|(FGHIJKLMNOPQ)|(FGHIJKLMNOPQR))?((G)|(GH)|(GHI)|(GHIJ)|(GHIJK)|(GHIJKL)|(GHIJKLM)|(GHIJKLMN)|(GHIJKLMNO)|(GHIJKLMNOP)|(GHIJKLMNOPQ)|(GHIJKLMNOPQR))?((H)|(HI)|(HIJ)|(HIJK)|(HIJKL)|(HIJKLM)|(HIJKLMN)|(HIJKLMNO)|(HIJKLMNOP)|(HIJKLMNOPQ)|(HIJKLMNOPQR))?((I)|(IJ)|(IJK)|(IJKL)|(IJKLM)|(IJKLMN)|(IJKLMNO)|(IJKLMNOP)|(IJKLMNOPQ)|(IJKLMNOPQR))?((J)|(JK)|(JKL)|(JKLM)|(JKLMN)|(JKLMNO)|(JKLMNOP)|(JKLMNOPQ)|(JKLMNOPQR))?((K)|(KL)|(KLM)|(KLMN)|(KLMNO)|(KLMNOP)|(KLMNOPQ)|(KLMNOPQR))?((L)|(LM)|(LMN)|(LMNO)|(LMNOP)|(LMNOPQ)|(LMNOPQR))?((M)|(MN)|(MNO)|(MNOP)|(MNOPQ)|(MNOPQR))?((N)|(NO)|(NOP)|(NOPQ)|(NOPQR))?((O)|(OP)|(OPQ)|(OPQR))?((P)|(PQ)|(PQR))?((Q)|(QR))?((R))?((R)|(RQ)|(RQP)|(RQPO)|(RQPON)|(RQPONM)|(RQPONML)|(RQPONMLK)|(RQPONMLKJ)|(RQPONMLKJI)|(RQPONMLKJIH)|(RQPONMLKJIHG)|(RQPONMLKJIHGF)|(RQPONMLKJIHGFE)|(RQPONMLKJIHGFED)|(RQPONMLKJIHGFEDC)|(RQPONMLKJIHGFEDCB)|(RQPONMLKJIHGFEDCBA))?((Q)|(QP)|(QPO)|(QPON)|(QPONM)|(QPONML)|(QPONMLK)|(QPONMLKJ)|(QPONMLKJI)|(QPONMLKJIH)|(QPONMLKJIHG)|(QPONMLKJIHGF)|(QPONMLKJIHGFE)|(QPONMLKJIHGFED)|(QPONMLKJIHGFEDC)|(QPONMLKJIHGFEDCB)|(QPONMLKJIHGFEDCBA))?((P)|(PO)|(PON)|(PONM)|(PONML)|(PONMLK)|(PONMLKJ)|(PONMLKJI)|(PONMLKJIH)|(PONMLKJIHG)|(PONMLKJIHGF)|(PONMLKJIHGFE)|(PONMLKJIHGFED)|(PONMLKJIHGFEDC)|(PONMLKJIHGFEDCB)|(PONMLKJIHGFEDCBA))?((O)|(ON)|(ONM)|(ONML)|(ONMLK)|(ONMLKJ)|(ONMLKJI)|(ONMLKJIH)|(ONMLKJIHG)|(ONMLKJIHGF)|(ONMLKJIHGFE)|(ONMLKJIHGFED)|(ONMLKJIHGFEDC)|(ONMLKJIHGFEDCB)|(ONMLKJIHGFEDCBA))?((N)|(NM)|(NML)|(NMLK)|(NMLKJ)|(NMLKJI)|(NMLKJIH)|(NMLKJIHG)|(NMLKJIHGF)|(NMLKJIHGFE)|(NMLKJIHGFED)|(NMLKJIHGFEDC)|(NMLKJIHGFEDCB)|(NMLKJIHGFEDCBA))?((M)|(ML)|(MLK)|(MLKJ)|(MLKJI)|(MLKJIH)|(MLKJIHG)|(MLKJIHGF)|(MLKJIHGFE)|(MLKJIHGFED)|(MLKJIHGFEDC)|(MLKJIHGFEDCB)|(MLKJIHGFEDCBA))?((L)|(LK)|(LKJ)|(LKJI)|(LKJIH)|(LKJIHG)|(LKJIHGF)|(LKJIHGFE)|(LKJIHGFED)|(LKJIHGFEDC)|(LKJIHGFEDCB)|(LKJIHGFEDCBA))?((K)|(KJ)|(KJI)|(KJIH)|(KJIHG)|(KJIHGF)|(KJIHGFE)|(KJIHGFED)|(KJIHGFEDC)|(KJIHGFEDCB)|(KJIHGFEDCBA))?((J)|(JI)|(JIH)|(JIHG)|(JIHGF)|(JIHGFE)|(JIHGFED)|(JIHGFEDC)|(JIHGFEDCB)|(JIHGFEDCBA))?((I)|(IH)|(IHG)|(IHGF)|(IHGFE)|(IHGFED)|(IHGFEDC)|(IHGFEDCB)|(IHGFEDCBA))?((H)|(HG)|(HGF)|(HGFE)|(HGFED)|(HGFEDC)|(HGFEDCB)|(HGFEDCBA))?((G)|(GF)|(GFE)|(GFED)|(GFEDC)|(GFEDCB)|(GFEDCBA))?((F)|(FE)|(FED)|(FEDC)|(FEDCB)|(FEDCBA))?((E)|(ED)|(EDC)|(EDCB)|(EDCBA))?((D)|(DC)|(DCB)|(DCBA))?((C)|(CB)|(CBA))?((B)|(BA))?((A))?)+$";
+set "a" "ABCDEFGHIJKLMNOPQR";
+set "b" "RQPONMLKJIHGFEDCBA";
+set "c" "${a}${b}${a}${b}${a}${b}${a}${b}";
+set "e" "${c}${c}${c}${c}${c}${c}${c}${c}";
+set "f" "${e}${e}${e}${e}${e}${e}${e}${e}";
+
+# We create a string on which this regex will spend enough time (around 200 ms)
+set "final" "${f}${f}${f}${f}${f}${f}${f}${f}${f}${f}${f}${f}${f}${f}@";
+
+# We repeat the throttling process for every mime part
+foreverypart {
+ # We use several if statements to multiply the cpu time consumed by one match
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+ if string :regex "${final}" "${my_exp}" { discard; }
+ if string :regex "${final}" "${my_exp}" { keep; }
+}
diff --git a/pigeonhole/tests/execute/errors/fileinto-bad-utf8.sieve b/pigeonhole/tests/execute/errors/fileinto-bad-utf8.sieve
new file mode 100644
index 0000000..3e57c92
--- /dev/null
+++ b/pigeonhole/tests/execute/errors/fileinto-bad-utf8.sieve
@@ -0,0 +1,7 @@
+require "fileinto";
+require "variables";
+require "encoded-character";
+
+set "mailbox" "${hex:ff}rop";
+fileinto "${mailbox}";
+
diff --git a/pigeonhole/tests/execute/errors/fileinto-invalid-name.sieve b/pigeonhole/tests/execute/errors/fileinto-invalid-name.sieve
new file mode 100644
index 0000000..871323e
--- /dev/null
+++ b/pigeonhole/tests/execute/errors/fileinto-invalid-name.sieve
@@ -0,0 +1,5 @@
+require "fileinto";
+require "mailbox";
+
+fileinto :create "foo//somedomain/org";
+
diff --git a/pigeonhole/tests/execute/errors/fileinto.sieve b/pigeonhole/tests/execute/errors/fileinto.sieve
new file mode 100644
index 0000000..185674c
--- /dev/null
+++ b/pigeonhole/tests/execute/errors/fileinto.sieve
@@ -0,0 +1,3 @@
+require "fileinto";
+
+fileinto "FROP";
diff --git a/pigeonhole/tests/execute/errors/redirect-limit.sieve b/pigeonhole/tests/execute/errors/redirect-limit.sieve
new file mode 100644
index 0000000..86cfda0
--- /dev/null
+++ b/pigeonhole/tests/execute/errors/redirect-limit.sieve
@@ -0,0 +1,5 @@
+redirect "address1@example.com";
+redirect "address2@example.com";
+redirect "address3@example.com";
+redirect "address4@example.com";
+redirect "address5@example.com";
diff --git a/pigeonhole/tests/execute/examples.svtest b/pigeonhole/tests/execute/examples.svtest
new file mode 100644
index 0000000..6143018
--- /dev/null
+++ b/pigeonhole/tests/execute/examples.svtest
@@ -0,0 +1,115 @@
+require "vnd.dovecot.testsuite";
+
+/* Compile and execute all example scripts to trigger
+ * any Segfaults. No message is set and no results are checked.
+ */
+
+test "Elvey example" {
+ if not test_script_compile "../../examples/elvey.sieve" {
+ test_fail "could not compile";
+ }
+
+ test_binary_save "elvey";
+ test_binary_load "elvey";
+
+ if not test_script_run { }
+}
+
+test "M. Johnson example" {
+ if not test_script_compile "../../examples/mjohnson.sieve" {
+ test_fail "could not compile";
+ }
+
+ test_binary_save "mjohnson";
+ test_binary_load "mjohnson";
+
+ if not test_script_run { }
+}
+
+test "RFC 3028 example" {
+ if not test_script_compile "../../examples/rfc3028.sieve" {
+ test_fail "could not compile";
+ }
+
+ test_binary_save "rfc3028";
+ test_binary_load "rfc3028";
+
+ if not test_script_run { }
+}
+
+test "Sieve examples" {
+ if not test_script_compile "../../examples/sieve_examples.sieve" {
+ test_fail "could not compile";
+ }
+
+ test_binary_save "sieve_examples";
+ test_binary_load "sieve_examples";
+
+ if not test_script_run { }
+}
+
+test "Vivil example" {
+ if not test_script_compile "../../examples/vivil.sieve" {
+ test_fail "could not compile";
+ }
+
+ test_binary_save "vivil";
+ test_binary_load "vivil";
+
+ if not test_script_run { }
+}
+
+test "Jerry example" {
+ if not test_script_compile "../../examples/jerry.sieve" {
+ test_fail "could not compile";
+ }
+
+ test_binary_save "jerry";
+ test_binary_load "jerry";
+
+ if not test_script_run { }
+}
+
+test "M. Klose example" {
+ if not test_script_compile "../../examples/mklose.sieve" {
+ test_fail "could not compile";
+ }
+
+ test_binary_save "mklose";
+ test_binary_load "mklose";
+
+ if not test_script_run { }
+}
+
+test "Sanjay example" {
+ if not test_script_compile "../../examples/sanjay.sieve" {
+ test_fail "could not compile";
+ }
+
+ test_binary_save "sanjay";
+ test_binary_load "sanjay";
+
+ if not test_script_run { }
+}
+
+test "Relational (RFC5231) example" {
+ if not test_script_compile "../../examples/relational.rfc5231.sieve" {
+ test_fail "could not compile";
+ }
+
+ test_binary_save "relational";
+ test_binary_load "relational";
+
+ if not test_script_run { }
+}
+
+test "Subaddress (RFC5233) example" {
+ if not test_script_compile "../../examples/subaddress.rfc5233.sieve" {
+ test_fail "could not compile";
+ }
+
+ test_binary_save "subaddress";
+ test_binary_load "subaddress";
+
+ if not test_script_run { }
+}
diff --git a/pigeonhole/tests/execute/mailstore.svtest b/pigeonhole/tests/execute/mailstore.svtest
new file mode 100644
index 0000000..d6cc220
--- /dev/null
+++ b/pigeonhole/tests/execute/mailstore.svtest
@@ -0,0 +1,84 @@
+require "vnd.dovecot.testsuite";
+require "fileinto";
+require "variables";
+require "mailbox";
+
+set "message1" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: First message
+
+Frop
+.
+;
+
+set "message2" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Second message
+
+Frop
+.
+;
+
+set "message3" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Third message
+
+Frop
+.
+;
+
+test "Duplicates" {
+ test_set "message" "${message1}";
+
+ fileinto :create "Folder";
+ fileinto :create "Folder";
+
+ if not test_result_execute {
+ test_fail "failed to execute first result";
+ }
+
+ test_result_reset;
+
+ test_set "message" "${message2}";
+
+ fileinto :create "Folder";
+ fileinto :create "Folder";
+
+ if not test_result_execute {
+ test_fail "failed to execute second result";
+ }
+
+ test_result_reset;
+
+ test_set "message" "${message3}";
+
+ fileinto :create "Folder";
+ fileinto :create "Folder";
+
+ if not test_result_execute {
+ test_fail "failed to execute third result";
+ }
+
+ test_message :folder "Folder" 0;
+
+ if not header :is "subject" "First message" {
+ test_fail "first message incorrect";
+ }
+
+ test_message :folder "Folder" 1;
+
+ if not header :is "subject" "Second message" {
+ test_fail "first message incorrect";
+ }
+
+ test_message :folder "Folder" 2;
+
+ if not header :is "subject" "Third message" {
+ test_fail "first message incorrect";
+ }
+}
+
+
diff --git a/pigeonhole/tests/execute/smtp.svtest b/pigeonhole/tests/execute/smtp.svtest
new file mode 100644
index 0000000..2c7d2e6
--- /dev/null
+++ b/pigeonhole/tests/execute/smtp.svtest
@@ -0,0 +1,449 @@
+require "vnd.dovecot.testsuite";
+require "envelope";
+
+test_set "message" text:
+From: stephan@example.org
+To: tss@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "timo@example.net";
+
+test "Redirect" {
+ redirect "cras@example.net";
+
+ if not test_result_execute {
+ test_fail "failed to execute redirect";
+ }
+
+ test_message :smtp 0;
+
+ if not address :is "to" "tss@example.net" {
+ test_fail "to address incorrect (strange forward)";
+ }
+
+ if not address :is "from" "stephan@example.org" {
+ test_fail "from address incorrect (strange forward)";
+ }
+
+ if not envelope :is "to" "cras@example.net" {
+ test_fail "envelope recipient incorrect";
+ }
+
+ if not envelope :is "from" "sirius@example.org" {
+ test_fail "envelope sender incorrect";
+ }
+
+ if not header :contains "x-sieve-redirected-from"
+ "timo@example.net" {
+ test_fail "x-sieve-redirected-from header is incorrect";
+ }
+}
+
+test_result_reset;
+test_set "message" text:
+From: stephan@example.org
+To: tss@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+test_set "envelope.from" "<>";
+test_set "envelope.to" "timo@example.net";
+
+test "Redirect from <>" {
+ redirect "cras@example.net";
+
+ if not test_result_execute {
+ test_fail "failed to execute redirect";
+ }
+
+ test_message :smtp 0;
+
+ if envelope :is "from" "sirius@example.org" {
+ test_fail "envelope sender incorrect (not changed)";
+ }
+
+ if not envelope :is "from" "" {
+ test_fail "envelope sender incorrect";
+ }
+
+ if not header :contains "x-sieve-redirected-from"
+ "timo@example.net" {
+ test_fail "x-sieve-redirected-from header is incorrect";
+ }
+}
+
+test_result_reset;
+test_set "message" text:
+From: stephan@example.org
+To: tss@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "timo@example.net";
+
+test_config_set "sieve_redirect_envelope_from" " recipient ";
+test_config_reload;
+
+test "Redirect from [recipient]" {
+ redirect "cras@example.net";
+
+ if not test_result_execute {
+ test_fail "failed to execute redirect";
+ }
+
+ test_message :smtp 0;
+
+ if envelope :is "from" "sirius@example.org" {
+ test_fail "envelope sender incorrect (not changed)";
+ }
+
+ if not envelope :is "from" "timo@example.net" {
+ test_fail "envelope sender incorrect";
+ }
+
+ if not header :contains "x-sieve-redirected-from"
+ "timo@example.net" {
+ test_fail "x-sieve-redirected-from header is incorrect";
+ }
+}
+
+test_result_reset;
+test_set "message" text:
+From: stephan@example.org
+To: tss@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "timo@example.net";
+test_set "envelope.orig_to" "tss@example.net";
+
+test_config_set "sieve_redirect_envelope_from" "orig_recipient ";
+test_config_reload;
+
+test "Redirect from [original recipient]" {
+ redirect "cras@example.net";
+
+ if not test_result_execute {
+ test_fail "failed to execute redirect";
+ }
+
+ test_message :smtp 0;
+
+ if envelope :is "from" "sirius@example.org" {
+ test_fail "envelope sender incorrect (not changed)";
+ }
+
+ if not envelope :is "from" "tss@example.net" {
+ test_fail "envelope sender incorrect";
+ }
+
+ if not header :contains "x-sieve-redirected-from"
+ "timo@example.net" {
+ test_fail "x-sieve-redirected-from header is incorrect";
+ }
+}
+
+test_result_reset;
+test_set "message" text:
+From: stephan@example.org
+To: tss@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "timo@example.net";
+test_set "envelope.orig_to" "tss@example.net";
+
+test_config_set "sieve_redirect_envelope_from" "<backscatter@example.net> ";
+test_config_reload;
+
+test "Redirect from [<explicit>]" {
+ redirect "cras@example.net";
+
+ if not test_result_execute {
+ test_fail "failed to execute redirect";
+ }
+
+ test_message :smtp 0;
+
+ if envelope :is "from" "sirius@example.org" {
+ test_fail "envelope sender incorrect (not changed)";
+ }
+
+ if not envelope :is "from" "backscatter@example.net" {
+ test_fail "envelope sender incorrect";
+ }
+
+ if not header :contains "x-sieve-redirected-from"
+ "timo@example.net" {
+ test_fail "x-sieve-redirected-from header is incorrect";
+ }
+}
+
+test_result_reset;
+test_set "message" text:
+From: stephan@example.org
+To: tss@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "timo@example.net";
+
+test_config_set "sieve_redirect_envelope_from" "<>";
+test_config_reload;
+
+test "Redirect from [<>]" {
+ redirect "cras@example.net";
+
+ if not test_result_execute {
+ test_fail "failed to execute redirect";
+ }
+
+ test_message :smtp 0;
+
+ if envelope :is "from" "sirius@example.org" {
+ test_fail "envelope sender incorrect (not changed)";
+ }
+
+ if not envelope :is "from" "" {
+ test_fail "envelope sender incorrect";
+ }
+
+ if not header :contains "x-sieve-redirected-from"
+ "timo@example.net" {
+ test_fail "x-sieve-redirected-from header is incorrect";
+ }
+}
+
+test_result_reset;
+test_set "message" text:
+From: stephan@example.org
+To: tss@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+test_set "envelope.from" "<>";
+test_set "envelope.to" "timo@example.net";
+test_set "envelope.orig_to" "tss@example.net";
+
+test_config_set "sieve_redirect_envelope_from" "<backscatter@example.net>";
+test_config_reload;
+
+test "Redirect from <> with [<explicit>]" {
+ redirect "cras@example.net";
+
+ if not test_result_execute {
+ test_fail "failed to execute redirect";
+ }
+
+ test_message :smtp 0;
+
+ if envelope :is "from" "backscatter@example.net" {
+ test_fail "envelope sender incorrect (erroneously changed)";
+ }
+
+ if not envelope :is "from" "" {
+ test_fail "envelope sender incorrect";
+ }
+
+ if not header :contains "x-sieve-redirected-from"
+ "timo@example.net" {
+ test_fail "x-sieve-redirected-from header is incorrect";
+ }
+}
+
+test_result_reset;
+test_set "message" text:
+From: stephan@example.org
+To: tss@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "timo@example.net";
+test_set "envelope.orig_to" "tss@example.net";
+
+test_config_set "sieve_redirect_envelope_from" "user_email";
+test_config_reload;
+
+test "Redirect from [user email - fallback default]" {
+ redirect "cras@example.net";
+
+ if not test_result_execute {
+ test_fail "failed to execute redirect";
+ }
+
+ test_message :smtp 0;
+
+ if not envelope :is "from" "timo@example.net" {
+ test_fail "envelope sender incorrect";
+ }
+
+ if not header :contains "x-sieve-redirected-from"
+ "timo@example.net" {
+ test_fail "x-sieve-redirected-from header is incorrect";
+ }
+}
+
+test_result_reset;
+test_set "message" text:
+From: stephan@example.org
+To: tss@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "timo@example.net";
+test_set "envelope.orig_to" "tss@example.net";
+
+test_config_set "sieve_redirect_envelope_from" "user_email";
+test_config_set "sieve_user_email" "t.sirainen@example.net";
+test_config_reload;
+
+test "Redirect from [user email]" {
+ redirect "cras@example.net";
+
+ if not test_result_execute {
+ test_fail "failed to execute redirect";
+ }
+
+ test_message :smtp 0;
+
+ if envelope :is "from" "sirius@example.org" {
+ test_fail "envelope sender incorrect (not changed)";
+ }
+
+ if not envelope :is "from" "t.sirainen@example.net" {
+ test_fail "envelope sender incorrect";
+ }
+
+ if not header :contains "x-sieve-redirected-from"
+ "t.sirainen@example.net" {
+ test_fail "x-sieve-redirected-from header is incorrect";
+ }
+}
+
+/*
+ * Redirect mail loop (sieve_user_email)
+ */
+
+test_result_reset;
+test_set "message" text:
+X-Sieve-Redirected-From: t.sirainen@example.net
+From: stephan@example.org
+To: tss@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "timo@example.net";
+test_set "envelope.orig_to" "tss@example.net";
+
+test_config_set "sieve_redirect_envelope_from" "user_email";
+test_config_set "sieve_user_email" "t.sirainen@example.net";
+test_config_reload;
+
+test "Redirect mail loop (sieve_user_email)" {
+ redirect "cras@example.net";
+
+ if not test_result_execute {
+ test_fail "failed to execute redirect";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "failed to recognize mail loop";
+ }
+}
+
+/*
+ * Redirect mail loop (final recipient)
+ */
+
+test_result_reset;
+test_set "message" text:
+X-Sieve-Redirected-From: timo@example.net
+From: stephan@example.org
+To: tss@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "timo@example.net";
+test_set "envelope.orig_to" "tss@example.net";
+
+test_config_reload;
+
+test "Redirect mail loop (final recipient)" {
+ redirect "cras@example.net";
+
+ if not test_result_execute {
+ test_fail "failed to execute redirect";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "failed to recognize mail loop";
+ }
+}
+
+/*
+ * Redirect mail loop (multiple headers)
+ */
+
+test_result_reset;
+test_set "message" text:
+X-Sieve-Redirected-From: stephan@example.net
+From: stephan@example.org
+To: tss@example.net
+Subject: Frop!
+X-Sieve-Redirected-From: t.sirainen@example.net
+X-Sieve-Redirected-From: t.sirainen@example.com
+
+Frop!
+.
+;
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "timo@example.net";
+test_set "envelope.orig_to" "tss@example.net";
+
+test_config_set "sieve_redirect_envelope_from" "user_email";
+test_config_set "sieve_user_email" "t.sirainen@example.net";
+test_config_reload;
+
+test "Redirect mail loop (sieve_user_email)" {
+ redirect "cras@example.net";
+
+ if not test_result_execute {
+ test_fail "failed to execute redirect";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "failed to recognize mail loop";
+ }
+}
diff --git a/pigeonhole/tests/extensions/body/basic.svtest b/pigeonhole/tests/extensions/body/basic.svtest
new file mode 100644
index 0000000..0b2bffc
--- /dev/null
+++ b/pigeonhole/tests/extensions/body/basic.svtest
@@ -0,0 +1,97 @@
+require "vnd.dovecot.testsuite";
+require "relational";
+require "comparator-i;ascii-numeric";
+
+require "body";
+
+test_set "message" text:
+From: stephan@example.org
+To: tss@example.net
+Subject: Test message.
+
+Test!
+
+.
+;
+
+/* Empty line
+ *
+ * RFC 5173:
+ * 'The body test matches content in the body of an email message, that
+ * is, anything following the first empty line after the header. (The
+ * empty line itself, if present, is not considered to be part of the
+ * body.)'
+ */
+test "The empty line" {
+
+ if not body :raw :is text:
+Test!
+
+.
+ {
+ test_fail "invalid message body extracted (1)";
+ }
+
+ if body :raw :is text:
+
+Test!
+
+.
+ {
+ test_fail "invalid message body extracted (2)";
+ }
+
+ if body :raw :is "Test"
+ {
+ test_fail "body test matches nonsense (3)";
+ }
+}
+
+/* Default comparator and match type
+ *
+ * RFC 5173:
+ * 'The COMPARATOR and MATCH-TYPE keyword parameters are defined in
+ * [SIEVE]. As specified in Sections 2.7.1 and 2.7.3 of [SIEVE], the
+ * default COMPARATOR is "i;ascii-casemap" and the default MATCH-TYPE is
+ * ":is".'
+ */
+
+test "Defaults" {
+ if anyof ( body :raw "Test", body :raw "*Test*" ) {
+ test_fail "default match type is not :is as is required";
+ }
+
+ if allof( not body :raw :contains "tesT", body :raw :contains "Test" ) {
+ test_fail "default comparator is not i;ascii-casemap as is required";
+ }
+}
+
+/* No body
+ *
+ * RFC 5173:
+ * 'If a message consists of a header only, not followed by an empty line,
+ * then that set is empty and all "body" tests return false, including
+ * those that test for an empty string. (This is similar to how the
+ * "header" test always fails when the named header fields aren't present.)'
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: tss@example.net
+Subject: No body is here!
+.
+;
+
+test "No body" {
+ if body :raw :contains "" {
+ test_fail "matched against non-existent body (:contains \"\")";
+ }
+
+ if body :raw :is "" {
+ test_fail "matched against non-existent body (:is \"\")";
+ }
+
+ if body :raw :matches "*" {
+ test_fail "matched against non-existent body (:matches \"*\")";
+ }
+}
diff --git a/pigeonhole/tests/extensions/body/content.svtest b/pigeonhole/tests/extensions/body/content.svtest
new file mode 100644
index 0000000..2eb3837
--- /dev/null
+++ b/pigeonhole/tests/extensions/body/content.svtest
@@ -0,0 +1,332 @@
+require "vnd.dovecot.testsuite";
+require "relational";
+require "comparator-i;ascii-numeric";
+
+require "body";
+
+/*
+ *
+ */
+
+test_set "message" text:
+From: justin@example.com
+To: carl@example.nl
+Subject: Frop
+Content-Type: multipart/mixed; boundary=donkey
+
+This is a multi-part message in MIME format.
+
+--donkey
+Content-Type: text/plain
+
+Plain Text
+
+--donkey
+Content-Type: text/stupid
+
+Stupid Text
+
+--donkey
+Content-Type: text/plain/stupid
+
+Plain Stupid Text
+
+--donkey--
+.
+;
+
+/*
+ * RFC5173, Section 5.2:
+ * If an individual content type begins or ends with a '/' (slash) or
+ * contains multiple slashes, then it matches no content types.
+ * ...
+ */
+
+test "Basic Match" {
+ if not body :content "text/plain" :matches "Plain Text*" {
+ test_fail "failed to match (1)";
+ }
+
+ if not body :content "text/plain" :contains "" {
+ test_fail "failed to match (2)";
+ }
+
+ if not body :content "text/stupid" :contains "" {
+ test_fail "failed to match (3)";
+ }
+}
+
+test "Begin Slash" {
+ if body :content "/plain" :contains "" {
+ test_fail "matched :content \"/plain\"";
+ }
+}
+
+test "End Slash" {
+ if body :content "text/" :contains "" {
+ test_fail "matched :content \"text/\"";
+ }
+}
+
+test "Double Slash" {
+ if body :content "text/plain/stupid" :contains "" {
+ test_fail "matched :content \"text/plain/stupid\"";
+ }
+}
+
+/*
+ *
+ */
+
+test_set "message" text:
+From: justin@example.com
+To: carl@example.nl
+Subject: Frop
+Content-Type: multipart/mixed; boundary=limit
+
+This is a multi-part message in MIME format.
+
+--limit
+Content-Type: text/plain
+
+This is a text message.
+
+--limit
+Content-Type: text/html
+
+<html><body>This is HTML</body></html>
+
+--limit
+Content-Type: application/sieve
+
+keep;
+
+--limit--
+.
+;
+
+/* RFC5173, Section 5.2:
+ * ...
+ * Otherwise, if it contains a slash, then it specifies a full
+ * <type>/<subtype> pair, and matches only that specific content type.
+ * If it is the empty string, all MIME content types are matched.
+ * Otherwise, it specifies a <type> only, and any subtype of that type
+ * matches it.
+ */
+
+test "Full Content Type" {
+ if not body :content "text/plain" :matches "This is a text message.*" {
+ test_fail "failed to match text/plain content";
+ }
+
+ if body :content "text/plain" :matches "<html><body>This is HTML</body></html>*" {
+ test_fail "erroneously matched text/html content";
+ }
+
+ if not body :content "text/html" :matches "<html><body>This is HTML</body></html>*" {
+ test_fail "failed to match text/html content";
+ }
+
+ if body :content "text/html" :matches "This is a text message.*" {
+ test_fail "erroneously matched text/plain content";
+ }
+
+ if body :content "text/html" :matches "This is HTML*" {
+ test_fail "body :content test matched plain text";
+ }
+}
+
+test "Empty Content Type" {
+ if not body :content "" :matches "This is a text message.*" {
+ test_fail "failed to match text/plain content";
+ }
+
+ if not body :content "" :matches "<html><body>This is HTML</body></html>*" {
+ test_fail "failed to match text/html content";
+ }
+
+ if not body :content "" :matches "keep;*" {
+ test_fail "failed to match application/sieve content";
+ }
+
+ if body :content "" :matches "*blurdybloop*" {
+ test_fail "body :content \"\" test matches nonsense";
+ }
+}
+
+test "Main Content Type" {
+ if not body :content "text" :matches "This is a text message.*" {
+ test_fail "failed to match text/plain content";
+ }
+
+ if not body :content "text" :matches "<html><body>This is HTML</body></html>*" {
+ test_fail "failed to match text/html content";
+ }
+
+ if body :content "text" :matches "keep;*" {
+ test_fail "erroneously matched application/sieve content";
+ }
+}
+
+/*
+ *
+ */
+
+test_set "message" text:
+From: Whomever <whoever@example.com>
+To: Someone <someone@example.com>
+Date: Sat, 10 Oct 2009 00:30:04 +0200
+Subject: whatever
+Content-Type: multipart/mixed; boundary=outer
+
+This is a multi-part message in MIME format.
+
+--outer
+Content-Type: multipart/alternative; boundary=inner
+
+This is a nested multi-part message in MIME format.
+
+--inner
+Content-Type: text/plain; charset="us-ascii"
+
+Hello
+
+--inner
+Content-Type: text/html; charset="us-ascii"
+
+<html><body>Hello</body></html>
+
+--inner--
+
+This is the end of the inner MIME multipart.
+
+--outer
+Content-Type: message/rfc822
+
+From: Someone Else
+Subject: Hello, this is an elaborate request for you to finally say hello
+ already!
+
+Please say Hello
+
+--outer--
+
+This is the end of the outer MIME multipart.
+.
+;
+
+/* RFC5173, Section 5.2:
+ *
+ * The search for MIME parts matching the :content specification is
+ * recursive and automatically descends into multipart and
+ * message/rfc822 MIME parts. All MIME parts with matching types are
+ * searched for the key strings. The test returns true if any
+ * combination of a searched MIME part and key-list argument match.
+ */
+
+test "Nested Search" {
+ if not body :content "text/plain" :matches "Hello*" {
+ test_fail "failed to match text/plain content";
+ }
+
+ if body :content "text/plain" :matches "<html><body>Hello</body></html>*" {
+ test_fail "erroneously matched text/html content";
+ }
+
+ if not body :content "text/html" :matches "<html><body>Hello</body></html>*" {
+ test_fail "failed to match text/html content";
+ }
+
+ if body :content "text/html" :matches "Hello*" {
+ test_fail "erroneously matched text/plain content";
+ }
+
+ if not body :content "text" :contains "html" {
+ test_fail "failed match text content (1)";
+ }
+
+ if not body :content "text" :contains "hello" {
+ test_fail "failed match text content (2)";
+ }
+
+ if not body :content "text/plain" :contains "please say hello" {
+ test_fail "failed match nested message content as text/plain";
+ }
+
+ if not body :content "text" :contains "please say hello" {
+ test_fail "failed match nested message content as text/*";
+ }
+
+ if not body :content "text" :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "matched wrong number of \"text/*\" body parts";
+ }
+}
+
+/* RFC5173, Section 5.2:
+ *
+ * If the :content specification matches a multipart MIME part, only the
+ * prologue and epilogue sections of the part will be searched for the
+ * key strings, treating the entire prologue and the entire epilogue as
+ * separate strings; the contents of nested parts are only searched if
+ * their respective types match the :content specification.
+ *
+ */
+
+test "Multipart Content" {
+ if not body :content "multipart" :contains
+ "This is a multi-part message in MIME format" {
+ test_fail "missed first multipart body part";
+ }
+
+ if not body :content "multipart" :contains
+ "This is a nested multi-part message in MIME format" {
+ test_fail "missed second multipart body part";
+ }
+
+ if not body :content "multipart" :contains
+ "This is the end of the inner MIME multipart" {
+ test_fail "missed third multipart body part";
+ }
+
+ if not body :content "multipart" :contains
+ "This is the end of the outer MIME multipart." {
+ test_fail "missed fourth multipart body part";
+ }
+
+ if body :content "multipart" :contains "--inner" {
+ test_fail "inner boundary is part of match";
+ }
+
+ if body :content "multipart" :contains "--outer" {
+ test_fail "outer boundary is part of match";
+ }
+}
+
+/* RFC5173, Section 5.2:
+ *
+ * If the :content specification matches a message/rfc822 MIME part,
+ * only the header of the nested message will be searched for the key
+ * strings, treating the header as a single string; the contents of the
+ * nested message body parts are only searched if their content type
+ * matches the :content specification.
+ */
+
+test "Content-Type: message/rfc822" {
+ if not body :content "message/rfc822" :contains
+ "From: Someone Else" {
+ test_fail "missed raw message/rfc822 from header";
+ }
+
+ if not body :content "message/rfc822" :is text:
+From: Someone Else
+Subject: Hello, this is an elaborate request for you to finally say hello
+ already!
+.
+ {
+ test_fail "header content does not match exactly";
+ }
+}
+
+
+
+
diff --git a/pigeonhole/tests/extensions/body/errors.svtest b/pigeonhole/tests/extensions/body/errors.svtest
new file mode 100644
index 0000000..8db5657
--- /dev/null
+++ b/pigeonhole/tests/extensions/body/errors.svtest
@@ -0,0 +1,19 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Invalid syntax
+ */
+
+test "Invalid Syntax" {
+ if test_script_compile "errors/syntax.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "12" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/body/errors/syntax.sieve b/pigeonhole/tests/extensions/body/errors/syntax.sieve
new file mode 100644
index 0000000..8adf0ef
--- /dev/null
+++ b/pigeonhole/tests/extensions/body/errors/syntax.sieve
@@ -0,0 +1,38 @@
+require "body";
+
+# 1: No key list
+if body { }
+
+# 2: Number
+if body 3 { }
+
+# OK: String
+if body "frop" { }
+
+# 3: To many arguments
+if body "frop" "friep" { }
+
+# 4: Unknown tag
+if body :frop { }
+
+# 5: Unknown tag with valid key
+if body :friep "frop" { }
+
+# 6: Content without argument
+if body :content { }
+
+# 7: Content without key argument
+if body :content "frop" { }
+
+# 8: Content with number argument
+if body :content 3 "frop" { }
+
+# 9: Content with unknown tag
+if body :content :frml "frop" { }
+
+# 10: Content with known tag
+if body :content :contains "frop" { }
+
+# 11: Duplicate transform
+if body :content "frop" :raw "frop" { }
+
diff --git a/pigeonhole/tests/extensions/body/match-values.svtest b/pigeonhole/tests/extensions/body/match-values.svtest
new file mode 100644
index 0000000..55d5535
--- /dev/null
+++ b/pigeonhole/tests/extensions/body/match-values.svtest
@@ -0,0 +1,55 @@
+require "vnd.dovecot.testsuite";
+
+require "body";
+require "variables";
+
+test_set "message" text:
+From: stephan@example.org
+To: s.bosch@twente.example.net
+Subject: Body test
+
+The big bad body test.
+.
+;
+
+# Test whether body test ignores match values
+test "Match values disabled" {
+ if not body :raw :matches "The * bad * test*" {
+ test_fail "should have matched";
+ }
+
+ if anyof (
+ string :is "${1}" "big",
+ string :is "${2}" "body",
+ not string :is "${0}" "",
+ not string :is "${1}" "",
+ not string :is "${2}" "") {
+ test_fail "match values not disabled";
+ }
+}
+
+test "Match values re-enabled" {
+ if not header :matches "from" "*@*" {
+ test_fail "should have matched";
+ }
+
+ if anyof (
+ not string :is "${0}" "stephan@example.org",
+ not string :is "${1}" "stephan",
+ not string :is "${2}" "example.org" ) {
+ test_fail "match values not re-enabled properly.";
+ }
+}
+
+test "Match values retained" {
+ if not body :raw :matches "The * bad * test*" {
+ test_fail "should have matched";
+ }
+
+ if anyof (
+ not string :is "${0}" "stephan@example.org",
+ not string :is "${1}" "stephan",
+ not string :is "${2}" "example.org" ) {
+ test_fail "match values not retained after body test.";
+ }
+}
diff --git a/pigeonhole/tests/extensions/body/raw.svtest b/pigeonhole/tests/extensions/body/raw.svtest
new file mode 100644
index 0000000..d3404b9
--- /dev/null
+++ b/pigeonhole/tests/extensions/body/raw.svtest
@@ -0,0 +1,85 @@
+require "vnd.dovecot.testsuite";
+require "body";
+
+test_set "message" text:
+From: Whomever <whoever@example.com>
+To: Someone <someone@example.com>
+Date: Sat, 10 Oct 2009 00:30:04 +0200
+Subject: whatever
+Content-Type: multipart/mixed; boundary=outer
+
+This is a multi-part message in MIME format.
+
+--outer
+Content-Type: multipart/alternative; boundary=inner
+
+This is a nested multi-part message in MIME format.
+
+--inner
+Content-Type: text/plain; charset="us-ascii"
+
+Hello
+
+--inner
+Content-Type: text/html; charset="us-ascii"
+
+<html><body>Hello</body></html>
+
+--inner--
+
+This is the end of the inner MIME multipart.
+
+--outer
+Content-Type: message/rfc822
+
+From: Someone Else
+Subject: hello request
+
+Please say Hello
+
+--outer--
+
+This is the end of the outer MIME multipart.
+.
+;
+
+/*
+ *
+ * RFC 5173:
+ * The ":raw" transform matches against the entire undecoded body of a
+ * message as a single item.
+ *
+ * If the specified body-transform is ":raw", the [MIME] structure of
+ * the body is irrelevant. The implementation MUST NOT remove any
+ * transfer encoding from the message, MUST NOT refuse to filter
+ * messages with syntactic errors (unless the environment it is part of
+ * rejects them outright), and MUST treat multipart boundaries or the
+ * MIME headers of enclosed body parts as part of the content being
+ * matched against, instead of MIME structures to interpret.
+ */
+
+test "Multipart Boundaries" {
+ if not body :raw :contains "--inner" {
+ test_fail "Raw body does not contain '--inner'";
+ }
+
+ if not body :raw :contains "--outer" {
+ test_fail "Raw body does not contain '--outer'";
+ }
+}
+
+test "Multipart Headers" {
+ if not body :raw :contains "boundary=inner" {
+ test_fail "Raw body does not contain 'boundary=inner'";
+ }
+
+ if not body :raw :contains "rfc822" {
+ test_fail "Raw body does not contain 'rfc822'";
+ }
+}
+
+test "Multipart Content" {
+ if not body :raw :contains "<html><body>Hello</body></html>" {
+ test_fail "Raw body does not contain '<html><body>Hello</body></html>'";
+ }
+}
diff --git a/pigeonhole/tests/extensions/body/text.svtest b/pigeonhole/tests/extensions/body/text.svtest
new file mode 100644
index 0000000..2dc6a03
--- /dev/null
+++ b/pigeonhole/tests/extensions/body/text.svtest
@@ -0,0 +1,225 @@
+require "vnd.dovecot.testsuite";
+require "relational";
+require "comparator-i;ascii-numeric";
+
+require "body";
+
+/*
+ *
+ */
+
+test_set "message" text:
+From: justin@example.com
+To: carl@example.nl
+Subject: Frop
+Content-Type: multipart/mixed; boundary=donkey
+
+This is a multi-part message in MIME format.
+
+--donkey
+Content-Type: text/plain
+
+Plain Text
+
+--donkey
+Content-Type: text/stupid
+
+Stupid Text
+
+--donkey
+Content-Type: text/plain/stupid
+
+Plain Stupid Text
+
+--donkey--
+.
+;
+
+test "Basic Match" {
+ if not body :text :contains "Plain Text" {
+ test_fail "failed to match (1)";
+ }
+
+ if not body :text :contains "Stupid Text" {
+ test_fail "failed to match (2)";
+ }
+}
+
+test "Double Slash" {
+ if body :text :contains "Plain Stupid Text" {
+ test_fail "matched \"text/plain/stupid\"";
+ }
+}
+
+/*
+ *
+ */
+
+test_set "message" text:
+From: justin@example.com
+To: carl@example.nl
+Subject: Frop
+Content-Type: multipart/mixed; boundary=limit
+
+This is a multi-part message in MIME format.
+
+--limit
+Content-Type: text/plain
+
+This is a text message.
+
+--limit
+Content-Type: text/html
+
+<html><body>This is HTML</body></html>
+
+--limit
+Content-Type: application/sieve
+
+keep;
+
+--limit--
+.
+;
+
+test "Full Content Type" {
+ if not body :text :contains "This is a text message" {
+ test_fail "failed to match text/plain content";
+ }
+
+ if not body :text :contains "This is HTML" {
+ test_fail "failed to match text/html content";
+ }
+
+ if body :text :contains "<html>" {
+ test_fail "erroneously matched text/html markup";
+ }
+
+ if body :text :contains "keep;" {
+ test_fail "body :text test matched non-text content";
+ }
+}
+
+/*
+ *
+ */
+
+test_set "message" text:
+From: Whomever <whoever@example.com>
+To: Someone <someone@example.com>
+Date: Sat, 10 Oct 2009 00:30:04 +0200
+Subject: whatever
+Content-Type: multipart/mixed; boundary=outer
+
+This is a multi-part message in MIME format.
+
+--outer
+Content-Type: multipart/alternative; boundary=inner
+
+This is a nested multi-part message in MIME format.
+
+--inner
+Content-Type: text/plain; charset="us-ascii"
+
+Hello
+
+--inner
+Content-Type: text/html; charset="us-ascii"
+
+<html><body>HTML Hello</body></html>
+
+--inner
+Content-Type: application/xhtml+xml; charset="us-ascii"
+
+<html><body>XHTML Hello</body></html>
+
+--inner--
+
+This is the end of the inner MIME multipart.
+
+--outer
+Content-Type: message/rfc822
+
+From: Someone Else
+Subject: Hello, this is an elaborate request for you to finally say hello
+ already!
+
+Please say Hello
+
+--outer--
+
+This is the end of the outer MIME multipart.
+.
+;
+
+/* RFC5173, Section 5.2:
+ *
+ * The search for MIME parts matching the :content specification is
+ * recursive and automatically descends into multipart and
+ * message/rfc822 MIME parts. All MIME parts with matching types are
+ * searched for the key strings. The test returns true if any
+ * combination of a searched MIME part and key-list argument match.
+ */
+
+test "Nested Search" {
+ if not body :text :contains "Hello" {
+ test_fail "failed to match text/plain content";
+ }
+ if not body :text :contains "HTML Hello" {
+ test_fail "failed to match text/html content";
+ }
+ if not body :text :contains "XHTML Hello" {
+ test_fail "failed to match application/xhtml+xml content";
+ }
+ if body :text :contains ["<html>", "body"] {
+ test_fail "erroneously matched text/html markup";
+ }
+ if not body :text :contains "Please say Hello" {
+ test_fail "failed to match message/rfc822 body";
+ }
+ if body :text :contains "MIME" {
+ test_fail "erroneously matched multipart prologue/epilogue text";
+ }
+}
+
+/*
+ * Broken/Empty parts
+ */
+
+test_set "message" text:
+From: Whomever <whoever@example.com>
+To: Someone <someone@example.com>
+Date: Sat, 10 Oct 2009 00:30:04 +0200
+Subject: whatever
+Content-Type: multipart/mixed; boundary=outer
+
+This is a multi-part message in MIME format.
+
+--outer
+Content-Type: text/html
+
+--outer
+Content-Type: text/html; charset=utf-8
+Content-Transfer-Encoding: multipart/related
+Content-Disposition: inline
+
+<html><body>Please say Hello</body></html>
+
+--outer--
+
+This is the end of the outer MIME multipart.
+.
+;
+
+test "Nested Search" {
+ if body :text :contains "Hello" {
+ test_fail "Cannot match empty/broken part";
+ }
+ if body :text :contains ["<html>", "body"] {
+ test_fail "erroneously matched text/html markup";
+ }
+ if body :text :contains "MIME" {
+ test_fail "erroneously matched multipart prologue/epilogue text";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/date/basic.svtest b/pigeonhole/tests/extensions/date/basic.svtest
new file mode 100644
index 0000000..5d0b33f
--- /dev/null
+++ b/pigeonhole/tests/extensions/date/basic.svtest
@@ -0,0 +1,73 @@
+require "vnd.dovecot.testsuite";
+require "date";
+require "variables";
+require "relational";
+
+test_set "message" text:
+From: stephan@example.org
+To: sirius@friep.example.com
+Subject: Frop!
+Date: Mon, 20 Jul 2009 21:44:43 +0300
+Delivery-Date: Mon, 22 Jul 2009 23:30:14 +0300
+Invalid-Date: Moo, 34 Juul 3060 25:30:42 +6600
+Wanna date?
+.
+;
+
+test "Defaults" {
+ if not date :originalzone "date" "std11" "mon, 20 jul 2009 21:44:43 +0300" {
+ test_fail "default comparator is not i;ascii-casemap";
+ }
+
+ if anyof ( date "date" "std11" "Mon", date "date" "std11" "*") {
+ test_fail "default match type appears to be :contains or :matches";
+ }
+}
+
+test "Count" {
+ if not date :count "eq" "date" "date" "1" {
+ test_fail "count of existing date header field is not 1";
+ }
+
+ if not date :count "eq" "resent-date" "date" "0" {
+ test_fail "count of non-existent date header field is not 0";
+ }
+}
+
+test "Invalid" {
+ if date :matches "invalid-date" "std11" "*" {
+ test_fail "matched invalid date: ${0}";
+ }
+}
+
+test "Comparison" {
+ if not date :originalzone :is "delivery-date" "date" "2009-07-22" {
+ if date :originalzone :matches "delivery-date" "date" "*" { set "date" "${1}"; }
+ test_fail "date is invalid: ${date}";
+ }
+ if not date :originalzone :value "ge" "delivery-date" "date" "2009-07-22" {
+ test_fail "date comparison ge failed equal";
+ }
+
+ if not date :originalzone :value "ge" "delivery-date" "date" "2009-07-21" {
+ test_fail "date comparison ge failed greater";
+ }
+
+ if anyof (not date :originalzone :value "ge" "delivery-date" "date" "2009-06-22",
+ not date :originalzone :value "ge" "date" "date" "2006-07-22" ) {
+ test_fail "date comparison ge failed much greater";
+ }
+
+ if not date :originalzone :value "le" "delivery-date" "date" "2009-07-22" {
+ test_fail "date comparison le failed equal";
+ }
+
+ if not date :originalzone :value "le" "delivery-date" "date" "2009-07-23" {
+ test_fail "date comparison le failed less";
+ }
+
+ if anyof (not date :originalzone :value "le" "delivery-date" "date" "2009-09-22",
+ not date :originalzone :value "le" "date" "date" "2012-07-22" ) {
+ test_fail "date comparison ge failed much less";
+ }
+}
diff --git a/pigeonhole/tests/extensions/date/date-parts.svtest b/pigeonhole/tests/extensions/date/date-parts.svtest
new file mode 100644
index 0000000..edc565c
--- /dev/null
+++ b/pigeonhole/tests/extensions/date/date-parts.svtest
@@ -0,0 +1,120 @@
+require "vnd.dovecot.testsuite";
+require "date";
+require "variables";
+
+test_set "message" text:
+From: stephan@example.org
+To: sirius@friep.example.com
+Subject: Frop!
+Date: Mon, 20 Jul 2009 21:44:43 +0300
+Delivery-Date: Mon, 22 Jul 2009 23:30:14 +0300
+
+Wanna date?
+.
+;
+
+/* "year" => the year, "0000" .. "9999". */
+test "Year" {
+ if not date :originalzone "date" "year" "2009" {
+ test_fail "failed to extract year part";
+ }
+}
+
+/* "month" => the month, "01" .. "12". */
+test "Month" {
+ if not date :originalzone "date" "month" "07" {
+ test_fail "failed to extract month part";
+ }
+}
+
+/* "day" => the day, "01" .. "31". */
+test "Day" {
+ if not date :originalzone "date" "day" "20" {
+ test_fail "failed to extract day part";
+ }
+}
+
+/* "date" => the date in "yyyy-mm-dd" format. */
+test "Date" {
+ if not date :originalzone "date" "date" "2009-07-20" {
+ test_fail "failed to extract date part";
+ }
+}
+
+/* "julian" => the Modified Julian Day, that is, the date
+ expressed as an integer number of days since
+ 00:00 UTC on November 17, 1858 (using the Gregorian
+ calendar). This corresponds to the regular
+ Julian Day minus 2400000.5. */
+test "Julian" {
+ if not date :originalzone "date" "julian" "55032" {
+ if date :matches :originalzone "date" "julian" "*" { }
+ test_fail "failed to extract julian part: ${0}";
+ }
+ if not date :originalzone "delivery-date" "julian" "55034" {
+ if date :matches :originalzone "delivery-date" "julian" "*" { }
+ test_fail "failed to extract julian part: ${0}";
+ }
+}
+
+/* "hour" => the hour, "00" .. "23". */
+test "Hour" {
+ if not date :originalzone "date" "hour" "21" {
+ test_fail "failed to extract hour part";
+ }
+}
+
+/* "minute" => the minute, "00" .. "59". */
+test "Minute" {
+ if not date :originalzone "date" "minute" "44" {
+ test_fail "failed to extract minute part";
+ }
+}
+
+/* "second" => the second, "00" .. "60". */
+test "Second" {
+ if not date :originalzone "date" "second" "43" {
+ test_fail "failed to extract second part";
+ }
+}
+
+/* "time" => the time in "hh:mm:ss" format. */
+test "Time" {
+ if not date :originalzone "date" "time" "21:44:43" {
+ test_fail "failed to extract time part";
+ }
+}
+
+/* "iso8601" => the date and time in restricted ISO 8601 format. */
+test "ISO8601" {
+ if not date :originalzone "date" "iso8601" "2009-07-20T21:44:43+03:00" {
+ test_fail "failed to extract iso8601 part";
+ }
+}
+
+/* "std11" => the date and time in a format appropriate
+ for use in a Date: header field [RFC2822]. */
+test "STD11" {
+ if not date :originalzone "date" "std11" "Mon, 20 Jul 2009 21:44:43 +0300" {
+ test_fail "failed to extract std11 part";
+ }
+}
+
+/* "zone" => the time zone in use. */
+test "zone" {
+ if not date :originalzone "date" "zone" "+0300" {
+ test_fail "failed to extract zone part";
+ }
+
+ if not date :zone "+0200" "date" "zone" "+0200" {
+ test_fail "failed to extract zone part";
+ }
+}
+
+/* "weekday" => the day of the week expressed as an integer between
+ "0" and "6". "0" is Sunday, "1" is Monday, etc. */
+test "Weekday" {
+ if not date :originalzone "date" "weekday" "1" {
+ test_fail "failed to extract weekday part";
+ }
+}
diff --git a/pigeonhole/tests/extensions/date/zones.svtest b/pigeonhole/tests/extensions/date/zones.svtest
new file mode 100644
index 0000000..77adb77
--- /dev/null
+++ b/pigeonhole/tests/extensions/date/zones.svtest
@@ -0,0 +1,76 @@
+require "vnd.dovecot.testsuite";
+require "date";
+require "variables";
+
+/* Extract local timezone first */
+test "Local-Zone" {
+ if not currentdate :matches "zone" "*" {
+ test_fail "matches '*' failed for zone part.";
+ }
+ set "local_zone" "${0}";
+}
+
+/* FIXME: using variables somehow fails here */
+if string "${local_zone}" "+0200" {
+test_set "message" text:
+From: stephan@example.org
+To: sirius@friep.example.com
+Subject: Frop!
+Date: Mon, 20 Jul 2009 21:44:43 +0300
+Delivery-Date: Mon, 23 Jul 2009 05:30:14 +0800
+
+Wanna date?
+.
+;
+} else {
+test_set "message" text:
+From: stephan@example.org
+To: sirius@friep.example.com
+Subject: Frop!
+Date: Mon, 20 Jul 2009 21:44:43 +0300
+Delivery-Date: Mon, 22 Jul 2009 23:30:14 +0200
+
+Wanna date?
+.
+;
+}
+
+test "Specified Zone" {
+ if not date :zone "+0200" "date" "zone" "+0200" {
+ if date :matches :zone "+0200" "date" "zone" "*" {}
+ test_fail "zone is incorrect: ${0}";
+ }
+
+ if not date :zone "+0200" "date" "time" "20:44:43" {
+ test_fail "zone is not applied";
+ }
+}
+
+test "Original Zone" {
+ if not date :originalzone "date" "zone" "+0300" {
+ if date :matches :originalzone "date" "zone" "*" {}
+ test_fail "zone is incorrect: ${0}";
+ }
+
+ if not date :originalzone "date" "time" "21:44:43" {
+ test_fail "time should be left untouched";
+ }
+}
+
+test "Local Zone Shift" {
+ if anyof (
+ allof (
+ string "${local_zone}" "+0200",
+ date "delivery-date" "iso8601" "2009-07-23T05:30:14+08:00"),
+ allof (
+ not string "${local_zone}" "+0200",
+ date "delivery-date" "iso8601" "2009-07-22T23:30:14+02:00")) {
+
+ if date :matches "delivery-date" "iso8601" "*"
+ { set "a" "${0}"; }
+ if date :originalzone :matches "delivery-date" "iso8601" "*"
+ { set "b" "${0}"; }
+
+ test_fail "time not shifted to local zone: ${b} => ${a}";
+ }
+}
diff --git a/pigeonhole/tests/extensions/duplicate/errors.svtest b/pigeonhole/tests/extensions/duplicate/errors.svtest
new file mode 100644
index 0000000..108a0f0
--- /dev/null
+++ b/pigeonhole/tests/extensions/duplicate/errors.svtest
@@ -0,0 +1,54 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Invalid syntax
+ */
+
+test "Invalid Syntax" {
+ if test_script_compile "errors/syntax.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "17" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Invalid Syntax (vnd)" {
+ if test_script_compile "errors/syntax-vnd.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "5" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Extension conflict
+ */
+
+test "Extension conflict" {
+ if test_script_compile "errors/conflict.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "2" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Extension conflict (vnd first)" {
+ if test_script_compile "errors/conflict-vnd.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "2" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+
diff --git a/pigeonhole/tests/extensions/duplicate/errors/conflict-vnd.sieve b/pigeonhole/tests/extensions/duplicate/errors/conflict-vnd.sieve
new file mode 100644
index 0000000..1c133df
--- /dev/null
+++ b/pigeonhole/tests/extensions/duplicate/errors/conflict-vnd.sieve
@@ -0,0 +1,4 @@
+require "vnd.dovecot.duplicate";
+require "duplicate";
+
+if duplicate { keep; }
diff --git a/pigeonhole/tests/extensions/duplicate/errors/conflict.sieve b/pigeonhole/tests/extensions/duplicate/errors/conflict.sieve
new file mode 100644
index 0000000..aa9b038
--- /dev/null
+++ b/pigeonhole/tests/extensions/duplicate/errors/conflict.sieve
@@ -0,0 +1,4 @@
+require "duplicate";
+require "vnd.dovecot.duplicate";
+
+if duplicate { keep; }
diff --git a/pigeonhole/tests/extensions/duplicate/errors/syntax-vnd.sieve b/pigeonhole/tests/extensions/duplicate/errors/syntax-vnd.sieve
new file mode 100644
index 0000000..f62aa2c
--- /dev/null
+++ b/pigeonhole/tests/extensions/duplicate/errors/syntax-vnd.sieve
@@ -0,0 +1,19 @@
+require "vnd.dovecot.duplicate";
+
+# Used as a command
+duplicate;
+
+# Used with no argument (not an error)
+if duplicate {}
+
+# Used with string argument
+if duplicate "frop" { }
+
+# Used with numer argument
+if duplicate 23423 { }
+
+# Used with numer argument
+if duplicate ["frop"] { }
+
+
+
diff --git a/pigeonhole/tests/extensions/duplicate/errors/syntax.sieve b/pigeonhole/tests/extensions/duplicate/errors/syntax.sieve
new file mode 100644
index 0000000..a561cfb
--- /dev/null
+++ b/pigeonhole/tests/extensions/duplicate/errors/syntax.sieve
@@ -0,0 +1,54 @@
+require "duplicate";
+
+# Used as a command
+duplicate;
+
+# Used with no argument (not an error)
+if duplicate {}
+
+# Used with string argument
+if duplicate "frop" { }
+
+# Used with numner argument
+if duplicate 23423 { }
+
+# Used with numer argument
+if duplicate ["frop"] { }
+
+# Used with unknown tag
+if duplicate :test "frop" { }
+
+# Bad :header parameter
+if duplicate :header 23 {}
+
+# Bad :uniqueid parameter
+if duplicate :uniqueid 23 {}
+
+# Bad :handle parameter
+if duplicate :handle ["a", "b", "c"] {}
+
+# Bad seconds parameter
+if duplicate :seconds "a" {}
+
+# Missing :header parameter
+if duplicate :header {}
+
+# Missing :uniqueid parameter
+if duplicate :uniqueid {}
+
+# Missing :handle parameter
+if duplicate :handle {}
+
+# Missing seconds parameter
+if duplicate :seconds {}
+
+# :last with a parameter
+if duplicate :last "frop" {}
+
+# :last as :seconds parameter
+if duplicate :seconds :last {}
+
+# Conflicting tags
+if duplicate :header "X-Frop" :uniqueid "FROP!" { }
+
+
diff --git a/pigeonhole/tests/extensions/duplicate/execute-vnd.svtest b/pigeonhole/tests/extensions/duplicate/execute-vnd.svtest
new file mode 100644
index 0000000..386550f
--- /dev/null
+++ b/pigeonhole/tests/extensions/duplicate/execute-vnd.svtest
@@ -0,0 +1,20 @@
+require "vnd.dovecot.testsuite";
+require "vnd.dovecot.duplicate";
+
+test "Run" {
+ if duplicate {
+ test_fail "test erroneously reported a duplicate";
+ }
+
+ if duplicate :handle "handle" {
+ test_fail "test with name erroneously reported a duplicate";
+ }
+
+ if duplicate {
+ test_fail "test erroneously reported a duplicate";
+ }
+
+ if duplicate :handle "handle" {
+ test_fail "test with name erroneously reported a duplicate";
+ }
+}
diff --git a/pigeonhole/tests/extensions/duplicate/execute.svtest b/pigeonhole/tests/extensions/duplicate/execute.svtest
new file mode 100644
index 0000000..9e060ff
--- /dev/null
+++ b/pigeonhole/tests/extensions/duplicate/execute.svtest
@@ -0,0 +1,41 @@
+require "vnd.dovecot.testsuite";
+require "duplicate";
+
+# Simple execution tests; no duplicate verification can be tested yet.
+test "Run" {
+ if duplicate {
+ test_fail "test erroneously reported a duplicate";
+ }
+
+ if duplicate :handle "handle" {
+ test_fail "test with :handle erroneously reported a duplicate";
+ }
+
+ if duplicate {
+ test_fail "test erroneously reported a duplicate";
+ }
+
+ if duplicate :handle "handle" {
+ test_fail "test with :handle erroneously reported a duplicate";
+ }
+
+ if duplicate :header "X-frop" {
+ test_fail "test with :header erroneously reported a duplicate";
+ }
+
+ if duplicate :uniqueid "FROP!" {
+ test_fail "test with :uniqueid erroneously reported a duplicate";
+ }
+
+ if duplicate :seconds 90 {
+ test_fail "test with :seconds erroneously reported a duplicate";
+ }
+
+ if duplicate :seconds 90 :last {
+ test_fail "test with :seconds :last erroneously reported a duplicate";
+ }
+
+ if duplicate :last {
+ test_fail "test with :seconds :last erroneously reported a duplicate";
+ }
+}
diff --git a/pigeonhole/tests/extensions/editheader/addheader.svtest b/pigeonhole/tests/extensions/editheader/addheader.svtest
new file mode 100644
index 0000000..426b43d
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/addheader.svtest
@@ -0,0 +1,833 @@
+require "vnd.dovecot.testsuite";
+require "encoded-character";
+require "variables";
+require "fileinto";
+require "mailbox";
+require "body";
+
+require "editheader";
+
+set "message" text:
+From: stephan@example.com
+To: timo@example.com
+Subject: Frop!
+
+Frop!
+
+.
+;
+
+test_set "message" "${message}";
+test "Addheader - first" {
+ if size :over 76 {
+ test_fail "original message is longer than 76 bytes?!";
+ }
+
+ addheader "X-Some-Header" "Header content";
+
+ if not size :over 76 {
+ test_fail "mail is not larger";
+ }
+
+ if size :over 107 {
+ test_fail "mail is too large";
+ }
+
+ if size :under 107 {
+ test_fail "mail is too small";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "header not added";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content added";
+ }
+
+ redirect "frop@example.com";
+ fileinto :create "folder1";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "folder1" 0 {
+ test_fail "message not stored";
+ }
+
+ if not size :over 76 {
+ test_fail "stored mail is not larger";
+ }
+
+ if size :over 107 {
+ test_fail "stored mail is too large";
+ }
+
+ if size :under 100 {
+ test_fail "stored mail is too small";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in stored mail";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "header not in stored mail";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content in stored mail ";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in redirected mail";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "header not in redirected mail";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content in redirected mail ";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+test_result_reset;
+test_set "message" "${message}";
+test "Addheader - first (two)" {
+ if size :over 76 {
+ test_fail "original message is longer than 76 bytes?!";
+ }
+
+ addheader "X-Some-Header" "Header content";
+ addheader "X-Some-Other-Header" "More header content";
+
+ if not size :over 76 {
+ test_fail "mail is not larger";
+ }
+
+ if size :over 149 {
+ test_fail "mail is too large";
+ }
+
+ if size :under 149 {
+ test_fail "mail is too small";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "header #1 not added";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content added #1";
+ }
+
+ if not exists "x-some-other-header" {
+ test_fail "header #2 not added";
+ }
+
+ if not header :is "x-some-other-header" "More header content" {
+ test_fail "wrong content added #2";
+ }
+
+ redirect "frop@example.com";
+ fileinto :create "folder2";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "folder2" 0 {
+ test_fail "message not stored";
+ }
+
+ if not size :over 76 {
+ test_fail "stored mail is not larger";
+ }
+
+ if size :over 149 {
+ test_fail "stored mail is too large";
+ }
+
+ if size :under 100 {
+ test_fail "stored mail is too small";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in stored mail";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "header #1 not in stored mail";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content #1 in stored mail ";
+ }
+
+ if not exists "x-some-other-header" {
+ test_fail "header #2 not in stored mail";
+ }
+
+ if not header :is "x-some-other-header" "More header content" {
+ test_fail "wrong content #2 in stored mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in redirected mail";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "header not in redirected mail";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content in redirected mail ";
+ }
+
+ if not exists "x-some-other-header" {
+ test_fail "header #2 not in redirected mail";
+ }
+
+ if not header :is "x-some-other-header" "More header content" {
+ test_fail "wrong content #2 in redirected mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+test_result_reset;
+test_set "message" "${message}";
+test "Addheader - last" {
+ if size :over 76 {
+ test_fail "original message is longer than 76 bytes?!";
+ }
+
+ addheader :last "X-Some-Header" "Header content";
+
+ if not size :over 76 {
+ test_fail "mail is not larger";
+ }
+
+ if size :over 107 {
+ test_fail "mail is too large";
+ }
+
+ if size :under 107 {
+ test_fail "mail is too small";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "header not added";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content added";
+ }
+
+ redirect "frop@example.com";
+ fileinto :create "folder3";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "folder3" 0 {
+ test_fail "message not stored";
+ }
+
+ if not size :over 76 {
+ test_fail "stored mail is not larger";
+ }
+
+ if size :over 107 {
+ test_fail "stored mail is too large";
+ }
+
+ if size :under 100 {
+ test_fail "stored mail is too small";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in stored mail";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "header not in stored mail";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content in stored mail ";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in redirected mail";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "header not in redirected mail";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content in redirected mail ";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+test_result_reset;
+test_set "message" "${message}";
+test "Addheader - last (two)" {
+ if size :over 76 {
+ test_fail "original message is longer than 76 bytes?!";
+ }
+
+ addheader :last "X-Some-Header" "Header content";
+ addheader "X-Some-Other-Header" "More header content";
+
+ if not size :over 76 {
+ test_fail "mail is not larger";
+ }
+
+ if size :over 149 {
+ test_fail "mail is too large";
+ }
+
+ if size :under 149 {
+ test_fail "mail is too small";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "header #1 not added";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content added #1";
+ }
+
+ if not exists "x-some-other-header" {
+ test_fail "header #2 not added";
+ }
+
+ if not header :is "x-some-other-header" "More header content" {
+ test_fail "wrong content added #2";
+ }
+
+ redirect "frop@example.com";
+ fileinto :create "folder4";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "folder4" 0 {
+ test_fail "message not stored";
+ }
+
+ if not size :over 76 {
+ test_fail "stored mail is not larger";
+ }
+
+ if size :over 149 {
+ test_fail "stored mail is too large";
+ }
+
+ if size :under 100 {
+ test_fail "stored mail is too small";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in stored mail";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "header #1 not in stored mail";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content #1 in stored mail";
+ }
+
+ if not exists "x-some-other-header" {
+ test_fail "header #2 not in stored mail";
+ }
+
+ if not header :is "x-some-other-header" "More header content" {
+ test_fail "wrong content #2 in stored mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in redirected mail";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "header #1 not in redirected mail";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content #1 in redirected mail ";
+ }
+
+ if not exists "x-some-other-header" {
+ test_fail "header #2 not in redirected mail";
+ }
+
+ if not header :is "x-some-other-header" "More header content" {
+ test_fail "wrong content #2 in redirected mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+test_result_reset;
+test_set "message" "${message}";
+test "Addheader - framed" {
+ if size :over 76 {
+ test_fail "original message is longer than 76 bytes?!";
+ }
+
+ addheader "X-Some-Header-first" "Header content first";
+ addheader :last "X-Some-Header-last" "Header content last";
+
+ if not size :over 76 {
+ test_fail "mail is not larger";
+ }
+
+ if size :over 160 {
+ test_fail "mail is too large";
+ }
+
+ if size :under 160 {
+ test_fail "mail is too small";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained";
+ }
+
+ if not exists "x-some-header-first" {
+ test_fail "first header not added";
+ }
+
+ if not exists "x-some-header-last" {
+ test_fail "last header not added";
+ }
+
+ if not header :is "x-some-header-first" "Header content first" {
+ test_fail "wrong first content added";
+ }
+
+ if not header :is "x-some-header-last" "Header content last" {
+ test_fail "wrong last content added";
+ }
+
+ redirect "frop@example.com";
+ fileinto :create "folder5";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "folder5" 0 {
+ test_fail "message not stored";
+ }
+
+ if not size :over 76 {
+ test_fail "stored mail is not larger";
+ }
+
+ if size :over 160 {
+ test_fail "stored mail is too large";
+ }
+
+ if size :under 152 {
+ test_fail "stored mail is too small";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in stored mail";
+ }
+
+ if not exists "x-some-header-first" {
+ test_fail "first header not in stored mail";
+ }
+
+ if not exists "x-some-header-last" {
+ test_fail "last header not in stored mail";
+ }
+
+ if not header :is "x-some-header-first" "Header content first" {
+ test_fail "wrong first header content in stored mail ";
+ }
+
+ if not header :is "x-some-header-last" "Header content last" {
+ test_fail "wrong last header content in stored mail ";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in redirected mail";
+ }
+
+ if not exists "x-some-header-first" {
+ test_fail "first header not in redirected mail";
+ }
+
+ if not exists "x-some-header-last" {
+ test_fail "last header not in redirected mail";
+ }
+
+ if not header :is "x-some-header-first" "Header content first" {
+ test_fail "wrong first header content in redirected mail ";
+ }
+
+ if not header :is "x-some-header-last" "Header content last" {
+ test_fail "wrong last header content in redirected mail ";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+/*
+ * Addheader - folded
+ */
+
+test_result_reset;
+test_set "message" "${message}";
+test "Addheader - folded" {
+ set "before"
+ "This is very long header content, folded to fit inside multiple header lines. This may cause problems, so that is why it is tested here.";
+ set "after"
+ "This is somewhat longer header content, folded to fit inside multiple header lines. This may cause problems, so that is why it is tested here.";
+
+ addheader :last "X-Some-Header-first" "${before}";
+ addheader :last "X-Some-Header-last" "${after}";
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained";
+ }
+
+ if not exists "x-some-header-first" {
+ test_fail "first header not added";
+ }
+
+ if not exists "x-some-header-last" {
+ test_fail "last header not added";
+ }
+
+ if not header :is "x-some-header-first" "${before}" {
+ test_fail "wrong first content added";
+ }
+
+ if not header :is "x-some-header-last" "${after}" {
+ test_fail "wrong last content added";
+ }
+
+ redirect "frop@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in redirected mail";
+ }
+
+ if not exists "x-some-header-first" {
+ test_fail "first header not in redirected mail";
+ }
+
+ if not exists "x-some-header-last" {
+ test_fail "last header not in redirected mail";
+ }
+
+ if not header :is "x-some-header-first" "${before}" {
+ test_fail "wrong first header content in redirected mail ";
+ }
+
+ if not header :is "x-some-header-last" "${after}" {
+ test_fail "wrong last header content in redirected mail ";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+/*
+ * Addheader - newlines
+ */
+
+test_result_reset;
+test_set "message" "${message}";
+test "Addheader - newlines" {
+ set "before" text:
+This is very long header content
+ containing newlines. This may
+ cause some problems, so that
+ is why it is tested here.
+.
+;
+
+ set "after" text:
+This is somewhat longer header content
+ containing newlines. This may
+ cause some problems, so that
+ is why it is tested here.
+.
+;
+
+ set "before_out"
+ "This is very long header content containing newlines. This may cause some problems, so that is why it is tested here.";
+
+ set "after_out"
+ "This is somewhat longer header content containing newlines. This may cause some problems, so that is why it is tested here.";
+
+ addheader "X-Some-Header-first" "${before}";
+ addheader :last "X-Some-Header-last" "${after}";
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained";
+ }
+
+ if not exists "x-some-header-first" {
+ test_fail "first header not added";
+ }
+
+ if not exists "x-some-header-last" {
+ test_fail "last header not added";
+ }
+
+ if not header :is "x-some-header-first" "${before_out}" {
+ if header :matches "x-some-header-first" "*" {}
+ test_fail "wrong first content added: `${0}`";
+ }
+
+ if not header :is "x-some-header-last" "${after_out}" {
+ if header :matches "x-some-header-last" "*" {}
+ test_fail "wrong last content added: `${0}`";
+ }
+
+ redirect "frop@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in redirected mail";
+ }
+
+ if not exists "x-some-header-first" {
+ test_fail "first header not in redirected mail";
+ }
+
+ if not exists "x-some-header-last" {
+ test_fail "last header not in redirected mail";
+ }
+
+ if not header :is "x-some-header-first" "${before_out}" {
+ if header :matches "x-some-header-first" "*" {}
+ test_fail "wrong first header content in redirected mail: `${0}`";
+ }
+
+ if not header :is "x-some-header-last" "${after_out}" {
+ if header :matches "x-some-header-last" "*" {}
+ test_fail "wrong last header content in redirected mail: `${0}`";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+test_result_reset;
+test_set "message" "${message}";
+test "Addheader - implicit keep" {
+ if size :over 76 {
+ test_fail "original message is longer than 76 bytes?!";
+ }
+
+ addheader "X-Some-Header" "Header content";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "INBOX" 0 {
+ test_fail "message not stored";
+ }
+
+ if not size :over 76 {
+ test_fail "stored mail is not larger";
+ }
+
+ if size :over 107 {
+ test_fail "stored mail is too large";
+ }
+
+ if size :under 100 {
+ test_fail "stored mail is too small";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in stored message";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "header not added to stored message";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content added to stored message";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+}
+
+test_set "message" "${message}";
+test "Addheader - UTF 8" {
+ if size :over 76 {
+ test_fail "original message is longer than 76 bytes?!";
+ }
+
+ addheader "X-Some-Header" "Это тест!";
+ fileinto :create "folder6";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "folder6" 0 {
+ test_fail "message not stored";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "header not added to stored message";
+ }
+
+ if not header :is "x-some-header" "Это тест!" {
+ if header :matches "x-some-header" "*" {}
+ test_fail "Bel character not retained: `${0}`";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+}
+
+test_result_reset;
+
+test_set "message" "${message}";
+test "Addheader - devious characters" {
+ if size :over 76 {
+ test_fail "original message is longer than 76 bytes?!";
+ }
+
+ addheader "X-Some-Header" "Ring my ${hex:07}!";
+ fileinto :create "folder7";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "folder7" 0 {
+ test_fail "message not stored";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "header not added to stored message";
+ }
+
+ if header :is "x-some-header" "Ring my !" {
+ if header :matches "x-some-header" "*" {}
+ test_fail "Bel character not retained: `${0}`";
+ }
+
+ if not header :is "x-some-header" "Ring my ${hex:07}!" {
+ if header :matches "x-some-header" "*" {}
+ test_fail "Incorrect header value: `${0}`";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+}
diff --git a/pigeonhole/tests/extensions/editheader/alternating.svtest b/pigeonhole/tests/extensions/editheader/alternating.svtest
new file mode 100644
index 0000000..44d459c
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/alternating.svtest
@@ -0,0 +1,181 @@
+require "vnd.dovecot.testsuite";
+require "variables";
+require "fileinto";
+require "mailbox";
+require "body";
+
+require "editheader";
+
+set "message" text:
+From: stephan@example.com
+To: timo@example.com
+Subject: Frop!
+
+Frop!
+
+.
+;
+
+
+test_set "message" "${message}";
+test "Alternating - add; delete" {
+ addheader "X-Some-Header" "Header content";
+
+ if not exists "x-some-header" {
+ test_fail "header not added";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content added";
+ }
+
+ redirect "frop@example.com";
+
+ deleteheader "X-Some-Header";
+
+ if exists "x-some-header" {
+ test_fail "header not deleted";
+ }
+
+ fileinto :create "folder1";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ /* redirected message */
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "added header not in redirected mail";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content in redirected mail ";
+ }
+
+ /* stored message message */
+
+ if not test_message :folder "folder1" 0 {
+ test_fail "message not stored";
+ }
+
+ if exists "x-some-header" {
+ test_fail "added header still present stored mail";
+ }
+}
+
+test_result_reset;
+
+test_set "message" "${message}";
+test "Alternating - delete; add" {
+ deleteheader "Subject";
+
+ if exists "subject" {
+ test_fail "header not deleted";
+ }
+
+ redirect "frop@example.com";
+
+ addheader "Subject" "Friep!";
+
+ if not exists "subject" {
+ test_fail "header not added";
+ }
+
+ if not header :is "subject" "Friep!" {
+ test_fail "wrong content added";
+ }
+
+ fileinto :create "folder2";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ /* redirected message */
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if exists "subject" {
+ test_fail "deleted header still present redirected mail";
+ }
+
+ /* stored message message */
+
+ if not test_message :folder "folder2" 0 {
+ test_fail "message not stored";
+ }
+
+ if not exists "subject" {
+ test_fail "added header not in stored mail";
+ }
+
+ if not header :is "subject" "Friep!" {
+ test_fail "wrong content in redirected mail ";
+ }
+}
+
+test_result_reset;
+
+test_set "message" "${message}";
+test "Alternating - add :last; delete any" {
+ addheader :last "X-Some-Header" "Header content";
+
+ if not exists "x-some-header" {
+ test_fail "header not added";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content added";
+ }
+
+ redirect "frop@example.com";
+
+ deleteheader "X-Some-Other-Header";
+
+ if not exists "x-some-header" {
+ test_fail "header somehow deleted";
+ }
+
+ fileinto :create "folder3";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ /* redirected message */
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "added header not in redirected mail";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content in redirected mail ";
+ }
+
+ /* stored message message */
+
+ if not test_message :folder "folder3" 0 {
+ test_fail "message not stored";
+ }
+
+ if not exists "x-some-header" {
+ test_fail "added header lost in stored mail";
+ }
+
+ if not header :is "x-some-header" "Header content" {
+ test_fail "wrong content in stored mail ";
+ }
+
+}
+
diff --git a/pigeonhole/tests/extensions/editheader/deleteheader.svtest b/pigeonhole/tests/extensions/editheader/deleteheader.svtest
new file mode 100644
index 0000000..8b9d3ad
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/deleteheader.svtest
@@ -0,0 +1,1115 @@
+require "vnd.dovecot.testsuite";
+require "variables";
+require "fileinto";
+require "mailbox";
+require "body";
+
+require "editheader";
+
+set "message" text:
+X-A: Onzinnige informatie
+X-B: kun je maar beter
+X-C: niet via e-mail versturen
+From: stephan@example.com
+X-D: en daarom is het nuttig
+To: timo@example.com
+Subject: Frop!
+X-A: dit terstond te verwijderen,
+X-B: omdat dit anders
+X-C: alleen maar schijfruimte verspilt.
+
+Frop!
+
+.
+;
+
+test_set "message" "${message}";
+test "Deleteheader - nonexistent" {
+ if size :over 288 {
+ test_fail "original message is longer than 288 bytes?!";
+ }
+
+ if size :under 288 {
+ test_fail "original message is shorter than 288 bytes?!";
+ }
+
+ deleteheader "X-Z";
+
+ if size :under 288 {
+ test_fail "message is shorter than original";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained";
+ }
+
+ if not header :is "X-B" "omdat dit anders" {
+ test_fail "original X-B header not retained";
+ }
+
+ if not header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C header not retained";
+ }
+
+ redirect "frop@example.com";
+ fileinto :create "folder1";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "folder1" 0 {
+ test_fail "message not stored";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in stored mail";
+ }
+
+ if not header :is "X-B" "omdat dit anders" {
+ test_fail "original X-B header not retained in stored mail";
+ }
+
+ if not header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C header not retained in stored mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in redirected mail";
+ }
+
+ if not header :is "X-B" "omdat dit anders" {
+ test_fail "original X-B header not retained in redirected mail";
+ }
+
+ if not header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C header not retained in redirected mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+test_set "message" "${message}";
+test "Deleteheader - nonexistent (match)" {
+ if size :over 288 {
+ test_fail "original message is longer than 288 bytes?!";
+ }
+
+ if size :under 288 {
+ test_fail "original message is shorter than 288 bytes?!";
+ }
+
+ deleteheader :matches "X-Z" "*frop*";
+
+ if size :under 288 {
+ test_fail "message is shorter than original";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained";
+ }
+
+ if not header :is "X-B" "omdat dit anders" {
+ test_fail "original X-B header not retained";
+ }
+
+ if not header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C header not retained";
+ }
+
+ redirect "frop@example.com";
+ fileinto :create "folder1b";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "folder1b" 0 {
+ test_fail "message not stored";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in stored mail";
+ }
+
+ if not header :is "X-B" "omdat dit anders" {
+ test_fail "original X-B header not retained in stored mail";
+ }
+
+ if not header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C header not retained in stored mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in redirected mail";
+ }
+
+ if not header :is "X-B" "omdat dit anders" {
+ test_fail "original X-B header not retained in redirected mail";
+ }
+
+ if not header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C header not retained in redirected mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+test_result_reset;
+test_set "message" "${message}";
+test "Deleteheader - one" {
+ if size :over 288 {
+ test_fail "original message is longer than 288 bytes?!";
+ }
+
+ if size :under 288 {
+ test_fail "original message is shorter than 288 bytes?!";
+ }
+
+ deleteheader "X-D";
+
+ if not size :under 288 {
+ test_fail "edited message is not shorter";
+ }
+
+ if size :over 258 {
+ test_fail "edited message is too long";
+ }
+
+ if size :under 258 {
+ test_fail "edited message is too short";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained";
+ }
+
+ if not header :is "X-B" "omdat dit anders" {
+ test_fail "original X-B header not retained";
+ }
+
+ if not header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C header not retained";
+ }
+
+ if exists "X-D" {
+ test_fail "X-D header not deleted";
+ }
+
+ redirect "frop@example.com";
+ fileinto :create "folder2";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "folder2" 0 {
+ test_fail "message not stored";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in stored mail";
+ }
+
+ if not header :is "X-B" "omdat dit anders" {
+ test_fail "original X-B header not retained in stored mail";
+ }
+
+ if not header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C header not retained in stored mail";
+ }
+
+ if exists "X-D" {
+ test_fail "X-D header not deleted in stored mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in redirected mail";
+ }
+
+ if not header :is "X-B" "omdat dit anders" {
+ test_fail "original X-B header not retained in redirected mail";
+ }
+
+ if not header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C header not retained in redirected mail";
+ }
+
+ if exists "X-D" {
+ test_fail "X-D header not deleted in redirected mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+test_result_reset;
+test_set "message" "${message}";
+test "Deleteheader - two (first)" {
+ if size :over 288 {
+ test_fail "original message is longer than 288 bytes?!";
+ }
+
+ if size :under 288 {
+ test_fail "original message is shorter than 288 bytes?!";
+ }
+
+ deleteheader "X-A";
+
+ if not size :under 288 {
+ test_fail "edited message is not shorter";
+ }
+
+ if size :over 226 {
+ test_fail "edited message is too long";
+ }
+
+ if size :under 226 {
+ test_fail "edited message is too short";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained";
+ }
+
+ if not header :is "X-B" "omdat dit anders" {
+ test_fail "original X-B header not retained";
+ }
+
+ if not header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C header not retained";
+ }
+
+ if exists "X-A" {
+ test_fail "X-A header not deleted";
+ }
+
+ redirect "frop@example.com";
+ fileinto :create "folder3";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "folder3" 0 {
+ test_fail "message not stored";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in stored mail";
+ }
+
+ if not header :is "X-B" "omdat dit anders" {
+ test_fail "original X-B header not retained in stored mail";
+ }
+
+ if not header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C header not retained in stored mail";
+ }
+
+ if exists "X-A" {
+ test_fail "X-A header not deleted in stored mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in redirected mail";
+ }
+
+ if not header :is "X-B" "omdat dit anders" {
+ test_fail "original X-B header not retained in redirected mail";
+ }
+
+ if not header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C header not retained in redirected mail";
+ }
+
+ if exists "X-A" {
+ test_fail "X-A header not deleted in redirected mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+test_result_reset;
+test_set "message" "${message}";
+test "Deleteheader - two (last)" {
+ if size :over 288 {
+ test_fail "original message is longer than 288 bytes?!";
+ }
+
+ if size :under 288 {
+ test_fail "original message is shorter than 288 bytes?!";
+ }
+
+ deleteheader "X-C";
+
+ if not size :under 288 {
+ test_fail "edited message is not shorter";
+ }
+
+ if size :over 215 {
+ test_fail "edited message is too long";
+ }
+
+ if size :under 215 {
+ test_fail "edited message is too short";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained";
+ }
+
+ if not header :is "X-A" "dit terstond te verwijderen," {
+ test_fail "original X-A header not retained";
+ }
+
+ if not header :is "X-B" "omdat dit anders" {
+ test_fail "original X-B header not retained";
+ }
+
+ if exists "X-C" {
+ test_fail "X-C header not deleted";
+ }
+
+ redirect "frop@example.com";
+ fileinto :create "folder4";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "folder4" 0 {
+ test_fail "message not stored";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in stored mail";
+ }
+
+ if not header :is "X-A" "dit terstond te verwijderen," {
+ test_fail "original X-A header not retained in stored mail";
+ }
+
+ if not header :is "X-B" "omdat dit anders" {
+ test_fail "original X-B header not retained in stored mail";
+ }
+
+ if exists "X-C" {
+ test_fail "X-C header not deleted in stored mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in redirected mail";
+ }
+
+ if not header :is "X-A" "dit terstond te verwijderen," {
+ test_fail "original X-A header not retained in redirected mail";
+ }
+
+ if not header :is "X-B" "omdat dit anders" {
+ test_fail "original X-B header not retained in redirected mail";
+ }
+
+ if exists "X-C" {
+ test_fail "X-C header not deleted in redirected mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+test_result_reset;
+test_set "message" "${message}";
+test "Deleteheader - :index" {
+ if size :over 288 {
+ test_fail "original message is longer than 288 bytes?!";
+ }
+
+ if size :under 288 {
+ test_fail "original message is shorter than 288 bytes?!";
+ }
+
+ deleteheader :index 1 "X-A";
+ deleteheader :index 2 "X-C";
+
+ if not size :under 288 {
+ test_fail "edited message is not shorter";
+ }
+
+ if size :over 220 {
+ test_fail "edited message is too long";
+ }
+
+ if size :under 220 {
+ test_fail "edited message is too short";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained";
+ }
+
+ if not header :is "X-A" "dit terstond te verwijderen," {
+ test_fail "original X-A (2) header not retained";
+ }
+
+ if not header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C (1) header not retained";
+ }
+
+ if header :is "X-A" "Onzinnige informatie" {
+ test_fail "original X-A (1) header not deleted";
+ }
+
+ if header :is "X-C" "alleen maar schijfruimte verspilt." {
+ test_fail "original X-C (2) header not deleted";
+ }
+
+ redirect "frop@example.com";
+ fileinto :create "folder5";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "folder5" 0 {
+ test_fail "message not stored";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in stored mail";
+ }
+
+ if not header :is "X-A" "dit terstond te verwijderen," {
+ test_fail "original X-A (2) header not retained in stored mail";
+ }
+
+ if not header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C (1) header not retained in stored mail";
+ }
+
+ if header :is "X-A" "Onzinnige informatie" {
+ test_fail "original X-A (1) header not deleted in stored mail";
+ }
+
+ if header :is "X-C" "alleen maar schijfruimte verspilt." {
+ test_fail "original X-C (2) header not deleted in stored mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in redirected mail";
+ }
+
+ if not header :is "X-A" "dit terstond te verwijderen," {
+ test_fail "original X-A (2) header not retained redirected mail";
+ }
+
+ if not header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-B (1) header not retained redirected mail";
+ }
+
+ if header :is "X-A" "Onzinnige informatie" {
+ test_fail "original X-A (1) header not deleted redirected mail";
+ }
+
+ if header :is "X-C" "alleen maar schijfruimte verspilt." {
+ test_fail "original X-B (2) header not deleted redirected mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+test_result_reset;
+test_set "message" "${message}";
+test "Deleteheader - :index :last" {
+ if size :over 288 {
+ test_fail "original message is longer than 288 bytes?!";
+ }
+
+ if size :under 288 {
+ test_fail "original message is shorter than 288 bytes?!";
+ }
+
+ deleteheader :index 1 :last "X-A";
+ deleteheader :last :index 2 "X-C";
+
+ if size :over 221 {
+ test_fail "edited message is too long";
+ }
+
+ if size :under 221 {
+ test_fail "edited message is too short";
+ }
+
+ if not size :under 288 {
+ test_fail "edited message is not shorter";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained";
+ }
+
+ if not header :is "X-A" "Onzinnige informatie" {
+ test_fail "original X-A (1) header not retained";
+ }
+
+ if not header :is "X-C" "alleen maar schijfruimte verspilt." {
+ test_fail "original X-C (2) header not retained";
+ }
+
+ if header :is "X-A" "dit terstond te verwijderen," {
+ test_fail "original X-A (2) header not deleted";
+ }
+
+ if header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C (1) header not deleted";
+ }
+
+ redirect "frop@example.com";
+ fileinto :create "folder6";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "folder6" 0 {
+ test_fail "message not stored";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in stored mail";
+ }
+
+ if not header :is "X-A" "Onzinnige informatie" {
+ test_fail "original X-A (1) header not retained in stored mail";
+ }
+
+ if not header :is "X-C" "alleen maar schijfruimte verspilt." {
+ test_fail "original X-C (2) header not retained in stored mail";
+ }
+
+ if header :is "X-A" "dit terstond te verwijderen," {
+ test_fail "original X-A (2) header not deleted in stored mail";
+ }
+
+ if header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C (1) header not deleted in stored mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in redirected mail";
+ }
+
+ if header :is "X-A" "dit terstond te verwijderen," {
+ test_fail "original X-A (2) header not deleted redirected mail";
+ }
+
+ if header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-B (1) header not deleted redirected mail";
+ }
+
+ if not header :is "X-A" "Onzinnige informatie" {
+ test_fail "original X-A (1) header not retained redirected mail";
+ }
+
+ if not header :is "X-C" "alleen maar schijfruimte verspilt." {
+ test_fail "original X-B (2) header not retained redirected mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+test_result_reset;
+test_set "message" "${message}";
+test "Deleteheader - implicit keep" {
+ deleteheader "X-D";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "INBOX" 0 {
+ test_fail "message not stored";
+ }
+
+ if not header :is "subject" "Frop!" {
+ test_fail "original subject header not retained in stored mail";
+ }
+
+ if not header :is "X-B" "omdat dit anders" {
+ test_fail "original X-B header not retained in stored mail";
+ }
+
+ if not header :is "X-C" "niet via e-mail versturen" {
+ test_fail "original X-C header not retained in stored mail";
+ }
+
+ if exists "X-D" {
+ test_fail "X-D header not deleted in stored mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+}
+
+/*
+ *
+ */
+
+test_result_reset;
+
+test_set "message" text:
+X-A: Dit is een klein verhaaltje
+X-B: om te testen of de correcte
+X-C: informatie wordt herkend en
+X-D: verwijderd. Zo valt goed te
+X-A: zien dat het allemaal werkt
+X-B: zoals het bedoeld is. Alles
+X-C: wordt in een keer getest op
+X-D: een wijze die efficient die
+X-A: problemen naar voren brengt
+X-B: die bij dit nieuwe deel van
+X-C: de programmatuur naar voren
+X-D: kunnen komen. Zo werkt het!
+
+Frop!
+.
+;
+
+test "Deleteheader - :matches" {
+ if size :over 417 {
+ test_fail "original message is longer than 417 bytes?!";
+ }
+
+ if size :under 417 {
+ test_fail "original message is shorter than 417 bytes?!";
+ }
+
+ deleteheader :matches "X-A" "*klein*";
+ deleteheader :matches "X-B" "*bedoeld*";
+ deleteheader :matches "X-C" "*programmatuur*";
+ deleteheader :contains "X-D" ["verwijderd", "!"];
+
+ if not size :under 417 {
+ test_fail "edited message is not shorter";
+ }
+
+ if size :over 247 {
+ test_fail "edited message is too long";
+ }
+
+ if size :under 247 {
+ test_fail "edited message is too short";
+ }
+
+ if not header :is "X-A" "zien dat het allemaal werkt" {
+ test_fail "original X-A (2) header not retained";
+ }
+
+ if not header :is "X-A" "problemen naar voren brengt" {
+ test_fail "original X-A (3) header not retained";
+ }
+
+ if not header :is "X-B" "om te testen of de correcte" {
+ test_fail "original X-B (1) header not retained";
+ }
+
+ if not header :is "X-B" "die bij dit nieuwe deel van" {
+ test_fail "original X-B (3) header not retained";
+ }
+
+ if not header :is "X-C" "informatie wordt herkend en" {
+ test_fail "original X-C (1) header not retained";
+ }
+
+ if not header :is "X-C" "wordt in een keer getest op" {
+ test_fail "original X-C (2) header not retained";
+ }
+
+ if not header :is "X-D" "een wijze die efficient die" {
+ test_fail "original X-C (2) header not retained";
+ }
+
+ if header :is "X-A" "Dit is een klein verhaaltje" {
+ test_fail "original X-A (1) header not deleted";
+ }
+
+ if header :is "X-B" "zoals het bedoeld is. Alles" {
+ test_fail "original X-B (2) header not deleted";
+ }
+
+ if header :is "X-C" "de programmatuur naar voren" {
+ test_fail "original X-C (3) header not deleted";
+ }
+
+ if header :is "X-D" "verwijderd. Zo valt goed te" {
+ test_fail "original X-C (1) header not deleted";
+ }
+
+ if header :is "X-D" "kunnen komen. Zo werkt het!" {
+ test_fail "original X-C (3) header not deleted";
+ }
+
+ redirect "frop@example.com";
+ fileinto :create "folder7";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :folder "folder7" 0 {
+ test_fail "message not stored";
+ }
+
+ if not header :is "X-A" "zien dat het allemaal werkt" {
+ test_fail "original X-A (2) header not retained in stored mail";
+ }
+
+ if not header :is "X-A" "problemen naar voren brengt" {
+ test_fail "original X-A (3) header not retained in stored mail";
+ }
+
+ if not header :is "X-B" "om te testen of de correcte" {
+ test_fail "original X-B (1) header not retained in stored mail";
+ }
+
+ if not header :is "X-B" "die bij dit nieuwe deel van" {
+ test_fail "original X-B (3) header not retained in stored mail";
+ }
+
+ if not header :is "X-C" "informatie wordt herkend en" {
+ test_fail "original X-C (1) header not retained in stored mail";
+ }
+
+ if not header :is "X-C" "wordt in een keer getest op" {
+ test_fail "original X-C (2) header not retained in stored mail";
+ }
+
+ if not header :is "X-D" "een wijze die efficient die" {
+ test_fail "original X-C (2) header not retained in stored mail";
+ }
+
+ if header :is "X-A" "Dit is een klein verhaaltje" {
+ test_fail "original X-A (1) header not deleted in stored mail";
+ }
+
+ if header :is "X-B" "zoals het bedoeld is. Alles" {
+ test_fail "original X-B (2) header not deleted in stored mail";
+ }
+
+ if header :is "X-C" "de programmatuur naar voren" {
+ test_fail "original X-C (3) header not deleted in stored mail";
+ }
+
+ if header :is "X-D" "verwijderd. Zo valt goed te" {
+ test_fail "original X-C (1) header not deleted in stored mail";
+ }
+
+ if header :is "X-D" "kunnen komen. Zo werkt het!" {
+ test_fail "original X-C (3) header not deleted in stored mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in stored mail";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not header :is "X-A" "zien dat het allemaal werkt" {
+ test_fail "original X-A (2) header not retained in redirected mail";
+ }
+
+ if not header :is "X-A" "problemen naar voren brengt" {
+ test_fail "original X-A (3) header not retained in redirected mail";
+ }
+
+ if not header :is "X-B" "om te testen of de correcte" {
+ test_fail "original X-B (1) header not retained in redirected mail";
+ }
+
+ if not header :is "X-B" "die bij dit nieuwe deel van" {
+ test_fail "original X-B (3) header not retained in redirected mail";
+ }
+
+ if not header :is "X-C" "informatie wordt herkend en" {
+ test_fail "original X-C (1) header not retained in redirected mail";
+ }
+
+ if not header :is "X-C" "wordt in een keer getest op" {
+ test_fail "original X-C (2) header not retained in redirected mail";
+ }
+
+ if not header :is "X-D" "een wijze die efficient die" {
+ test_fail "original X-C (2) header not retained in redirected mail";
+ }
+
+ if header :is "X-A" "Dit is een klein verhaaltje" {
+ test_fail "original X-A (1) header not deleted in redirected mail";
+ }
+
+ if header :is "X-B" "zoals het bedoeld is. Alles" {
+ test_fail "original X-B (2) header not deleted in redirected mail";
+ }
+
+ if header :is "X-C" "de programmatuur naar voren" {
+ test_fail "original X-C (3) header not deleted in redirected mail";
+ }
+
+ if header :is "X-D" "verwijderd. Zo valt goed te" {
+ test_fail "original X-C (1) header not deleted in redirected mail";
+ }
+
+ if header :is "X-D" "kunnen komen. Zo werkt het!" {
+ test_fail "original X-C (3) header not deleted in redirected mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+
+/*
+ *
+ */
+
+set "message2" text:
+X-A: Long folded header to test removal of folded
+ headers from a message. This is the top header.
+X-B: First intermittent unfolded header
+X-A: Long folded header to test removal of folded
+ headers from a message. This is the middle header.
+X-B: Second intermittent unfolded header
+X-A: Long folded header to test removal of folded
+ headers from a message. This is the bottom header,
+ which concludes the header of this message.
+
+Frop!
+.
+;
+
+test_result_reset;
+test_set "message" "${message2}";
+test "Deleteheader - folded" {
+ deleteheader "X-A";
+
+ if exists "X-A" {
+ test_fail "original X-A (1) header not deleted";
+ }
+
+ if not header :is "X-B" "First intermittent unfolded header" {
+ test_fail "original X-B (2) header not retained";
+ }
+
+ if not header :is "X-B" "Second intermittent unfolded header" {
+ test_fail "original X-B (2) header not retained";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+
+ redirect "frop@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if exists "X-A" {
+ test_fail "original X-A (1) header not deleted in redirected mail";
+ }
+
+ if not header :is "X-B" "First intermittent unfolded header" {
+ test_fail "original X-B (2) header not retained in redirected mail";
+ }
+
+ if not header :is "X-B" "Second intermittent unfolded header" {
+ test_fail "original X-B (2) header not retained in redirected mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+test_result_reset;
+test_set "message" "${message2}";
+test "Deleteheader - folded (match)" {
+ deleteheader :matches "X-A" "*header*";
+
+ if exists "X-A" {
+ test_fail "original X-A (1) header not deleted";
+ }
+
+ if not header :is "X-B" "First intermittent unfolded header" {
+ test_fail "original X-B (2) header not retained";
+ }
+
+ if not header :is "X-B" "Second intermittent unfolded header" {
+ test_fail "original X-B (2) header not retained";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+
+ redirect "frop@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if exists "X-A" {
+ test_fail "original X-A (1) header not deleted in redirected mail";
+ }
+
+ if not header :is "X-B" "First intermittent unfolded header" {
+ test_fail "original X-B (2) header not retained in redirected mail";
+ }
+
+ if not header :is "X-B" "Second intermittent unfolded header" {
+ test_fail "original X-B (2) header not retained in redirected mail";
+ }
+
+ if not body :matches "Frop!*" {
+ test_fail "body not retained in redirected mail";
+ }
+}
+
+
+/*
+ * TEST: Ignoring whitespace
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.com
+Subject: Help
+X-A: Text
+X-B: Text
+
+Text
+.
+;
+
+test "Ignoring whitespace" {
+ deleteheader :is "subject" "Help";
+ deleteheader :is "x-a" "Text";
+ deleteheader :is "x-b" "Text";
+
+ if exists "subject" {
+ test_fail "subject header not deleted";
+ }
+
+ if exists "x-a" {
+ test_fail "x-a header not deleted";
+ }
+
+ if exists "x-b" {
+ test_fail "x-b header not deleted";
+ }
+}
+
+/*
+ * TEST: Interaction with body test
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.com
+Subject: Hoppa
+
+Text
+.
+;
+
+test "Interaction with body test" {
+ addheader "X-Frop" "frop";
+
+ if body "!TEST!" {}
+
+ deleteheader "subject";
+
+ if exists "subject" {
+ test_fail "subject header not deleted";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/editheader/errors.svtest b/pigeonhole/tests/extensions/editheader/errors.svtest
new file mode 100644
index 0000000..1d1f24d
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/errors.svtest
@@ -0,0 +1,164 @@
+require "vnd.dovecot.testsuite";
+require "comparator-i;ascii-numeric";
+require "relational";
+require "variables";
+
+require "editheader";
+
+test "Invalid field-name" {
+ if test_script_compile "errors/field-name.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "5" {
+ test_fail "wrong number of errors reported";
+ }
+
+ if not test_error :index 1 :matches "*field name*X-field:*invalid*" {
+ test_fail "wrong error reported (1)";
+ }
+
+ if not test_error :index 2 :matches "*field name*X field*invalid*" {
+ test_fail "wrong error reported (2)";
+ }
+
+ if not test_error :index 3 :matches "*field name*X-field:*invalid*" {
+ test_fail "wrong error reported (3)";
+ }
+
+ if not test_error :index 4 :matches "*field name*X field*invalid*" {
+ test_fail "wrong error reported (4)";
+ }
+}
+
+test "Invalid field-name at runtime " {
+ if not test_script_compile "errors/field-name-runtime.sieve" {
+ test_fail "compile failed";
+ }
+
+ if test_script_run {
+ test_fail "run should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "1" {
+ test_fail "wrong number of errors reported";
+ }
+
+ if not test_error :matches "*field name*X-field:*invalid*" {
+ test_fail "wrong error reported";
+ }
+}
+
+test "Invalid field value" {
+ if test_script_compile "errors/field-value.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "2" {
+ test_fail "wrong number of errors reported";
+ }
+
+ if not test_error :index 1 :matches "*value*Woah*invalid*" {
+ test_fail "wrong error reported (1): ${0}";
+ }
+}
+
+test "Command syntax (FIXME: count only)" {
+ if test_script_compile "errors/command-syntax.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "10" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * TEST - Size limit
+ */
+
+test "Size limit" {
+ if not test_script_compile "errors/size-limit.sieve" {
+ test_fail "compile should have succeeded";
+ }
+
+ test_config_set "sieve_editheader_max_header_size" "1024";
+ test_config_reload :extension "editheader";
+
+ if test_script_compile "errors/size-limit.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "2" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+
+/*
+ * TEST - Size limit at runtime
+ */
+
+test_config_set "sieve_editheader_max_header_size" "";
+test_config_reload :extension "editheader";
+
+test "Size limit at runtime" {
+ if not test_script_compile "errors/size-limit-runtime.sieve" {
+ test_fail "compile should have succeeded";
+ }
+
+ if not test_script_run {
+ test_fail "run failed";
+ }
+
+ test_config_set "sieve_editheader_max_header_size" "1024";
+ test_config_reload :extension "editheader";
+
+ if not test_script_compile "errors/size-limit-runtime.sieve" {
+ test_fail "compile should have succeeded";
+ }
+
+ if test_script_run {
+ test_fail "run should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "1" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * TEST - Implicit keep at runtime error
+ */
+
+test_set "message" text:
+From: stephan@example.com
+To: tss@example.com
+Subject: Frop
+
+Frop!
+.
+;
+
+test "Implicit keep at runtime error" {
+ if not test_script_compile "errors/runtime-error.sieve" {
+ test_fail "compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "run failed";
+ }
+
+ if test_result_execute {
+ test_fail "result execution should have failed";
+ }
+
+ if not test_message :folder "INBOX" 0 {
+ test_fail "message not stored (no implicit keep)";
+ }
+
+ if exists "X-Frop" {
+ test_fail "implicit keep message has editheader changes";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/editheader/errors/command-syntax.sieve b/pigeonhole/tests/extensions/editheader/errors/command-syntax.sieve
new file mode 100644
index 0000000..8543e6d
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/errors/command-syntax.sieve
@@ -0,0 +1,42 @@
+require "editheader";
+
+/* "addheader" [":last"] <field-name: string> <value: string>
+ */
+
+# 1: missing field name and value
+addheader;
+
+# 2: missing value
+addheader "x-frop";
+
+# 3: value not a string; number
+addheader "x-frop" 2;
+
+# 4: value not a string; list
+addheader "x-frop" ["frop"];
+
+# 5: strange tag
+addheader :tag "x-frop" "frop";
+
+/* "deleteheader" [":index" <fieldno: number> [":last"]]
+ * [COMPARATOR] [MATCH-TYPE]
+ * <field-name: string>
+ * [<value-patterns: string-list>]
+ */
+
+# 6: missing field name
+deleteheader;
+
+# 7: :last tag without index
+deleteheader :last "x-frop";
+
+# 8: :index tag with string argument
+deleteheader :index "frop" "x-frop";
+
+# OK: match type without value patterns
+deleteheader :matches "x-frop";
+
+# 9: value patterns not a string(list)
+deleteheader "x-frop" 1;
+
+
diff --git a/pigeonhole/tests/extensions/editheader/errors/field-name-runtime.sieve b/pigeonhole/tests/extensions/editheader/errors/field-name-runtime.sieve
new file mode 100644
index 0000000..3f34461
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/errors/field-name-runtime.sieve
@@ -0,0 +1,6 @@
+require "editheader";
+require "variables";
+
+set "header" "X-field:";
+
+addheader "${header}" "Frop";
diff --git a/pigeonhole/tests/extensions/editheader/errors/field-name.sieve b/pigeonhole/tests/extensions/editheader/errors/field-name.sieve
new file mode 100644
index 0000000..469bfc8
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/errors/field-name.sieve
@@ -0,0 +1,19 @@
+require "editheader";
+
+# Ok
+addheader "X-field" "Frop";
+
+# Invalid ':'
+addheader "X-field:" "Frop";
+
+# Invalid ' '
+addheader "X field" "Frop";
+
+# Ok
+deleteheader "X-field";
+
+# Invalid ':'
+deleteheader "X-field:";
+
+# Invalid ' '
+deleteheader "X field";
diff --git a/pigeonhole/tests/extensions/editheader/errors/field-value.sieve b/pigeonhole/tests/extensions/editheader/errors/field-value.sieve
new file mode 100644
index 0000000..c9f4eab
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/errors/field-value.sieve
@@ -0,0 +1,15 @@
+require "editheader";
+require "encoded-character";
+
+# Ok
+addheader "X-field" "Frop";
+
+# Ok
+addheader "X-field" "Frop
+Frml";
+
+# Invalid 'BELL'; but not an error
+addheader "X-field" "Yeah${hex:07}!";
+
+# Invalid 'NUL'
+addheader "X-field" "Woah${hex:00}!";
diff --git a/pigeonhole/tests/extensions/editheader/errors/runtime-error.sieve b/pigeonhole/tests/extensions/editheader/errors/runtime-error.sieve
new file mode 100644
index 0000000..b308d74
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/errors/runtime-error.sieve
@@ -0,0 +1,6 @@
+require "editheader";
+require "fileinto";
+
+addheader "X-Frop" "Friep";
+
+fileinto "Rediculous.non-existent.folder";
diff --git a/pigeonhole/tests/extensions/editheader/errors/size-limit-runtime.sieve b/pigeonhole/tests/extensions/editheader/errors/size-limit-runtime.sieve
new file mode 100644
index 0000000..73a1437
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/errors/size-limit-runtime.sieve
@@ -0,0 +1,46 @@
+require "editheader";
+require "variables";
+
+set "blob" text:
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+.
+;
+
+addheader "x-frop" "${blob}";
diff --git a/pigeonhole/tests/extensions/editheader/errors/size-limit.sieve b/pigeonhole/tests/extensions/editheader/errors/size-limit.sieve
new file mode 100644
index 0000000..598f5f9
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/errors/size-limit.sieve
@@ -0,0 +1,43 @@
+require "editheader";
+
+addheader "x-frop" text:
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+.
+;
diff --git a/pigeonhole/tests/extensions/editheader/execute.svtest b/pigeonhole/tests/extensions/editheader/execute.svtest
new file mode 100644
index 0000000..e65cc5d
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/execute.svtest
@@ -0,0 +1,57 @@
+require "vnd.dovecot.testsuite";
+require "include";
+require "variables";
+require "editheader";
+
+/*
+ * Testsuite self-test
+ */
+
+set "message" ".";
+addheader "X-Some-Header" "Header content";
+test_result_reset;
+test_set "message" "${message}";
+
+/*
+ * Multi script
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: idiot@example.com
+To: idiot@example.org
+Subject: Frop!
+
+Frop.
+.
+;
+
+test_result_reset;
+test "Multi script" {
+ if not test_multiscript [
+ "execute/multiscript-before.sieve",
+ "execute/multiscript-personal.sieve",
+ "execute/multiscript-after.sieve"
+ ] {
+ test_fail "failed to run all scripts";
+ }
+
+ test_message :folder "INBOX" 0;
+
+ if not header "subject" "Frop!" {
+ test_fail "keep not executed.";
+ }
+
+ if not header "X-Before" "before" {
+ test_fail "No X-Before header";
+ }
+
+ if not header "X-Personal" "personal" {
+ test_fail "No X-Personal header";
+ }
+
+ if not header "X-After" "after" {
+ test_fail "No X-After header";
+ }
+}
diff --git a/pigeonhole/tests/extensions/editheader/execute/multiscript-after.sieve b/pigeonhole/tests/extensions/editheader/execute/multiscript-after.sieve
new file mode 100644
index 0000000..f11f02d
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/execute/multiscript-after.sieve
@@ -0,0 +1,4 @@
+require "editheader";
+
+addheader "X-After" "after";
+
diff --git a/pigeonhole/tests/extensions/editheader/execute/multiscript-before.sieve b/pigeonhole/tests/extensions/editheader/execute/multiscript-before.sieve
new file mode 100644
index 0000000..5c8a988
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/execute/multiscript-before.sieve
@@ -0,0 +1,4 @@
+require "editheader";
+
+addheader "X-Before" "before";
+
diff --git a/pigeonhole/tests/extensions/editheader/execute/multiscript-personal.sieve b/pigeonhole/tests/extensions/editheader/execute/multiscript-personal.sieve
new file mode 100644
index 0000000..92e82ac
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/execute/multiscript-personal.sieve
@@ -0,0 +1,4 @@
+require "editheader";
+
+addheader "X-Personal" "personal";
+
diff --git a/pigeonhole/tests/extensions/editheader/protected.svtest b/pigeonhole/tests/extensions/editheader/protected.svtest
new file mode 100644
index 0000000..148a9c8
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/protected.svtest
@@ -0,0 +1,173 @@
+require "vnd.dovecot.testsuite";
+
+require "variables";
+require "encoded-character";
+require "editheader";
+
+set "message" text:
+Received: by example.com (Postfix, from userid 202)
+ id 32A131WFW23QWE4; Mon, 21 Nov 2011 05:25:26 +0200 (EET)
+Delivery-date: Mon, 21 Nov 2011 04:26:04 +0100
+Auto-Submitted: yes
+X-Friep: frop 3
+Subject: Frop!
+From: stephan@example.com
+To: tss@example.com
+
+Frop!
+.
+;
+
+test_set "message" "${message}";
+test "Default protected" {
+ if not exists "received" {
+ test_fail "received header did not exist in the first place";
+ }
+
+ if not exists "auto-submitted" {
+ test_fail "auto-submitted header did not exist in the first place";
+ }
+
+ deleteheader "received";
+ deleteheader "auto-submitted";
+ deleteheader "subject";
+
+ if not exists "received" {
+ test_fail "protected received header was deleted";
+ }
+
+ if not exists "auto-submitted" {
+ test_fail "protected auto-submitted header was deleted";
+ }
+
+ if exists "subject" {
+ test_fail "subject header cannot be protected, but it was not deleted";
+ }
+}
+
+test_config_set "sieve_editheader_protected" "subject delivery-date x-frop";
+test_config_reload :extension "editheader";
+
+test_set "message" "${message}";
+test "Configured protected" {
+ if not exists "delivery-date" {
+ test_fail "received header did not exist in the first place";
+ }
+
+ if not exists "subject" {
+ test_fail "received header did not exist in the first place";
+ }
+
+ if exists "x-frop" {
+ test_fail "x-frop header already present";
+ }
+
+ deleteheader "delivery-date";
+ deleteheader "subject";
+ addheader "x-frop" "Frop!";
+
+ if not exists "delivery-date" {
+ test_fail "protected delivery-date header was deleted";
+ }
+
+ if exists "subject" {
+ test_fail "subject header cannot be protected, but it was not deleted";
+ }
+
+ if exists "x-frop" {
+ test_fail "protected x-frop header was added";
+ }
+}
+
+test_config_set "sieve_editheader_protected" "";
+test_config_set "sieve_editheader_forbid_add" "subject x-frop";
+test_config_set "sieve_editheader_forbid_delete" "subject x-friep";
+test_config_reload :extension "editheader";
+
+test_set "message" "${message}";
+test "Configured forbid_add/forbid_delete" {
+ if not exists "delivery-date" {
+ test_fail "received header did not exist in the first place";
+ }
+
+ if not exists "subject" {
+ test_fail "received header did not exist in the first place";
+ }
+
+ if not exists "x-friep" {
+ test_fail "x-friep header did not exist in the first place";
+ }
+
+ if exists "x-frop" {
+ test_fail "x-frop header already present";
+ }
+
+ deleteheader "delivery-date";
+ deleteheader "subject";
+ deleteheader "x-friep";
+
+ if exists "delivery-date" {
+ test_fail "unprotected delivery-date header was not deleted";
+ }
+
+ if exists "subject" {
+ test_fail "subject header cannot be protected, but it was not deleted";
+ }
+
+ if not exists "x-friep" {
+ test_fail "protected x-friep header was deleted";
+ }
+
+ addheader "delivery-date" "Yesterday";
+ addheader "subject" "Fropfrop!";
+ addheader "x-frop" "Frop!";
+ addheader "received" text:
+by sieve.example.com (My little Sieve script)
+id 3jhl22khhf23f; Mon, 24 Aug 2015 04:11:54 -0600;
+.
+;
+ addheader "auto-submitted" "no way";
+
+ if not header "delivery-date" "Yesterday" {
+ test_fail "unprotected delivery-date header was not added";
+ }
+
+ if not header "subject" "Fropfrop!" {
+ test_fail "subject header cannot be protected, but it was not added";
+ }
+
+ if exists "x-frop" {
+ test_fail "protected x-frop header was added";
+ }
+
+ if not header :contains "received" "sieve.example.com" {
+ test_fail "received header was not added";
+ }
+
+ if not header "auto-submitted" "no way" {
+ test_fail "autosubmitted header was not added";
+ }
+}
+
+/*
+ * TEST - Bad header configuration
+ */
+
+test_config_set "sieve_editheader_protected" "${unicode:1F4A9} delivery-date";
+test_config_reload :extension "editheader";
+
+test_set "message" "${message}";
+test "Bad header configuration" {
+ if not exists "delivery-date" {
+ test_fail "delivery-date header did not exist in the first place";
+ }
+
+ deleteheader "delivery-date";
+
+ if not exists "delivery-date" {
+ test_fail "protected delivery-date header was deleted";
+ }
+}
+
+test_config_set "sieve_editheader_protected" "";
+test_config_reload :extension "editheader";
diff --git a/pigeonhole/tests/extensions/editheader/utf8.svtest b/pigeonhole/tests/extensions/editheader/utf8.svtest
new file mode 100644
index 0000000..159a71c
--- /dev/null
+++ b/pigeonhole/tests/extensions/editheader/utf8.svtest
@@ -0,0 +1,97 @@
+require "vnd.dovecot.testsuite";
+
+require "encoded-character";
+require "variables";
+require "editheader";
+
+test_set "message" text:
+Subject: Frop!
+From: stephan@example.com
+To: stephan@example.com
+
+Frop!
+.
+;
+
+test "UTF8 - add; get" {
+ set "comment" "Ein unerh${unicode:00F6}rt gro${unicode:00DF}er Test";
+
+ addheader "Comment" "${comment}";
+
+ if not exists "comment" {
+ test_fail "header not added";
+ }
+
+ if not header :is "comment" "${comment}" {
+ test_fail "wrong content added/retrieved";
+ }
+
+ redirect "frop@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ /* redirected message */
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not exists "comment" {
+ test_fail "header not added in redirected mail";
+ }
+
+ if not header :is "comment" "${comment}" {
+ test_fail "wrong content added/retrieved from redirected mail";
+ }
+}
+
+test_result_reset;
+
+test_set "message" text:
+Subject: Frop!
+Comment: Ein =?utf-8?q?unerh=C3=B6rt_gro=C3=9Fer?= Test
+X-Spam: no
+From: stephan@example.com
+To: stephan@example.com
+
+Frop!
+.
+;
+
+test "UTF8 - existing; delete other; get" {
+ set "comment" "Ein unerh${unicode:00F6}rt gro${unicode:00DF}er Test";
+
+ deleteheader "x-spam";
+
+ if not exists "comment" {
+ test_fail "header not present";
+ }
+
+ if not header :is "comment" "${comment}" {
+ test_fail "wrong content retrieved";
+ }
+
+ redirect "frop@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ /* redirected message */
+
+ if not test_message :smtp 0 {
+ test_fail "message not redirected";
+ }
+
+ if not exists "comment" {
+ test_fail "header not present in redirected mail";
+ }
+
+ if not header :is "comment" "${comment}" {
+ test_fail "wrong content retrieved from redirected mail";
+ }
+}
+
+
diff --git a/pigeonhole/tests/extensions/encoded-character.svtest b/pigeonhole/tests/extensions/encoded-character.svtest
new file mode 100644
index 0000000..150d812
--- /dev/null
+++ b/pigeonhole/tests/extensions/encoded-character.svtest
@@ -0,0 +1,180 @@
+require "vnd.dovecot.testsuite";
+
+require "encoded-character";
+require "variables";
+
+test "HEX equality one" {
+ if not string "${hex:42}" "B" {
+ test_fail "failed to match the string 'B'";
+ }
+
+ if string "${hex:42}" "b" {
+ test_fail "matched nonsense";
+ }
+
+ if string "${hex:42}" "" {
+ test_fail "substitution failed";
+ }
+}
+
+test "HEX equality one middle" {
+ if not string " ${hex:42} " " B " {
+ test_fail "failed to match the string ' B '";
+ }
+
+ if string " ${hex:42} " " b " {
+ test_fail "matched nonsense";
+ }
+
+ if string " ${hex:42} " " " {
+ test_fail "substitution failed";
+ }
+}
+
+test "HEX equality one begin" {
+ if not string "${hex:42} " "B " {
+ test_fail "failed to match the string 'B '";
+ }
+
+ if string "${hex:42} " " b" {
+ test_fail "matched nonsense";
+ }
+
+ if string "${hex:42} " " " {
+ test_fail "substitution failed";
+ }
+}
+
+test "HEX equality one end" {
+ if not string " ${hex:42}" " B" {
+ test_fail "failed to match the string ' B'";
+ }
+
+ if string " ${hex:42}" " b " {
+ test_fail "matched nonsense";
+ }
+
+ if string " ${hex:42}" " " {
+ test_fail "substitution failed";
+ }
+}
+
+test "HEX equality two triple" {
+ if not string "${hex:42 61 64}${hex: 61 73 73}" "Badass" {
+ test_fail "failed to match the string 'Badass'";
+ }
+
+ if string "${hex:42 61 64}${hex: 61 73 73}" "Sadass" {
+ test_fail "matched nonsense";
+ }
+
+ if string "${hex:42 61 64}${hex: 61 73 73}" "" {
+ test_fail "substitution failed";
+ }
+}
+
+test "HEX equality braindead" {
+ if not string "${hex:42 72 61 69 6E 64 65 61 64}" "Braindead" {
+ test_fail "failed to match the string 'Braindead'";
+ }
+
+ if string "${hex:42 72 61 69 6E 64 65 61 64}" "Brian Nut" {
+ test_fail "matched nonsense";
+ }
+}
+
+test "Syntax errors" {
+ if anyof( not string "$" "${hex:24}", not string "$ " "${hex:24} ", not string " $" " ${hex:24}" ) {
+ test_fail "loose $ handled inappropriately";
+ }
+
+ if anyof( not string "${" "${hex:24}{", not string "a${" "a${hex:24}{", not string "${a" "${hex:24}{a" ) {
+ test_fail "loose ${ handled inappropriately";
+ }
+
+ if anyof( not string "${}" "${hex:24}{}", not string "b${}" "b${hex:24}{}", not string "${}b" "${hex:24}{}b" ) {
+ test_fail "entirely missing content handled inappropriately";
+ }
+
+ if not string "${:}" "${hex:24}{:}" {
+ test_fail "missing content handled inappropriately";
+ }
+
+ if not string "${hex:}" "${hex:24}{hex:}" {
+ test_fail "missing hex content handled inappropriately";
+ }
+
+ if not string "${unicode:}" "${hex:24}{unicode:}" {
+ test_fail "missing unicode content handled inappropriately";
+ }
+
+ if not string "${hex:sss}" "${hex:24}{hex:sss}" {
+ test_fail "erroneous hex content handled inappropriately";
+ }
+
+ if not string "${unicode:ttt}" "${hex:24}{unicode:ttt}" {
+ test_fail "erroneous unicode content handled inappropriately";
+ }
+
+ if not string "${hex:aa aa" "${hex:24}{hex:aa aa" {
+ test_fail "unterminated hex content handled inappropriately";
+ }
+
+ if not string "${unicode: aaaa aaaa" "${hex:24}{unicode: aaaa aaaa" {
+ test_fail "unterminated unicode content handled inappropriately";
+ }
+}
+
+/*
+ * RFC Examples
+ */
+
+test "RFC Examples" {
+ if not string "$${hex:40}" "$@" {
+ test_fail "failed RFC example 1";
+ }
+
+ if not string "${hex: 40 }" "@" {
+ test_fail "failed RFC example 2";
+ }
+
+ if not string "${HEX: 40}" "@" {
+ test_fail "failed RFC example 3";
+ }
+
+ if not string "${hex:40" "${hex:40" {
+ test_fail "failed RFC example 4";
+ }
+
+ if not string "${hex:400}" "${hex:400}" {
+ test_fail "failed RFC example 5";
+ }
+
+ if not string "${hex:4${hex:30}}" "${hex: 24}{hex:40}" {
+ test_fail "failed RFC example 6";
+ }
+
+ if not string "${unicode:40}" "@" {
+ test_fail "failed RFC example 7";
+ }
+
+ if not string "${ unicode:40}" "${ unicode:40}" {
+ test_fail "failed RFC example 8";
+ }
+
+ if not string "${UNICODE:40}" "@" {
+ test_fail "failed RFC example 9";
+ }
+
+ if not string "${UnICoDE:0000040}" "@" {
+ test_fail "failed RFC example 10";
+ }
+
+ if not string "${Unicode:40}" "@" {
+ test_fail "failed RFC example 11";
+ }
+
+ if not string "${Unicode:Cool}" "${Unicode:Cool}" {
+ test_fail "failed RFC example 12";
+ }
+}
diff --git a/pigeonhole/tests/extensions/enotify/basic.svtest b/pigeonhole/tests/extensions/enotify/basic.svtest
new file mode 100644
index 0000000..2a03aee
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/basic.svtest
@@ -0,0 +1,15 @@
+require "vnd.dovecot.testsuite";
+require "enotify";
+
+test "Execute" {
+ /* Test to catch runtime segfaults */
+ if valid_notify_method
+ "mailto:stephan@example.com" {
+
+ /* Test to catch runtime segfaults */
+ notify
+ :message "This is probably very important"
+ :importance "1"
+ "mailto:stephan@example.com%2cstephan@example.org?subject=Important%20message%20received";
+ }
+}
diff --git a/pigeonhole/tests/extensions/enotify/encodeurl.svtest b/pigeonhole/tests/extensions/enotify/encodeurl.svtest
new file mode 100644
index 0000000..d334dd3
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/encodeurl.svtest
@@ -0,0 +1,359 @@
+require "vnd.dovecot.testsuite";
+require "encoded-character";
+require "variables";
+require "enotify";
+
+/*
+ * :encodeurl simple
+ */
+
+test ":encodeurl simple" {
+ set :encodeurl "url_data" "\\frop\\&fruts/^@";
+
+ if not string :is :comparator "i;octet" "${url_data}" "%5Cfrop%5C%26fruts%2F%5E%40" {
+ test_fail "url data encoded incorrectly '${url_data}'";
+ }
+}
+
+/*
+ * :encodeurl variable size limit
+ */
+
+test_config_set "sieve_variables_max_variable_size" "4000";
+test_config_reload :extension "variables";
+
+set "a" text:
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@
+.
+;
+
+test ":encodeurl variable size limit" {
+ set :length "alen" "${a}";
+
+ if not string "${alen}" "4000" {
+ test_fail "variable 'a' not 4000 bytes long (${alen})";
+ }
+
+ set :encodeurl "b" "${a}";
+ set :length "blen" "${b}";
+
+ if not string "${blen}" "3999" {
+ test_fail "variable 'b' not 3999 bytes long (${blen})";
+ }
+
+ set :encodeurl "c" "0${a}";
+ set :length "clen" "${c}";
+
+ if not string "${clen}" "4000" {
+ test_fail "variable 'c' not 4000 bytes long (${clen})";
+ }
+
+ set "cmt" "%40%40%40%40%40%40%40%40%40%40%40%40";
+ set "cmt" "${cmt}%40%40%40%40%40%40%40%40%40%40%40%0D%0A";
+ set "cmh" "${cmt}${cmt}${cmt}${cmt}";
+ set "cm" "${cmh}${cmh}${cmh}${cmh}${cmh}${cmh}${cmh}${cmh}${cmh}${cmh}";
+ set "cm" "${cm}${cmh}${cmh}${cmh}";
+ set "cm" "0${cm}${cmt}%40%40%40%40%40%40%40%40";
+
+ if not string :is "${c}" "${cm}" {
+ test_fail "variable 'c' has unexpected value";
+ }
+
+ set :encodeurl "d" "00${a}";
+ set :length "dlen" "${d}";
+
+ if not string "${dlen}" "3998" {
+ test_fail "variable 'd' not 3998 bytes long (${dlen})";
+ }
+}
+
+/*
+ * :encodeurl variable size limit UTF-8
+ */
+
+test_config_set "sieve_variables_max_variable_size" "4000";
+test_config_reload :extension "variables";
+
+set "a" text:
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}${unicode:4e03}
+.
+;
+
+test ":encodeurl variable size limit UTF-8" {
+ set :length "alen" "${a}";
+
+ if not string "${alen}" "546" {
+ test_fail "variable 'a' not 549 characters long (${alen})";
+ }
+
+ set :encodeurl "b" "${a}";
+ set :length "blen" "${b}";
+
+ if not string "${blen}" "3978" {
+ test_fail "variable 'b' not 3978 bytes long (${blen})";
+ }
+
+ set :encodeurl "c" "${a}${unicode:4e00}${unicode:4e00}";
+ set :length "clen" "${c}";
+
+ if not string "${clen}" "3996" {
+ test_fail "variable 'c' not 3996 bytes long (${clen})";
+ }
+
+ set :encodeurl "d" "${a}${unicode:4e00}${unicode:4e00}${unicode:4e00}";
+ set :length "dlen" "${d}";
+
+ if not string "${dlen}" "3996" {
+ test_fail "variable 'd' not 3996 bytes long (${dlen})";
+ }
+
+ set :encodeurl "e" "0000${a}${unicode:4e00}${unicode:4e00}";
+ set :length "elen" "${e}";
+
+ if not string "${elen}" "4000" {
+ test_fail "variable 'e' not 4000 bytes long (${elen})";
+ }
+
+ set :encodeurl "f" "00000${a}${unicode:4e00}${unicode:4e00}";
+ set :length "flen" "${f}";
+
+ if not string "${flen}" "3992" {
+ test_fail "variable 'f' not 3992 bytes long (${flen})";
+ }
+}
diff --git a/pigeonhole/tests/extensions/enotify/errors.svtest b/pigeonhole/tests/extensions/enotify/errors.svtest
new file mode 100644
index 0000000..5af36df
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/errors.svtest
@@ -0,0 +1,45 @@
+require "vnd.dovecot.testsuite";
+require "comparator-i;ascii-numeric";
+require "relational";
+
+require "enotify";
+
+test "Invalid URI (FIXME: count only)" {
+ if test_script_compile "errors/uri.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "2" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Invalid mailto URI (FIXME: count only)" {
+ if test_script_compile "errors/uri-mailto.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "7" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Invalid mailto :from address (FIXME: count only)" {
+ if test_script_compile "errors/from-mailto.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Invalid :options argument (FIXME: count only)" {
+ if test_script_compile "errors/options.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "6" {
+ test_fail "wrong number of errors reported";
+ }
+}
diff --git a/pigeonhole/tests/extensions/enotify/errors/from-mailto.sieve b/pigeonhole/tests/extensions/enotify/errors/from-mailto.sieve
new file mode 100644
index 0000000..d519256
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/errors/from-mailto.sieve
@@ -0,0 +1,7 @@
+require "enotify";
+
+# 1: Invalid from address
+notify :from "stephan#example.org" "mailto:stephan@example.com";
+
+# 2: Empty from address
+notify :from "" "mailto:stephan@example.com";
diff --git a/pigeonhole/tests/extensions/enotify/errors/options.sieve b/pigeonhole/tests/extensions/enotify/errors/options.sieve
new file mode 100644
index 0000000..58d2265
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/errors/options.sieve
@@ -0,0 +1,18 @@
+require "enotify";
+
+# 1: empty option
+notify :options "" "mailto:stephan@example.org";
+
+# 2: invalid option name syntax
+notify :options "frop" "mailto:stephan@example.org";
+
+# 3: invalid option name syntax
+notify :options "_frop=" "mailto:stephan@example.org";
+
+# 4: invalid option name syntax
+notify :options "=frop" "mailto:stephan@example.org";
+
+# 5: invalid value
+notify :options "frop=frml
+frop" "mailto:stephan@example.org";
+
diff --git a/pigeonhole/tests/extensions/enotify/errors/uri-mailto.sieve b/pigeonhole/tests/extensions/enotify/errors/uri-mailto.sieve
new file mode 100644
index 0000000..2aced86
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/errors/uri-mailto.sieve
@@ -0,0 +1,20 @@
+require "enotify";
+
+# 1: Invalid character in to part
+notify "mailto:stephan@example.org;?header=frop";
+
+# 2: Invalid character in hname
+notify "mailto:stephan@example.org?header<=frop";
+
+# 3: Invalid character in hvalue
+notify "mailto:stephan@example.org?header=fr>op";
+
+# 4: Invalid header name
+notify "mailto:stephan@example.org?header:=frop";
+
+# 5: Invalid recipient
+notify "mailto:stephan%23example.org";
+
+# 6: Invalid to header recipient
+notify "mailto:stephan@example.org?to=nico%23frop.example.org";
+
diff --git a/pigeonhole/tests/extensions/enotify/errors/uri.sieve b/pigeonhole/tests/extensions/enotify/errors/uri.sieve
new file mode 100644
index 0000000..13ead81
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/errors/uri.sieve
@@ -0,0 +1,5 @@
+require "enotify";
+
+# 1: Invalid url scheme
+notify "snailto:stephan@example.org";
+
diff --git a/pigeonhole/tests/extensions/enotify/execute.svtest b/pigeonhole/tests/extensions/enotify/execute.svtest
new file mode 100644
index 0000000..cd6486d
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/execute.svtest
@@ -0,0 +1,99 @@
+require "vnd.dovecot.testsuite";
+require "relational";
+
+
+/*
+ * Execution testing (currently just meant to trigger any segfaults)
+ */
+
+test "RFC Example 1" {
+ if not test_script_compile "execute/draft-rfc-ex1.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script run failed";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+}
+
+test "RFC Example 2" {
+ if not test_script_compile "execute/draft-rfc-ex2.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script execute failed";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+}
+
+/* tel: not supported
+test "RFC Example 3" {
+ if not test_script_compile "execute/draft-rfc-ex3.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script execute failed";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+}
+*/
+
+/* tel: and xmmp: not supported
+test "RFC Example 5" {
+ if not test_script_compile "execute/draft-rfc-ex5.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script execute failed";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+}
+*/
+
+test "RFC Example 6" {
+ if not test_script_compile "execute/draft-rfc-ex6.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script execute failed";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+}
+
+test "Duplicate recipients" {
+ if not test_script_compile "execute/duplicates.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script execute failed";
+ }
+
+ if test_result_action :count "ne" "2" {
+ test_fail "second notify action was discarded entirely";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+}
diff --git a/pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex1.sieve b/pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex1.sieve
new file mode 100644
index 0000000..6747d7b
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex1.sieve
@@ -0,0 +1,26 @@
+require ["enotify", "fileinto", "variables"];
+
+if header :contains "from" "boss@example.org" {
+ notify :importance "1"
+ :message "This is probably very important"
+ "mailto:alm@example.com";
+ # Don't send any further notifications
+ stop;
+}
+
+if header :contains "to" "sievemailinglist@example.org" {
+ # :matches is used to get the value of the Subject header
+ if header :matches "Subject" "*" {
+ set "subject" "${1}";
+ }
+
+ # :matches is used to get the value of the From header
+ if header :matches "From" "*" {
+ set "from" "${1}";
+ }
+
+ notify :importance "3"
+ :message "[SIEVE] ${from}: ${subject}"
+ "mailto:alm@example.com";
+ fileinto "INBOX.sieve";
+}
diff --git a/pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex2.sieve b/pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex2.sieve
new file mode 100644
index 0000000..a5c6a26
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex2.sieve
@@ -0,0 +1,22 @@
+require ["enotify", "fileinto", "variables", "envelope"];
+
+if header :matches "from" "*@*.example.org" {
+ # :matches is used to get the MAIL FROM address
+ if envelope :all :matches "from" "*" {
+ set "env_from" " [really: ${1}]";
+ }
+
+ # :matches is used to get the value of the Subject header
+ if header :matches "Subject" "*" {
+ set "subject" "${1}";
+ }
+
+ # :matches is used to get the address from the From header
+ if address :matches :all "from" "*" {
+ set "from_addr" "${1}";
+ }
+
+ notify :message "${from_addr}${env_from}: ${subject}"
+ "mailto:alm@example.com";
+}
+
diff --git a/pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex3.sieve b/pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex3.sieve
new file mode 100644
index 0000000..a7b4a64
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex3.sieve
@@ -0,0 +1,31 @@
+require ["enotify", "variables"];
+
+set "notif_method"
+ "xmpp:tim@example.com?message;subject=SIEVE;body=You%20got%20mail";
+
+if header :contains "subject" "Your dog" {
+ set "notif_method" "tel:+14085551212";
+}
+
+if header :contains "to" "sievemailinglist@example.org" {
+ set "notif_method" "";
+}
+
+if not string :is "${notif_method}" "" {
+ notify "${notif_method}";
+}
+
+if header :contains "from" "boss@example.org" {
+ # :matches is used to get the value of the Subject header
+ if header :matches "Subject" "*" {
+ set "subject" "${1}";
+ }
+
+ # don't need high importance notification for
+ # a 'for your information'
+ if not header :contains "subject" "FYI:" {
+ notify :importance "1" :message "BOSS: ${subject}"
+ "tel:+14085551212";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex5.sieve b/pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex5.sieve
new file mode 100644
index 0000000..c6b7dc6
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex5.sieve
@@ -0,0 +1,11 @@
+require ["enotify"];
+
+if notify_method_capability
+ "xmpp:tim@example.com?message;subject=SIEVE"
+ "Online"
+ "yes" {
+ notify :importance "1" :message "You got mail"
+ "xmpp:tim@example.com?message;subject=SIEVE";
+} else {
+ notify :message "You got mail" "tel:+14085551212";
+}
diff --git a/pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex6.sieve b/pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex6.sieve
new file mode 100644
index 0000000..6a65c64
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/execute/draft-rfc-ex6.sieve
@@ -0,0 +1,5 @@
+require ["enotify", "variables"];
+
+set :encodeurl "body_param" "Safe body&evil=evilbody";
+
+notify "mailto:tim@example.com?body=${body_param}";
diff --git a/pigeonhole/tests/extensions/enotify/execute/duplicates.sieve b/pigeonhole/tests/extensions/enotify/execute/duplicates.sieve
new file mode 100644
index 0000000..17f2388
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/execute/duplicates.sieve
@@ -0,0 +1,4 @@
+require "enotify";
+
+notify :message "Incoming stupidity." "mailto:stephan@example.org%2cstephan@friep.example.com%2cidiot@example.org";
+notify :message "There it is." "mailto:tss@example.net%2cstephan@example.org%2cidiot@example.org%2cnico@frop.example.org%2cstephan@friep.example.com";
diff --git a/pigeonhole/tests/extensions/enotify/mailto.svtest b/pigeonhole/tests/extensions/enotify/mailto.svtest
new file mode 100644
index 0000000..68d8daa
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/mailto.svtest
@@ -0,0 +1,541 @@
+require "vnd.dovecot.testsuite";
+require "enotify";
+require "relational";
+require "envelope";
+require "variables";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Simple test
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "Simple" {
+ notify "mailto:stephan@example.org";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not header :matches "Auto-Submitted" "auto-notified*" {
+ test_fail "auto-submitted header set inappropriately";
+ }
+
+ if not exists "X-Sieve" {
+ test_fail "x-sieve header missing from outgoing message";
+ }
+
+ if anyof (
+ not header :matches "x-priority" "3 *",
+ not header "importance" "normal") {
+
+ test_fail "default priority is not normal";
+ }
+}
+
+/*
+ * Multiple recipients
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "Multiple recipients" {
+ notify "mailto:timo@example.com%2cstephan@dovecot.example.net?cc=postmaster@frop.example.org&subject=Frop%20received";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not address :is "to" "timo@example.com" {
+ test_fail "first To address missing";
+ }
+
+ if not address :is "to" "stephan@dovecot.example.net" {
+ test_fail "second To address missing";
+ }
+
+ if not address :is "cc" "postmaster@frop.example.org" {
+ test_fail "first Cc address missing";
+ }
+
+ if not address :count "eq" :comparator "i;ascii-numeric" "to" "2" {
+ test_fail "too many recipients in To header";
+ }
+
+ if not address :count "eq" :comparator "i;ascii-numeric" "cc" "1" {
+ test_fail "too many recipients in Cc header";
+ }
+
+ if not header "subject" "Frop received" {
+ test_fail "subject header set incorrectly";
+ }
+
+ test_message :smtp 1;
+
+ if not header :matches "Auto-Submitted" "auto-notified*" {
+ test_fail "auto-submitted header not found for second message";
+ }
+
+ test_message :smtp 2;
+
+ if not header :matches "Auto-Submitted" "auto-notified*" {
+ test_fail "auto-submitted header not found for third message";
+ }
+}
+
+/*
+ * Duplicate recipients
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "Duplicate recipients" {
+ notify "mailto:timo@example.com%2cstephan@dovecot.example.net?cc=stephan@dovecot.example.net";
+ notify "mailto:stephan@example.org?cc=timo@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if address "Cc" "stephan@dovecot.example.net" {
+ test_fail "duplicate recipient not removed from first message";
+ }
+
+ test_message :smtp 1;
+
+ if address "Cc" "timo@example.com" {
+ test_fail "duplicate recipient not removed from second message";
+ }
+}
+
+
+/*
+ * Notifying on automated messages
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Auto-submitted: auto-notify
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "Notifying on automated messages" {
+ notify "mailto:stephan@example.org?cc=timo@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "notified of auto-submitted message";
+ }
+}
+
+/*
+ * Envelope
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test_result_reset;
+
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "bertus@frop.example.org";
+
+test "Envelope" {
+ notify "mailto:stephan@example.org?cc=timo@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not envelope :localpart :is "from" "postmaster" {
+ test_fail "envelope sender set incorrectly";
+ }
+
+ if not envelope :is "to" "stephan@example.org" {
+ test_fail "envelope sender set incorrectly";
+ }
+
+ test_message :smtp 1;
+
+ if not envelope :localpart :is "from" "postmaster" {
+ test_fail "envelope sender set incorrectly";
+ }
+
+ if not envelope :is "to" "timo@example.com" {
+ test_fail "envelope sender set incorrectly";
+ }
+}
+
+/*
+ * Envelope :from
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "bertus@frop.example.org";
+
+test_result_reset;
+
+test "Envelope :from" {
+ notify :from "nico@frop.example.org"
+ "mailto:stephan@example.org?cc=timo@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not envelope :is "from" "nico@frop.example.org" {
+ test_fail "envelope sender set incorrectly";
+ }
+
+ if not envelope :is "to" "stephan@example.org" {
+ test_fail "envelope sender set incorrectly";
+ }
+
+ test_message :smtp 1;
+
+ if not envelope :is "from" "nico@frop.example.org" {
+ test_fail "envelope sender set incorrectly";
+ }
+
+ if not envelope :is "to" "timo@example.com" {
+ test_fail "envelope sender set incorrectly";
+ }
+}
+
+/*
+ * Envelope <>
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test_set "envelope.from" "<>";
+test_set "envelope.to" "bertus@frop.example.org";
+
+test_result_reset;
+
+test "Envelope <>" {
+ notify :from "nico@frop.example.org"
+ "mailto:stephan@example.org?cc=timo@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not envelope :is "from" "" {
+ test_fail "envelope sender set incorrectly";
+ }
+
+ if not envelope :is "to" "stephan@example.org" {
+ test_fail "envelope recipient set incorrectly";
+ }
+
+ test_message :smtp 1;
+
+ if not envelope :is "from" "" {
+ test_fail "envelope sender set incorrectly";
+ }
+
+ if not envelope :is "to" "timo@example.com" {
+ test_fail "envelope recipient set incorrectly";
+ }
+}
+
+/*
+ * Envelope config - sender
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "bertus@frop.example.org";
+
+test_config_set "sieve_notify_mailto_envelope_from"
+ "sender";
+test_config_reload :extension "enotify";
+test_result_reset;
+
+test "Envelope config - sender" {
+ notify :from "nico@frop.example.org"
+ "mailto:stephan@example.org?cc=timo@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not header :is "from" "nico@frop.example.org" {
+ test_fail "from set incorrectly";
+ }
+
+ if not envelope :is "from" "sirius@example.org" {
+ test_fail "envelope sender set incorrectly";
+ }
+
+ if not envelope :is "to" "stephan@example.org" {
+ test_fail "envelope recipient set incorrectly";
+ }
+
+ test_message :smtp 1;
+
+ if not header :is "from" "nico@frop.example.org" {
+ test_fail "from set incorrectly";
+ }
+
+ if not envelope :is "from" "sirius@example.org" {
+ test_fail "envelope sender set incorrectly";
+ }
+
+ if not envelope :is "to" "timo@example.com" {
+ test_fail "envelope recipient set incorrectly";
+ }
+}
+
+/*
+ * Envelope config - recipient
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "bertus@frop.example.org";
+
+test_config_set "sieve_notify_mailto_envelope_from"
+ "recipient";
+test_config_reload :extension "enotify";
+test_result_reset;
+
+test "Envelope config - recipient" {
+ notify :from "nico@frop.example.org"
+ "mailto:stephan@example.org?cc=timo@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not header :is "from" "nico@frop.example.org" {
+ test_fail "from set incorrectly";
+ }
+
+ if not envelope :is "from" "bertus@frop.example.org" {
+ test_fail "envelope sender set incorrectly";
+ }
+
+ if not envelope :is "to" "stephan@example.org" {
+ test_fail "envelope recipient set incorrectly";
+ }
+
+ test_message :smtp 1;
+
+ if not header :is "from" "nico@frop.example.org" {
+ test_fail "from set incorrectly";
+ }
+
+ if not envelope :is "from" "bertus@frop.example.org" {
+ test_fail "envelope sender set incorrectly";
+ }
+
+ if not envelope :is "to" "timo@example.com" {
+ test_fail "envelope recipient set incorrectly";
+ }
+}
+
+/*
+ * Envelope config - user_email
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "bertus@frop.example.org";
+
+test_config_set "sieve_notify_mailto_envelope_from"
+ "user_email";
+test_config_set "sieve_user_email" "b.wortel@example.org";
+test_config_reload;
+test_config_reload :extension "enotify";
+test_result_reset;
+
+test "Envelope config - user_email" {
+ notify :from "nico@frop.example.org"
+ "mailto:stephan@example.org?cc=timo@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not header :is "from" "nico@frop.example.org" {
+ test_fail "from set incorrectly";
+ }
+
+ if not envelope :is "from" "b.wortel@example.org" {
+ test_fail "envelope sender set incorrectly";
+ }
+
+ if not envelope :is "to" "stephan@example.org" {
+ test_fail "envelope recipient set incorrectly";
+ }
+
+ test_message :smtp 1;
+
+ if not header :is "from" "nico@frop.example.org" {
+ test_fail "from set incorrectly";
+ }
+
+ if not envelope :is "from" "b.wortel@example.org" {
+ test_fail "envelope sender set incorrectly";
+ }
+
+ if not envelope :is "to" "timo@example.com" {
+ test_fail "envelope recipient set incorrectly";
+ }
+}
+
+/*
+ * UTF-8 addresses
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "UTF-8 address" {
+ set "to" "=?utf-8?q?G=C3=BCnther?= M. Karotte <g.m.karotte@example.com>";
+ set "cc" "Dieter T. =?utf-8?q?Stoppelr=C3=BCbe?= <d.t.stoppelruebe@example.com>";
+
+ set :encodeurl "to_enc" "${to}";
+ set :encodeurl "cc_enc" "${cc}";
+
+ notify "mailto:?to=${to_enc}&cc=${cc_enc}";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ set "expected" "Günther M. Karotte <g.m.karotte@example.com>";
+ if not header :is "to" "${expected}" {
+ if header :matches "to" "*" { set "decoded" "${1}"; }
+
+ test_fail text:
+to header is not encoded/decoded properly:
+expected: ${expected}
+decoded: ${decoded}
+.
+;
+ }
+
+ set "expected" "Dieter T. Stoppelrübe <d.t.stoppelruebe@example.com>";
+ if not header :is "cc" "${expected}" {
+ if header :matches "cc" "*" { set "decoded" "${1}"; }
+
+ test_fail text:
+to header is not encoded/decoded properly:
+expected: ${expected}
+decoded: ${decoded}
+.
+;
+ }
+}
diff --git a/pigeonhole/tests/extensions/enotify/notify_method_capability.svtest b/pigeonhole/tests/extensions/enotify/notify_method_capability.svtest
new file mode 100644
index 0000000..0d13477
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/notify_method_capability.svtest
@@ -0,0 +1,12 @@
+require "vnd.dovecot.testsuite";
+require "enotify";
+
+test "Mailto" {
+ if not notify_method_capability :is "mailto:stephan@example.org" "online" "maybe" {
+ test_fail "test should have matched";
+ }
+
+ if notify_method_capability :is "mailto:stephan@example.org" "online" "yes" {
+ test_fail "test should not have matched";
+ }
+}
diff --git a/pigeonhole/tests/extensions/enotify/valid_notify_method.svtest b/pigeonhole/tests/extensions/enotify/valid_notify_method.svtest
new file mode 100644
index 0000000..35255d6
--- /dev/null
+++ b/pigeonhole/tests/extensions/enotify/valid_notify_method.svtest
@@ -0,0 +1,31 @@
+require "vnd.dovecot.testsuite";
+
+require "enotify";
+
+test "Mailto: invalid header name" {
+ if valid_notify_method
+ "mailto:stephan@example.org?header:=frop" {
+ test_fail "invalid uri accepted";
+ }
+}
+
+test "Mailto: invalid recipient" {
+ if valid_notify_method
+ "mailto:stephan%23example.org" {
+ test_fail "invalid uri accepted";
+ }
+}
+
+test "Mailto: invalid to header recipient" {
+ if valid_notify_method
+ "mailto:stephan@example.org?to=nico%23frop.example.org" {
+ test_fail "invalid uri accepted";
+ }
+}
+
+test "Mailto: valid URI" {
+ if not valid_notify_method
+ "mailto:stephan@example.org" {
+ test_fail "valid uri denied";
+ }
+}
diff --git a/pigeonhole/tests/extensions/envelope.svtest b/pigeonhole/tests/extensions/envelope.svtest
new file mode 100644
index 0000000..9cf3b8b
--- /dev/null
+++ b/pigeonhole/tests/extensions/envelope.svtest
@@ -0,0 +1,244 @@
+require "vnd.dovecot.testsuite";
+
+require "envelope";
+
+/*
+ * Empty envelope addresses
+ */
+
+/* RFC 5228, Section 5.4: The null reverse-path is matched against as the empty
+ * string, regardless of the ADDRESS-PART argument specified.
+ */
+
+test "Envelope - from empty" {
+ /* Return_path: "" */
+
+ test_set "envelope.from" "";
+
+ if not envelope :all :is "from" "" {
+ test_fail "failed to (:all :is)-match a \"\" return path";
+ }
+
+ if not envelope :all :contains "from" "" {
+ test_fail "failed to (:all :contains)-match a \"\" return path";
+ }
+
+ if not envelope :domain :is "from" "" {
+ test_fail "failed to (:domain :is)-match a \"\" return path";
+ }
+
+ if not envelope :domain :contains "from" "" {
+ test_fail "failed to (:domain :contains)-match a \"\" return path";
+ }
+
+ /* Return path: <> */
+
+ test_set "envelope.from" "<>";
+
+ if not envelope :all :is "from" "" {
+ test_fail "failed to (:all :is)-match a <> return path";
+ }
+
+ if not envelope :all :contains "from" "" {
+ test_fail "failed to (:all :contains)-match a <> return path";
+ }
+
+ if not envelope :domain :is "from" "" {
+ test_fail "failed to (:domain :is)-match a <> return path";
+ }
+
+ if not envelope :domain :contains "from" "" {
+ test_fail "failed to (:domain :contains)-match a <> return path";
+ }
+
+ if envelope :all :is "from" "nico@frop.example.org" {
+ test_fail "envelope test matches nonsense";
+ }
+}
+
+/*
+ * Invalid envelope addresses
+ */
+
+test "Envelope - invalid paths" {
+ /* Return_path: "hutsefluts" */
+
+ test_set "envelope.from" "hutsefluts@";
+ test_set "envelope.to" "knurft@";
+
+ if envelope :all :is "from" "hutsefluts@" {
+ test_fail ":all address part matched syntactically incorrect reverse path";
+ }
+ if envelope :all :is "to" "knurft@" {
+ test_fail ":all address part matched syntactically incorrect forward path";
+ }
+}
+
+/*
+ * Syntax errors
+ */
+
+test "Envelope - syntax errors" {
+ /* Control */
+ test_set "envelope.from" "<stephan@example.org>";
+ if not envelope :all :is "from" "stephan@example.org" {
+ test_fail "correct control test failed";
+ }
+
+ # Duplicate <
+ test_set "envelope.from" "<<stephan@example.org>";
+ if envelope :all :is "from" "stephan@example.org" {
+ test_fail "failed to recognize syntax error (1)";
+ }
+
+ # Spurious >
+ test_set "envelope.from" "stephan@example.org>";
+ if envelope :all :is "from" "stephan@example.org" {
+ test_fail "failed to recognize syntax error (2)";
+ }
+
+ # Missing >
+ test_set "envelope.from" "<stephan@example.org";
+ if envelope :all :is "from" "stephan@example.org" {
+ test_fail "failed to recognize syntax error (3)";
+ }
+
+ # No @
+ test_set "envelope.from" "<stephan example.org>";
+ if envelope :domain :contains "from" "example" {
+ test_fail "failed to recognize syntax error (4)";
+ }
+
+ # Duplicate @
+ test_set "envelope.from" "<stephan@@example.org>";
+ if envelope :domain :contains "from" "example" {
+ test_fail "failed to recognize syntax error (5)";
+ }
+}
+
+/*
+ * Ignoring source routes
+ */
+
+test "Envelope - source route" {
+ /* Single */
+ test_set "envelope.from" "<@cola.example.org:stephan@example.org>";
+ if not envelope :localpart :is "from" "stephan" {
+ test_fail "parsing path with source route (single) failed";
+ }
+
+ /* Dual */
+ test_set "envelope.from" "<@cola.example.org,@mx.utwente.nl:stephan@example.org>";
+ if not envelope :localpart :is "from" "stephan" {
+ test_fail "parsing path with source route (dual) failed";
+ }
+
+ /* Multiple */
+ test_set "envelope.from" "<@cola.example.org,@mx.utwente.nl,@smtp.example.net:stephan@example.org>";
+ if not envelope :localpart :is "from" "stephan" {
+ test_fail "parsing path with source route (multiple) failed";
+ }
+}
+
+test "Envelope - source route errors" {
+ test_set "envelope.to" "<cola.example.org:stephan@example.org>";
+ if envelope :domain :contains "to" "" {
+ test_fail "parsing syntactically incorrect path should have failed (1)";
+ }
+
+ test_set "envelope.to" "<@.example.org:stephan@example.org>";
+ if envelope :domain :contains "to" "" {
+ test_fail "parsing syntactically incorrect path should have failed (2)";
+ }
+
+ test_set "envelope.to" "<@cola..nl:stephan@example.org>";
+ if envelope :domain :contains "to" "" {
+ test_fail "parsing syntactically incorrect path should have failed (3)";
+ }
+
+ test_set "envelope.to" "<@cola.example.orgstephan@example.org>";
+ if envelope :domain :contains "to" "" {
+ test_fail "parsing syntactically incorrect path should have failed (4)";
+ }
+
+ test_set "envelope.to" "<@cola.example.org@mx.utwente.nl:stephan@example.org>";
+ if envelope :domain :contains "to" "" {
+ test_fail "parsing syntactically incorrect path should have failed (5)";
+ }
+
+ test_set "envelope.to" "<@cola.example.org,mx.utwente.nl:stephan@example.org>";
+ if envelope :domain :contains "to" "" {
+ test_fail "parsing syntactically incorrect path should have failed (6)";
+ }
+
+ test_set "envelope.to" "<@cola.example.org,@mx.utwente.nl,stephan@example.org>";
+ if envelope :domain :contains "to" "" {
+ test_fail "parsing syntactically incorrect path should have failed (7)";
+ }
+}
+
+test "Envelope - local part only" {
+ test_set "envelope.to" "<MAILER-DAEMON>";
+ if not envelope :is "to" "MAILER-DAEMON" {
+ test_fail "failed to parse local_part only path";
+ }
+
+ test_set "envelope.to" "MAILER-DAEMON@";
+ if envelope :is "to" "MAILER-DAEMON" {
+ test_fail "parsing syntactically incorrect path with missing domain";
+ }
+
+ test_set "envelope.to" "<MAILER-DAEMON>";
+ if not envelope :is "to" "MAILER-DAEMON" {
+ test_fail "failed to parse local_part only path with angle brackets";
+ }
+}
+
+test "Envelope - Japanese localpart" {
+ test_set "envelope.to" ".japanese@example.com";
+ if not envelope :localpart :is "to" ".japanese" {
+ test_fail "failed to parse japanese local_part (1)";
+ }
+
+ test_set "envelope.to" "japanese.@example.com";
+ if not envelope :localpart :is "to" "japanese." {
+ test_fail "failed to parse japanese local_part (2)";
+ }
+
+ test_set "envelope.to" "japanese...localpart@example.com";
+ if not envelope :localpart :is "to" "japanese...localpart" {
+ test_fail "failed to parse japanese local_part (3)";
+ }
+
+ test_set "envelope.to" "..japanese...localpart..@example.com";
+ if not envelope :localpart :is "to" "..japanese...localpart.." {
+ test_fail "failed to parse japanese local_part (4)";
+ }
+}
+
+test "Envelope - Non-standard hostnames" {
+ test_set "envelope.to" "japanese@_example.com";
+ if not envelope :domain :is "to" "_example.com" {
+ test_fail "failed to parse non-standard domain (1)";
+ }
+
+ test_set "envelope.to" "japanese@ex_ample.com";
+ if not envelope :domain :is "to" "ex_ample.com" {
+ test_fail "failed to parse non-standard domain (2)";
+ }
+
+ test_set "envelope.to" "japanese@example_.com";
+ if not envelope :domain :is "to" "example_.com" {
+ test_fail "failed to parse non-standard domain (3)";
+ }
+
+ test_set "envelope.to" "japanese@-example.com";
+ if not envelope :domain :is "to" "-example.com" {
+ test_fail "failed to parse non-standard domain (4)";
+ }
+
+ test_set "envelope.to" "japanese@example-.com";
+ if not envelope :domain :is "to" "example-.com" {
+ test_fail "failed to parse non-standard domain (5)";
+ }
+}
diff --git a/pigeonhole/tests/extensions/environment/basic.svtest b/pigeonhole/tests/extensions/environment/basic.svtest
new file mode 100644
index 0000000..bb0beb4
--- /dev/null
+++ b/pigeonhole/tests/extensions/environment/basic.svtest
@@ -0,0 +1,33 @@
+require "vnd.dovecot.testsuite";
+require "environment";
+require "variables";
+
+test "Name" {
+ if not environment :contains "name" "pigeonhole" {
+ if environment :matches "name" "*" { set "env_name" "${1}"; }
+
+ test_fail "name environment returned invalid value(1): ${env_name}";
+ }
+
+ if not environment :contains "name" "sieve" {
+ if environment :matches "name" "*" { set "env_name" "${1}"; }
+
+ test_fail "name environment returned invalid value(2): ${env_name}";
+ }
+
+ if environment :contains "name" "cyrus" {
+ test_fail "something is definitely wrong here";
+ }
+
+ if not environment :is :comparator "i;octet" "name" "Pigeonhole Sieve" {
+ test_fail "name environment does not match exactly with what is expected";
+ }
+}
+
+test "Location" {
+ if not environment "location" "MS" {
+ test_fail "wrong testsuite environment location";
+ }
+}
+
+
diff --git a/pigeonhole/tests/extensions/environment/rfc.svtest b/pigeonhole/tests/extensions/environment/rfc.svtest
new file mode 100644
index 0000000..c3177ae
--- /dev/null
+++ b/pigeonhole/tests/extensions/environment/rfc.svtest
@@ -0,0 +1,28 @@
+require "vnd.dovecot.testsuite";
+require "environment";
+require "relational";
+
+test "Non-existent" {
+ if environment :contains "nonsense" "" {
+ test_fail "matched unknown environment item";
+ }
+}
+
+test "Exists" {
+ if not environment :contains "version" "" {
+ test_fail "failed to match known environment item";
+ }
+}
+
+test "Count" {
+ if anyof (
+ environment :count "eq" "nonsense" "0",
+ environment :count "eq" "nonsense" "1"
+ ) {
+ test_fail "count should not match unknown environment item";
+ }
+
+ if not environment :count "eq" "location" "1" {
+ test_fail "count of non-empty environment should be 1";
+ }
+}
diff --git a/pigeonhole/tests/extensions/ihave/errors.svtest b/pigeonhole/tests/extensions/ihave/errors.svtest
new file mode 100644
index 0000000..c6b9750
--- /dev/null
+++ b/pigeonhole/tests/extensions/ihave/errors.svtest
@@ -0,0 +1,19 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+test "Error command" {
+ if not test_script_compile "errors/error.sieve" {
+ test_fail "compile failed";
+ }
+
+ if test_script_run {
+ test_fail "execution should have failed";
+ }
+
+ if test_error :count "gt" :comparator "i;ascii-numeric" "1" {
+ test_fail "too many runtime errors reported";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/ihave/errors/error.sieve b/pigeonhole/tests/extensions/ihave/errors/error.sieve
new file mode 100644
index 0000000..8da0fe7
--- /dev/null
+++ b/pigeonhole/tests/extensions/ihave/errors/error.sieve
@@ -0,0 +1,3 @@
+require "ihave";
+
+error "Something failed.";
diff --git a/pigeonhole/tests/extensions/ihave/execute.svtest b/pigeonhole/tests/extensions/ihave/execute.svtest
new file mode 100644
index 0000000..701d817
--- /dev/null
+++ b/pigeonhole/tests/extensions/ihave/execute.svtest
@@ -0,0 +1,23 @@
+require "vnd.dovecot.testsuite";
+
+/*
+ * Execution testing (currently just meant to trigger any segfaults)
+ */
+
+test "Basic" {
+ if not test_script_compile "execute/ihave.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script run failed";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+
+ test_binary_save "ihave-basic";
+ test_binary_load "ihave-basic";
+}
+
diff --git a/pigeonhole/tests/extensions/ihave/execute/ihave.sieve b/pigeonhole/tests/extensions/ihave/execute/ihave.sieve
new file mode 100644
index 0000000..0fe84c8
--- /dev/null
+++ b/pigeonhole/tests/extensions/ihave/execute/ihave.sieve
@@ -0,0 +1,7 @@
+require "ihave";
+
+if ihave "nonsense-extension" {
+ nonsense_command "Frop!";
+}
+
+redirect "frop@example.com";
diff --git a/pigeonhole/tests/extensions/ihave/restrictions.svtest b/pigeonhole/tests/extensions/ihave/restrictions.svtest
new file mode 100644
index 0000000..5dba126
--- /dev/null
+++ b/pigeonhole/tests/extensions/ihave/restrictions.svtest
@@ -0,0 +1,14 @@
+require "vnd.dovecot.testsuite";
+require "ihave";
+
+test "Restricted: encoded-character" {
+ if ihave "encoded-character" {
+ test_fail "encoded-character extension is incompatible with ihave";
+ }
+}
+
+test "Restricted: variables" {
+ if ihave "variables" {
+ test_fail "variables extension is incompatible with ihave";
+ }
+}
diff --git a/pigeonhole/tests/extensions/imap4flags/basic.svtest b/pigeonhole/tests/extensions/imap4flags/basic.svtest
new file mode 100644
index 0000000..d6af444
--- /dev/null
+++ b/pigeonhole/tests/extensions/imap4flags/basic.svtest
@@ -0,0 +1,332 @@
+require "vnd.dovecot.testsuite";
+
+require "imap4flags";
+require "relational";
+require "variables";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Basic functionality tests
+ */
+
+test "Hasflag empty" {
+ if hasflag "\\Seen" {
+ test_fail "hasflag sees initial \\seen flag were there should be none";
+ }
+ if hasflag "\\draft" {
+ test_fail "hasflag sees initial \\draft flag were there should be none";
+ }
+ if hasflag "\\recent" {
+ test_fail "hasflag sees initial \\recent flag were there should be none";
+ }
+ if hasflag "\\flagged" {
+ test_fail "hasflag sees initial \\flagged flag were there should be none";
+ }
+ if hasflag "\\answered" {
+ test_fail "hasflag sees initial \\answered flag were there should be none";
+ }
+ if hasflag "\\deleted" {
+ test_fail "hasflag sees initial \\deleted flag were there should be none";
+ }
+
+ if hasflag :comparator "i;ascii-numeric" :count "ge" "1" {
+ test_fail "hasflag sees initial flags were there should be none";
+ }
+}
+
+test "Setflag; Hasflag one" {
+ setflag "\\seen";
+
+ if not hasflag "\\Seen" {
+ test_fail "flag not set of hasflag fails to see it";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "1" {
+ test_fail "flag not set of hasflag fails to see it";
+ }
+
+ if hasflag "$Nonsense" {
+ test_fail "hasflag sees other flag that the one set";
+ }
+}
+
+test "Hasflag; duplicates" {
+ set "Flags" "A B C D E F A B C D E F";
+
+ if hasflag :comparator "i;ascii-numeric" :count "gt" "Flags" "6" {
+ test_fail "hasflag must ignore duplicates";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "Flags" "6" {
+ test_fail "hasflag :count gives strange results";
+ }
+}
+
+test "Flag operations" {
+ setflag "A";
+
+ if not hasflag "A" {
+ test_fail "hasflag misses set flag";
+ }
+
+ if hasflag :comparator "i;ascii-numeric" :count "gt" "1" {
+ test_fail "hasflag sees more than one flag";
+ }
+
+ addflag "B";
+
+ if not hasflag "B" {
+ test_fail "flag \"B\" not added";
+ }
+
+ if not hasflag "A" {
+ test_fail "flag \"A\" not retained";
+ }
+
+ if hasflag :comparator "i;ascii-numeric" :count "gt" "2" {
+ test_fail "hasflag sees more than two flags";
+ }
+
+ addflag ["C", "D", "E F"];
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "6" {
+ test_fail "hasflag sees more than two flags";
+ }
+
+ removeflag ["D"];
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "5" {
+ test_fail "hasflag sees more than two flags";
+ }
+
+ if hasflag "D" {
+ test_fail "removed flag still present";
+ }
+
+ set "var" "G";
+ addflag "${var}";
+
+ if not hasflag "G" {
+ test_fail "flag \"G\" not added";
+ }
+
+ if not hasflag "A" {
+ test_fail "flag \"A\" not retained";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "6" {
+ test_fail "hasflag sees something other than six flags";
+ }
+}
+
+test "Variable flag operations" {
+ setflag "frop" "A";
+
+ if not hasflag "frop" "A" {
+ test_fail "hasflag misses set flag";
+ }
+
+ if hasflag :comparator "i;ascii-numeric" :count "gt" "frop" "1" {
+ test_fail "hasflag sees more than one flag";
+ }
+
+ addflag "frop" "B";
+
+ if not hasflag "frop" "B" {
+ test_fail "flag \"B\" not added";
+ }
+
+ if not hasflag "frop" "A" {
+ test_fail "flag \"A\" not retained";
+ }
+
+ if hasflag :comparator "i;ascii-numeric" :count "gt" "frop" "2" {
+ test_fail "hasflag sees more than two flags";
+ }
+
+ addflag "frop" ["C", "D", "E F"];
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "frop" "6" {
+ test_fail "hasflag sees something other than six flags";
+ }
+
+ removeflag "frop" ["D"];
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "frop" "5" {
+ test_fail "hasflag sees something other than five flags";
+ }
+
+ if hasflag "frop" "D" {
+ test_fail "removed flag still present";
+ }
+
+ set "var" "G";
+ addflag "frop" "${var}";
+
+ if not hasflag "frop" "G" {
+ test_fail "flag \"G\" not added";
+ }
+
+ if not hasflag "frop" "A" {
+ test_fail "flag \"A\" not retained";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "frop" "6" {
+ test_fail "hasflag sees something other than six flags";
+ }
+}
+
+test "Setflag; string list" {
+ setflag ["A B", "C D"];
+
+ if not hasflag "A" {
+ test_fail "hasflag misses A flag";
+ }
+
+ if not hasflag "B" {
+ test_fail "hasflag misses B flag";
+ }
+
+ if not hasflag "C" {
+ test_fail "hasflag misses C flag";
+ }
+
+ if not hasflag "D" {
+ test_fail "hasflag misses D flag";
+ }
+
+ if hasflag :comparator "i;ascii-numeric" :count "ne" "4" {
+ test_fail "hasflag sees incorrect number of flags";
+ }
+}
+
+test "Removal: one" {
+ setflag "\\seen";
+
+ if not hasflag "\\seen" {
+ test_fail "hasflag misses set flag";
+ }
+
+ removeflag "\\seen";
+
+ if hasflag "\\seen" {
+ test_fail "flag not removed";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "0" {
+ test_fail "flags are still set";
+ }
+}
+
+test "Removal: first" {
+ setflag "$frop \\seen";
+
+ if not allof ( hasflag "\\seen", hasflag "$frop" ) {
+ test_fail "hasflag misses set flags";
+ }
+
+ removeflag "$frop";
+
+ if not hasflag "\\seen" {
+ test_fail "wrong flag removed";
+ }
+
+ if hasflag "$frop" {
+ test_fail "flag not removed";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "1" {
+ test_fail "more than one flag remains set";
+ }
+}
+
+test "Removal: last" {
+ setflag "\\seen $friep";
+
+ if not allof ( hasflag "\\seen", hasflag "$friep" ) {
+ test_fail "hasflag misses set flags";
+ }
+
+ removeflag "$friep";
+
+ if not hasflag "\\seen" {
+ test_fail "wrong flag removed";
+ }
+
+ if hasflag "$friep" {
+ test_fail "flag not removed";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "1" {
+ test_fail "more than one flag remains set";
+ }
+}
+
+test "Removal: middle" {
+ setflag "\\seen $friep \\flagged";
+
+ if not allof ( hasflag "\\flagged", hasflag "\\seen", hasflag "$friep" ) {
+ test_fail "hasflag misses set flags";
+ }
+
+ removeflag "$friep";
+
+ if not allof ( hasflag "\\seen", hasflag "\\flagged" ) {
+ test_fail "wrong flag removed";
+ }
+
+ if hasflag "$friep" {
+ test_fail "flag not removed";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "2" {
+ test_fail "more than two flags remain set";
+ }
+}
+
+test "Removal: duplicates" {
+ setflag "\\seen $friep $friep \\flagged $friep";
+
+ if not allof ( hasflag "\\flagged", hasflag "\\seen", hasflag "$friep" ) {
+ test_fail "hasflag misses set flags";
+ }
+
+ removeflag "$friep";
+
+ if not allof ( hasflag "\\seen", hasflag "\\flagged" ) {
+ test_fail "wrong flag removed";
+ }
+
+ if hasflag "$friep" {
+ test_fail "flag not removed";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "2" {
+ test_fail "more than two flags remain set";
+ }
+}
+
+test "Removal: whitespace" {
+ setflag " \\seen $friep $friep \\flagged $friep ";
+
+ if not allof ( hasflag "\\flagged", hasflag "\\seen", hasflag "$friep" ) {
+ test_fail "hasflag misses set flags";
+ }
+
+ removeflag "$friep";
+
+ if not allof ( hasflag "\\seen", hasflag "\\flagged" ) {
+ test_fail "wrong flag removed";
+ }
+
+ if hasflag "$friep" {
+ test_fail "flag not removed";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "2" {
+ test_fail "more than two flags remain set";
+ }
+}
+
+
+
diff --git a/pigeonhole/tests/extensions/imap4flags/execute.svtest b/pigeonhole/tests/extensions/imap4flags/execute.svtest
new file mode 100644
index 0000000..1ee1906
--- /dev/null
+++ b/pigeonhole/tests/extensions/imap4flags/execute.svtest
@@ -0,0 +1,68 @@
+require "vnd.dovecot.testsuite";
+require "imap4flags";
+require "relational";
+
+
+/*
+ * Execution testing
+ */
+
+test_mailbox_create "INBOX.Junk";
+test_mailbox_create "INBOX.Nonsense";
+
+test "Flags Side Effect" {
+ if not test_script_compile "execute/flags-side-effect.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script execute failed";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+
+ test_result_reset;
+
+ if not test_message :folder "INBOX.Junk" 0 {
+ test_fail "message not stored in INBOX.Junk";
+ }
+
+ if not hasflag :count "eq" "1" {
+ test_fail "invalid number of flags for message in INBOX.Junk";
+ }
+
+ if not hasflag :is "NONSENSE" {
+ test_fail "invalid flag set for message in INBOX.Junk";
+ }
+
+ test_result_reset;
+
+ if not test_message :folder "INBOX" 0 {
+ test_fail "message not stored in INBOX";
+ }
+
+ if not hasflag :count "eq" "1" {
+ test_fail "invalid number of flags for message in INBOX";
+ }
+
+ if not hasflag :is "\\seen" {
+ test_fail "invalid flag set for message in INBOX";
+ }
+
+ test_result_reset;
+
+ if not test_message :folder "INBOX.Nonsense" 0 {
+ test_fail "message not stored in INBOX.Nonsense";
+ }
+
+ if not hasflag :count "eq" "1" {
+ test_fail "invalid number of flags for message in Inbox.Nonsense";
+ }
+
+ if not hasflag :is "IMPLICIT" {
+ test_fail "invalid flag set for message in Inbox.Nonsene";
+ }
+
+}
diff --git a/pigeonhole/tests/extensions/imap4flags/execute/flags-side-effect.sieve b/pigeonhole/tests/extensions/imap4flags/execute/flags-side-effect.sieve
new file mode 100644
index 0000000..17de0ad
--- /dev/null
+++ b/pigeonhole/tests/extensions/imap4flags/execute/flags-side-effect.sieve
@@ -0,0 +1,18 @@
+require "imap4flags";
+require "fileinto";
+
+/*
+ * When keep/fileinto is used multiple times in a script and duplicate
+ * message elimination is performed, the last flag list value MUST win.
+ */
+
+setflag "IMPLICIT";
+
+fileinto :flags "\\Seen \\Draft" "INBOX.Junk";
+fileinto :flags "NONSENSE" "INBOX.Junk";
+
+keep;
+keep :flags "\\Seen";
+
+fileinto :flags "\\Seen" "Inbox.Nonsense";
+fileinto "Inbox.Nonsense";
diff --git a/pigeonhole/tests/extensions/imap4flags/flagstore.svtest b/pigeonhole/tests/extensions/imap4flags/flagstore.svtest
new file mode 100644
index 0000000..bf11402
--- /dev/null
+++ b/pigeonhole/tests/extensions/imap4flags/flagstore.svtest
@@ -0,0 +1,146 @@
+require "vnd.dovecot.testsuite";
+require "fileinto";
+require "imap4flags";
+require "relational";
+require "comparator-i;ascii-numeric";
+require "mailbox";
+
+test_set "message" text:
+From: Henry von Flockenstoffen <henry@example.com>
+To: Dieter von Ausburg <dieter@example.com>
+Subject: Test message.
+
+Test message.
+.
+;
+
+test "Basic" {
+ if hasflag :comparator "i;ascii-numeric" :count "ge" "1" {
+ test_fail "some flags or keywords are already set";
+ }
+
+ setflag "$label1 \\answered";
+
+ fileinto :create "Uninteresting";
+
+ if not test_result_execute {
+ test_fail "failed to execute first result";
+ }
+
+ test_result_reset;
+
+ setflag "\\draft \\seen Junk";
+
+ fileinto "Uninteresting";
+
+ if not test_result_execute {
+ test_fail "failed to execute second result";
+ }
+
+ test_result_reset;
+
+ fileinto :flags "\\flagged" "Uninteresting";
+
+ if not test_result_execute {
+ test_fail "failed to execute third result";
+ }
+
+ test_result_reset;
+
+ test_message :folder "Uninteresting" 0;
+
+ if not hasflag "$label1 \\answered" {
+ test_fail "flags not stored for first message";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "2" {
+ test_fail "invalid number of flags set for first message";
+ }
+
+ test_result_reset;
+
+ test_message :folder "Uninteresting" 1;
+
+ if not hasflag "\\draft \\seen Junk" {
+ test_fail "flags not stored for second message";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "3" {
+ test_fail "invalid number of flags set for second message";
+ }
+
+ test_result_reset;
+
+ test_message :folder "Uninteresting" 2;
+
+ if not hasflag "\\flagged" {
+ test_fail "flags not stored for third message";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "1" {
+ test_fail "invalid number of flags set for third message";
+ }
+}
+
+test_result_reset;
+test_set "message" text:
+From: Henry von Flockenstoffen <henry@example.com>
+To: Dieter von Ausburg <dieter@example.com>
+Subject: Test message.
+
+Test message.
+.
+;
+
+test "Flag changes between stores" {
+ if hasflag :comparator "i;ascii-numeric" :count "ge" "1" {
+ test_fail "some flags or keywords are already set";
+ }
+
+ setflag "$label1 \\answered";
+ fileinto :create "FolderA";
+
+ setflag "$label2";
+ fileinto :create "FolderB";
+
+ fileinto :create :flags "\\seen \\draft \\flagged" "FolderC";
+
+ if not test_result_execute {
+ test_fail "failed to execute first result";
+ }
+
+ test_result_reset;
+ test_message :folder "FolderA" 0;
+
+ if not hasflag "\\answered $label1" {
+ test_fail "flags not stored for first message";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "2" {
+ test_fail "invalid number of flags set for first message";
+ }
+
+ test_result_reset;
+ test_message :folder "FolderB" 0;
+
+ if not hasflag "$label2" {
+ test_fail "flag not stored for second message";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "1" {
+ test_fail "invalid number of flags set for second message";
+ }
+
+ test_result_reset;
+ test_message :folder "FolderC" 0;
+
+ if not hasflag "\\seen \\flagged \\draft" {
+ test_fail "flags not stored for third message";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "3" {
+ test_fail "invalid number of flags set for third message";
+ }
+}
+
+
diff --git a/pigeonhole/tests/extensions/imap4flags/flagstring.svtest b/pigeonhole/tests/extensions/imap4flags/flagstring.svtest
new file mode 100644
index 0000000..23b6b34
--- /dev/null
+++ b/pigeonhole/tests/extensions/imap4flags/flagstring.svtest
@@ -0,0 +1,82 @@
+require "vnd.dovecot.testsuite";
+require "imap4flags";
+require "variables";
+
+test "Duplicates: setflag" {
+ setflag "flags" "\\seen \\seen";
+
+ if not string "${flags}" "\\seen" {
+ test_fail "duplicate \\seen flag item not removed (1)";
+ }
+
+ setflag "flags" "\\seen $frop \\seen";
+
+ if not string "${flags}" "\\seen $frop" {
+ test_fail "duplicate \\seen flag item not removed (2)";
+ }
+
+ setflag "flags" "\\seen $frop $frop \\seen";
+
+ if not string "${flags}" "\\seen $frop" {
+ test_fail "duplicate \\seen flag item not removed (3)";
+ }
+
+ setflag "flags" "$frop \\seen $frop \\seen";
+
+ if not string "${flags}" "$frop \\seen" {
+ test_fail "duplicate \\seen flag item not removed (4)";
+ }
+
+ setflag "flags" "$frop \\seen \\seen \\seen \\seen $frop $frop $frop \\seen";
+
+ if not string "${flags}" "$frop \\seen" {
+ test_fail "duplicate \\seen flag item not removed (5)";
+ }
+}
+
+test "Duplicates: addflag" {
+ setflag "flags" "";
+ addflag "flags" "\\seen \\seen";
+
+ if not string "${flags}" "\\seen" {
+ test_fail "duplicate \\seen flag item not removed (1)";
+ }
+
+ setflag "flags" "";
+ addflag "flags" "\\seen $frop \\seen";
+
+ if not string "${flags}" "\\seen $frop" {
+ test_fail "duplicate \\seen flag item not removed (2)";
+ }
+
+ setflag "flags" "";
+ addflag "flags" "\\seen $frop $frop \\seen";
+
+ if not string "${flags}" "\\seen $frop" {
+ test_fail "duplicate \\seen flag item not removed (3)";
+ }
+
+ setflag "flags" "";
+ addflag "flags" "$frop \\seen $frop \\seen";
+
+ if not string "${flags}" "$frop \\seen" {
+ test_fail "duplicate \\seen flag item not removed (4)";
+ }
+
+ setflag "flags" "";
+ addflag "flags" "$frop \\seen \\seen \\seen \\seen $frop $frop $frop \\seen";
+
+ if not string "${flags}" "$frop \\seen" {
+ test_fail "duplicate \\seen flag item not removed (5)";
+ }
+
+ setflag "flags" "$frop \\seen";
+ addflag "flags" "\\seen \\seen \\seen $frop $frop $frop \\seen";
+
+ if not string "${flags}" "$frop \\seen" {
+ test_fail "duplicate \\seen flag item not removed (6)";
+ }
+}
+
+
+
diff --git a/pigeonhole/tests/extensions/imap4flags/hasflag.svtest b/pigeonhole/tests/extensions/imap4flags/hasflag.svtest
new file mode 100644
index 0000000..1088190
--- /dev/null
+++ b/pigeonhole/tests/extensions/imap4flags/hasflag.svtest
@@ -0,0 +1,91 @@
+require "vnd.dovecot.testsuite";
+
+require "imap4flags";
+require "relational";
+require "variables";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Generic tests
+ */
+
+test "Ignoring \"\"" {
+ setflag "";
+
+ if hasflag "" {
+ test_fail "hasflag fails to ignore empty string";
+ }
+}
+
+/*
+ * Variables
+ */
+
+test "Multiple variables" {
+ setflag "A" "Aflag";
+ setflag "B" "Bflag";
+ setflag "C" "Cflag";
+
+ if not hasflag ["a", "b", "c"] ["Bflag"] {
+ test_fail "hasflag failed to match multiple flags variables";
+ }
+}
+
+/*
+ * RFC examples
+ */
+
+test "RFC hasflag example - :is" {
+ setflag "A B";
+
+ if not hasflag ["b","A"] {
+ test_fail "list representation did not match";
+ }
+
+ if not hasflag :is "b A" {
+ test_fail "string representation did not match";
+ }
+}
+
+test "RFC hasflag example - :contains variable" {
+ set "MyVar" "NonJunk Junk gnus-forward $Forwarded NotJunk JunkRecorded $Junk $NotJunk";
+
+ if not hasflag :contains "MyVar" "Junk" {
+ test_fail "failed true example 1";
+ }
+
+ if not hasflag :contains "MyVar" "forward" {
+ test_fail "failed true example 2";
+ }
+
+ if not hasflag :contains "MyVar" ["label", "forward"] {
+ test_fail "failed true example 3";
+ }
+
+ if not hasflag :contains "MyVar" ["junk", "forward"] {
+ test_fail "failed true example 4";
+ }
+
+ if not hasflag :contains "MyVar" "junk forward" {
+ test_fail "failed true example 4 (rewrite 1)";
+ }
+
+ if not hasflag :contains "MyVar" "forward junk" {
+ test_fail "failed true example 4 (rewrite 2)";
+ }
+
+ if hasflag :contains "MyVar" "label" {
+ test_fail "failed false example 1";
+ }
+
+ if hasflag :contains "MyVar" ["label1", "label2"] {
+ test_fail "failed false example 2";
+ }
+}
+
+test "RFC hasflag example - :count variable" {
+ set "MyFlags" "A B";
+ if not hasflag :count "ge" :comparator "i;ascii-numeric" "MyFlags" "2" {
+ test_fail "failed count \"ge\" comparison";
+ }
+}
diff --git a/pigeonhole/tests/extensions/imap4flags/multiscript.svtest b/pigeonhole/tests/extensions/imap4flags/multiscript.svtest
new file mode 100644
index 0000000..5080eda
--- /dev/null
+++ b/pigeonhole/tests/extensions/imap4flags/multiscript.svtest
@@ -0,0 +1,55 @@
+require "vnd.dovecot.testsuite";
+require "imap4flags";
+require "relational";
+require "comparator-i;ascii-numeric";
+require "mailbox";
+require "fileinto";
+
+test "Segfault Trigger 1" {
+
+ if not test_multiscript [
+ "multiscript/group-spam.sieve",
+ "multiscript/spam.sieve",
+ "multiscript/sent-store.sieve"]
+ {
+ test_fail "failed multiscript execution";
+ }
+}
+
+test_set "message" text:
+From: Henry von Flockenstoffen <henry@example.com>
+To: Dieter von Ausburg <dieter@example.com>
+Subject: Test message.
+
+Test message.
+.
+;
+
+test "Internal Flags" {
+ if hasflag :comparator "i;ascii-numeric" :count "ge" "1" {
+ test_fail "some flags or keywords are already set";
+ }
+
+ if not test_multiscript [
+ "multiscript/setflag.sieve",
+ "multiscript/fileinto.sieve"]
+ {
+ test_fail "failed multiscript execution";
+ }
+
+ test_result_reset;
+ test_message :folder "folder" 0;
+
+ if not hasflag "\\answered" {
+ test_fail "\\answered flag not stored for message";
+ }
+
+ if not hasflag "$label1" {
+ test_fail "$label1 keyword not stored for message";
+ }
+
+ if not hasflag :comparator "i;ascii-numeric" :count "eq" "2" {
+ test_fail "invalid number of flags set for message";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/imap4flags/multiscript/fileinto.sieve b/pigeonhole/tests/extensions/imap4flags/multiscript/fileinto.sieve
new file mode 100644
index 0000000..94892a5
--- /dev/null
+++ b/pigeonhole/tests/extensions/imap4flags/multiscript/fileinto.sieve
@@ -0,0 +1,4 @@
+require "fileinto";
+require "mailbox";
+
+fileinto :create "folder";
diff --git a/pigeonhole/tests/extensions/imap4flags/multiscript/group-spam.sieve b/pigeonhole/tests/extensions/imap4flags/multiscript/group-spam.sieve
new file mode 100644
index 0000000..92ea3b9
--- /dev/null
+++ b/pigeonhole/tests/extensions/imap4flags/multiscript/group-spam.sieve
@@ -0,0 +1,14 @@
+require ["fileinto", "variables", "envelope"];
+
+if header :contains "X-Group-Mail" ["Yes", "YES", "1"] {
+ if header :contains "X-Spam-Flag" ["Yes", "YES", "1"] {
+ if envelope :matches :localpart "to" "*" {
+ fileinto "group/${1}/SPAM"; stop;
+ }
+ }
+ if address :is ["To"] "sales@florist.ru" {
+ fileinto "group/info/Orders";
+ }
+ stop;
+}
+keep;
diff --git a/pigeonhole/tests/extensions/imap4flags/multiscript/sent-store.sieve b/pigeonhole/tests/extensions/imap4flags/multiscript/sent-store.sieve
new file mode 100644
index 0000000..cb21daa
--- /dev/null
+++ b/pigeonhole/tests/extensions/imap4flags/multiscript/sent-store.sieve
@@ -0,0 +1,7 @@
+require ["imap4flags"];
+
+if header :contains "X-Set-Seen" ["Yes", "YES", "1"] {
+ setflag "\\Seen";
+}
+
+keep;
diff --git a/pigeonhole/tests/extensions/imap4flags/multiscript/setflag.sieve b/pigeonhole/tests/extensions/imap4flags/multiscript/setflag.sieve
new file mode 100644
index 0000000..c992d19
--- /dev/null
+++ b/pigeonhole/tests/extensions/imap4flags/multiscript/setflag.sieve
@@ -0,0 +1,3 @@
+require "imap4flags";
+
+setflag "$label1 \\answered";
diff --git a/pigeonhole/tests/extensions/imap4flags/multiscript/spam.sieve b/pigeonhole/tests/extensions/imap4flags/multiscript/spam.sieve
new file mode 100644
index 0000000..9e1b6c3
--- /dev/null
+++ b/pigeonhole/tests/extensions/imap4flags/multiscript/spam.sieve
@@ -0,0 +1,8 @@
+require ["fileinto"];
+
+if header :contains "X-Spam-Flag" ["Yes", "YES", "1"] {
+ fileinto "SPAM";
+}
+keep;
+
+
diff --git a/pigeonhole/tests/extensions/include/errors.svtest b/pigeonhole/tests/extensions/include/errors.svtest
new file mode 100644
index 0000000..6f8b1cc
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors.svtest
@@ -0,0 +1,149 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Generic include errors
+ */
+
+test "Generic" {
+ if test_script_compile "errors/generic.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Circular - direct" {
+ if test_script_compile "errors/circular-1.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Circular - one intermittent" {
+ if test_script_compile "errors/circular-2.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "4" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Circular - two intermittent" {
+ if test_script_compile "errors/circular-3.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "5" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Using global without variables required
+ */
+
+test "Variables inactive" {
+ if test_script_compile "errors/variables-inactive.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Generic variables errors
+ */
+
+test "Variables" {
+ if test_script_compile "errors/variables.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Global variable namespace
+ */
+
+test "Global Namespace" {
+ if test_script_compile "errors/global-namespace.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "4" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Invalid script names
+ */
+
+test "Invalid Script Names" {
+ if test_script_compile "errors/scriptname.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "8" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/* Include limit */
+
+test "Include limit" {
+ test_config_set "sieve_include_max_includes" "3";
+ test_config_reload :extension "include";
+
+ if test_script_compile "errors/include-limit.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "2" {
+ test_fail "wrong number of errors reported";
+ }
+
+ test_config_set "sieve_include_max_includes" "255";
+ test_config_reload :extension "include";
+
+ if not test_script_compile "errors/include-limit.sieve" {
+ test_fail "compile should have succeeded";
+ }
+}
+
+/* Depth limit */
+
+test "Depth limit" {
+ test_config_set "sieve_include_max_nesting_depth" "2";
+ test_config_reload :extension "include";
+
+ if test_script_compile "errors/depth-limit.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "4" {
+ test_fail "wrong number of errors reported";
+ }
+
+ test_config_set "sieve_include_max_nesting_depth" "10";
+ test_config_reload :extension "include";
+
+ if not test_script_compile "errors/depth-limit.sieve" {
+ test_fail "compile should have succeeded";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/include/errors/action-conflicts.sieve b/pigeonhole/tests/extensions/include/errors/action-conflicts.sieve
new file mode 100644
index 0000000..ddeb42c
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/action-conflicts.sieve
@@ -0,0 +1,4 @@
+require "include";
+
+include "action-fileinto";
+include "action-reject";
diff --git a/pigeonhole/tests/extensions/include/errors/circular-1.sieve b/pigeonhole/tests/extensions/include/errors/circular-1.sieve
new file mode 100644
index 0000000..22b6f87
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/circular-1.sieve
@@ -0,0 +1,5 @@
+require "include";
+
+discard;
+
+include "circular-one";
diff --git a/pigeonhole/tests/extensions/include/errors/circular-2.sieve b/pigeonhole/tests/extensions/include/errors/circular-2.sieve
new file mode 100644
index 0000000..0cfa375
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/circular-2.sieve
@@ -0,0 +1,5 @@
+require "include";
+
+discard;
+
+include "circular-two";
diff --git a/pigeonhole/tests/extensions/include/errors/circular-3.sieve b/pigeonhole/tests/extensions/include/errors/circular-3.sieve
new file mode 100644
index 0000000..1ad95b6
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/circular-3.sieve
@@ -0,0 +1,5 @@
+require "include";
+
+discard;
+
+include "circular-three";
diff --git a/pigeonhole/tests/extensions/include/errors/depth-limit.sieve b/pigeonhole/tests/extensions/include/errors/depth-limit.sieve
new file mode 100644
index 0000000..93291b6
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/depth-limit.sieve
@@ -0,0 +1,3 @@
+require "include";
+
+include :personal "depth-limit-1";
diff --git a/pigeonhole/tests/extensions/include/errors/generic.sieve b/pigeonhole/tests/extensions/include/errors/generic.sieve
new file mode 100644
index 0000000..66eba18
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/generic.sieve
@@ -0,0 +1,7 @@
+require "include";
+
+# Non-existent sieve script
+include "frop.sieve";
+
+# Use of / in script names
+include "../frop.sieve";
diff --git a/pigeonhole/tests/extensions/include/errors/global-namespace.sieve b/pigeonhole/tests/extensions/include/errors/global-namespace.sieve
new file mode 100644
index 0000000..3827b60
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/global-namespace.sieve
@@ -0,0 +1,13 @@
+require "variables";
+require "include";
+
+# Invalid namespace
+set "globl.var" "frop";
+
+# Sub-namespace
+set "global.env.0" "12";
+
+# Invalid variable name
+set "global.12" "porf";
+
+
diff --git a/pigeonhole/tests/extensions/include/errors/include-limit.sieve b/pigeonhole/tests/extensions/include/errors/include-limit.sieve
new file mode 100644
index 0000000..f6689dd
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/include-limit.sieve
@@ -0,0 +1,6 @@
+require "include";
+
+include "rfc-ex1-always_allow";
+include "rfc-ex2-spam_filter_script";
+include "rfc-ex1-mailing_lists";
+include "rfc-ex1-spam_tests";
diff --git a/pigeonhole/tests/extensions/include/errors/scriptname.sieve b/pigeonhole/tests/extensions/include/errors/scriptname.sieve
new file mode 100644
index 0000000..9a10c3d
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/scriptname.sieve
@@ -0,0 +1,25 @@
+require "variables";
+require "include";
+require "encoded-character";
+
+# Slash
+include "../frop";
+
+# More slashes
+include "../../james/sieve/vacation";
+
+# 0000-001F; [CONTROL CHARACTERS]
+include "idiotic${unicode: 001a}";
+
+# 007F; DELETE
+include "idiotic${unicode: 007f}";
+
+# 0080-009F; [CONTROL CHARACTERS]
+include "idiotic${unicode: 0085}";
+
+# 2028; LINE SEPARATOR
+include "idiotic${unicode: 2028}";
+
+# 2029; PARAGRAPH SEPARATOR
+include "idiotic${unicode: 2029}";
+
diff --git a/pigeonhole/tests/extensions/include/errors/variables-inactive.sieve b/pigeonhole/tests/extensions/include/errors/variables-inactive.sieve
new file mode 100644
index 0000000..06e0df1
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/variables-inactive.sieve
@@ -0,0 +1,7 @@
+require "include";
+require "fileinto";
+
+global "friep";
+global "frop";
+
+fileinto "Frop";
diff --git a/pigeonhole/tests/extensions/include/errors/variables.sieve b/pigeonhole/tests/extensions/include/errors/variables.sieve
new file mode 100644
index 0000000..eac99f8
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/variables.sieve
@@ -0,0 +1,23 @@
+require "include";
+require "variables";
+
+# Duplicate global declaration (not an error)
+global "frml";
+global "frml";
+
+keep;
+
+# Global after command not being require or global (not an error)
+global "friep";
+
+# DEPRECATED: import/export after command not being require or import/export
+export "friep";
+import "friep";
+
+# Marking local variable as global
+set "frutsels" "frop";
+global "frutsels";
+set "frutsels" "frop";
+
+
+
diff --git a/pigeonhole/tests/extensions/include/execute.svtest b/pigeonhole/tests/extensions/include/execute.svtest
new file mode 100644
index 0000000..734ac66
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/execute.svtest
@@ -0,0 +1,68 @@
+require "vnd.dovecot.testsuite";
+require "include";
+require "variables";
+
+test_set "message" text:
+From: idiot@example.com
+To: idiot@example.org
+Subject: Frop!
+
+Frop.
+.
+;
+
+test "Actions Fileinto" {
+ test_mailbox_create "aaaa";
+ test_mailbox_create "bbbb";
+
+ if not test_script_compile "execute/actions-fileinto.sieve" {
+ test_fail "failed to compile sieve script";
+ }
+
+ test_binary_save "actions-fileinto";
+ test_binary_load "actions-fileinto";
+
+ if not test_script_run {
+ test_fail "failed to execute sieve script";
+ }
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ test_message :folder "aaaa" 0;
+
+ if not header "subject" "Frop!" {
+ test_fail "fileinto \"aaaa\" not executed.";
+ }
+
+ test_message :folder "bbbb" 0;
+
+ if not header "subject" "Frop!" {
+ test_fail "fileinto \"bbbb\" not executed.";
+ }
+}
+
+test "Namespace - file" {
+ if not test_script_compile "execute/namespace.sieve" {
+ test_fail "failed to compile sub-test";
+ }
+
+ if not test_script_run {
+ test_fail "failed to execute sub-test";
+ }
+}
+
+test "Namespace - dict" {
+ test_config_set "sieve" "dict:file:${tst.path}/included/namespace.dict";
+ test_config_set "sieve_global" "dict:file:${tst.path}/included-global/namespace.dict";
+ test_config_reload :extension "include";
+
+ if not test_script_compile "execute/namespace.sieve" {
+ test_fail "failed to compile sub-test";
+ }
+
+ if not test_script_run {
+ test_fail "failed to execute sub-test";
+ }
+}
diff --git a/pigeonhole/tests/extensions/include/execute/actions-fileinto.sieve b/pigeonhole/tests/extensions/include/execute/actions-fileinto.sieve
new file mode 100644
index 0000000..b0b8157
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/execute/actions-fileinto.sieve
@@ -0,0 +1,5 @@
+require "include";
+
+include "actions-fileinto1";
+include "actions-fileinto2";
+include "actions-fileinto3";
diff --git a/pigeonhole/tests/extensions/include/execute/namespace.sieve b/pigeonhole/tests/extensions/include/execute/namespace.sieve
new file mode 100644
index 0000000..cbe41a2
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/execute/namespace.sieve
@@ -0,0 +1,26 @@
+require "vnd.dovecot.testsuite";
+require "include";
+require "variables";
+
+set "global.a" "none";
+include :personal "namespace";
+
+if string "${global.a}" "none" {
+ test_fail "personal script not executed";
+}
+
+if not string "${global.a}" "personal" {
+ test_fail "executed global instead of personal script: ${global.a}";
+}
+
+set "global.a" "none";
+include :global "namespace";
+
+if string "{global.a}" "none" {
+ test_fail "global script not executed";
+}
+
+if not string "${global.a}" "global" {
+ test_fail "executed personal instead of global script: ${global.a}";
+}
+
diff --git a/pigeonhole/tests/extensions/include/execute/optional.sieve b/pigeonhole/tests/extensions/include/execute/optional.sieve
new file mode 100644
index 0000000..a6ad479
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/execute/optional.sieve
@@ -0,0 +1,5 @@
+require "include";
+
+include :optional "optional-1";
+include :optional "optional-2";
+include :optional "optional-3";
diff --git a/pigeonhole/tests/extensions/include/included-global/namespace.dict b/pigeonhole/tests/extensions/include/included-global/namespace.dict
new file mode 100644
index 0000000..8f52fd3
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included-global/namespace.dict
@@ -0,0 +1,4 @@
+priv/sieve/name/namespace
+1
+priv/sieve/data/1
+require ["variables", "include"]; set "global.a" "global";
diff --git a/pigeonhole/tests/extensions/include/included-global/namespace.sieve b/pigeonhole/tests/extensions/include/included-global/namespace.sieve
new file mode 100644
index 0000000..d11c2f1
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included-global/namespace.sieve
@@ -0,0 +1,4 @@
+require "include";
+require "variables";
+
+set "global.a" "global";
diff --git a/pigeonhole/tests/extensions/include/included-global/rfc-ex1-spam_tests.sieve b/pigeonhole/tests/extensions/include/included-global/rfc-ex1-spam_tests.sieve
new file mode 100644
index 0000000..340ceaf
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included-global/rfc-ex1-spam_tests.sieve
@@ -0,0 +1,7 @@
+require ["reject"];
+
+if anyof (header :contains "Subject" "$$",
+ header :contains "Subject" "Make money")
+{
+ reject "Not wanted";
+}
diff --git a/pigeonhole/tests/extensions/include/included/action-fileinto.sieve b/pigeonhole/tests/extensions/include/included/action-fileinto.sieve
new file mode 100644
index 0000000..9aafb95
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/action-fileinto.sieve
@@ -0,0 +1,3 @@
+require "fileinto";
+
+fileinto "frop";
diff --git a/pigeonhole/tests/extensions/include/included/action-reject.sieve b/pigeonhole/tests/extensions/include/included/action-reject.sieve
new file mode 100644
index 0000000..6e7b0b0
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/action-reject.sieve
@@ -0,0 +1,3 @@
+require "reject";
+
+reject "Ik heb geen zin in die rommel.";
diff --git a/pigeonhole/tests/extensions/include/included/actions-fileinto1.sieve b/pigeonhole/tests/extensions/include/included/actions-fileinto1.sieve
new file mode 100644
index 0000000..d4c5031
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/actions-fileinto1.sieve
@@ -0,0 +1,3 @@
+require "fileinto";
+
+fileinto "aaaa";
diff --git a/pigeonhole/tests/extensions/include/included/actions-fileinto2.sieve b/pigeonhole/tests/extensions/include/included/actions-fileinto2.sieve
new file mode 100644
index 0000000..f73da0d
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/actions-fileinto2.sieve
@@ -0,0 +1,4 @@
+require "fileinto";
+
+fileinto "bbbb";
+
diff --git a/pigeonhole/tests/extensions/include/included/actions-fileinto3.sieve b/pigeonhole/tests/extensions/include/included/actions-fileinto3.sieve
new file mode 100644
index 0000000..d4c5031
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/actions-fileinto3.sieve
@@ -0,0 +1,3 @@
+require "fileinto";
+
+fileinto "aaaa";
diff --git a/pigeonhole/tests/extensions/include/included/circular-one.sieve b/pigeonhole/tests/extensions/include/included/circular-one.sieve
new file mode 100644
index 0000000..2d60606
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/circular-one.sieve
@@ -0,0 +1,5 @@
+require "include";
+
+keep;
+
+include "circular-one";
diff --git a/pigeonhole/tests/extensions/include/included/circular-three-2.sieve b/pigeonhole/tests/extensions/include/included/circular-three-2.sieve
new file mode 100644
index 0000000..5199f21
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/circular-three-2.sieve
@@ -0,0 +1,3 @@
+require "include";
+
+include "circular-three-3";
diff --git a/pigeonhole/tests/extensions/include/included/circular-three-3.sieve b/pigeonhole/tests/extensions/include/included/circular-three-3.sieve
new file mode 100644
index 0000000..4c062cd
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/circular-three-3.sieve
@@ -0,0 +1,3 @@
+require "include";
+
+include "circular-three.sieve";
diff --git a/pigeonhole/tests/extensions/include/included/circular-three.sieve b/pigeonhole/tests/extensions/include/included/circular-three.sieve
new file mode 100644
index 0000000..13be546
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/circular-three.sieve
@@ -0,0 +1,7 @@
+require "include";
+
+keep;
+
+include "circular-three-2";
+
+
diff --git a/pigeonhole/tests/extensions/include/included/circular-two-2.sieve b/pigeonhole/tests/extensions/include/included/circular-two-2.sieve
new file mode 100644
index 0000000..d529214
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/circular-two-2.sieve
@@ -0,0 +1,3 @@
+require "include";
+
+include "circular-two.sieve";
diff --git a/pigeonhole/tests/extensions/include/included/circular-two.sieve b/pigeonhole/tests/extensions/include/included/circular-two.sieve
new file mode 100644
index 0000000..8a879cb
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/circular-two.sieve
@@ -0,0 +1,7 @@
+require "include";
+
+keep;
+
+include "circular-two-2";
+
+
diff --git a/pigeonhole/tests/extensions/include/included/depth-limit-1.sieve b/pigeonhole/tests/extensions/include/included/depth-limit-1.sieve
new file mode 100644
index 0000000..ce5571f
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/depth-limit-1.sieve
@@ -0,0 +1,3 @@
+require "include";
+
+include :personal "depth-limit-2";
diff --git a/pigeonhole/tests/extensions/include/included/depth-limit-2.sieve b/pigeonhole/tests/extensions/include/included/depth-limit-2.sieve
new file mode 100644
index 0000000..79c55e0
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/depth-limit-2.sieve
@@ -0,0 +1,3 @@
+require "include";
+
+include :personal "depth-limit-3";
diff --git a/pigeonhole/tests/extensions/include/included/depth-limit-3.sieve b/pigeonhole/tests/extensions/include/included/depth-limit-3.sieve
new file mode 100644
index 0000000..6203a21
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/depth-limit-3.sieve
@@ -0,0 +1 @@
+keep;
diff --git a/pigeonhole/tests/extensions/include/included/namespace.dict b/pigeonhole/tests/extensions/include/included/namespace.dict
new file mode 100644
index 0000000..35d7aaa
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/namespace.dict
@@ -0,0 +1,4 @@
+priv/sieve/name/namespace
+1
+priv/sieve/data/1
+require ["variables", "include"]; set "global.a" "personal";
diff --git a/pigeonhole/tests/extensions/include/included/namespace.sieve b/pigeonhole/tests/extensions/include/included/namespace.sieve
new file mode 100644
index 0000000..3f5738f
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/namespace.sieve
@@ -0,0 +1,4 @@
+require "include";
+require "variables";
+
+set "global.a" "personal";
diff --git a/pigeonhole/tests/extensions/include/included/once-1.sieve b/pigeonhole/tests/extensions/include/included/once-1.sieve
new file mode 100644
index 0000000..288d141
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/once-1.sieve
@@ -0,0 +1,9 @@
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "${result} ONE";
+
+return;
+
diff --git a/pigeonhole/tests/extensions/include/included/once-2.sieve b/pigeonhole/tests/extensions/include/included/once-2.sieve
new file mode 100644
index 0000000..abf29e5
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/once-2.sieve
@@ -0,0 +1,12 @@
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "${result} TWO";
+
+keep;
+
+include :once "once-1";
+
+return;
diff --git a/pigeonhole/tests/extensions/include/included/once-3.sieve b/pigeonhole/tests/extensions/include/included/once-3.sieve
new file mode 100644
index 0000000..739651e
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/once-3.sieve
@@ -0,0 +1,3 @@
+require "include";
+
+include "once-4";
diff --git a/pigeonhole/tests/extensions/include/included/once-4.sieve b/pigeonhole/tests/extensions/include/included/once-4.sieve
new file mode 100644
index 0000000..9cc1a47
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/once-4.sieve
@@ -0,0 +1,3 @@
+require "include";
+
+include :once "once-3";
diff --git a/pigeonhole/tests/extensions/include/included/optional-1.sieve b/pigeonhole/tests/extensions/include/included/optional-1.sieve
new file mode 100644
index 0000000..288d141
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/optional-1.sieve
@@ -0,0 +1,9 @@
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "${result} ONE";
+
+return;
+
diff --git a/pigeonhole/tests/extensions/include/included/optional-2.sieve b/pigeonhole/tests/extensions/include/included/optional-2.sieve
new file mode 100644
index 0000000..11920f5
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/optional-2.sieve
@@ -0,0 +1,9 @@
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "${result} TWO";
+
+keep;
+
diff --git a/pigeonhole/tests/extensions/include/included/rfc-ex1-always_allow.sieve b/pigeonhole/tests/extensions/include/included/rfc-ex1-always_allow.sieve
new file mode 100644
index 0000000..6dc8ddc
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/rfc-ex1-always_allow.sieve
@@ -0,0 +1,8 @@
+if header :is "From" "boss@example.com"
+{
+ keep;
+}
+elsif header :is "From" "ceo@example.com"
+{
+ keep;
+}
diff --git a/pigeonhole/tests/extensions/include/included/rfc-ex1-mailing_lists.sieve b/pigeonhole/tests/extensions/include/included/rfc-ex1-mailing_lists.sieve
new file mode 100644
index 0000000..d020972
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/rfc-ex1-mailing_lists.sieve
@@ -0,0 +1,10 @@
+require ["fileinto"];
+
+if header :is "Sender" "owner-ietf-mta-filters@imc.example.com"
+{
+ fileinto "lists.sieve";
+}
+elsif header :is "Sender" "owner-ietf-imapext@imc.example.com"
+{
+ fileinto "lists.imapext";
+}
diff --git a/pigeonhole/tests/extensions/include/included/rfc-ex1-spam_tests.sieve b/pigeonhole/tests/extensions/include/included/rfc-ex1-spam_tests.sieve
new file mode 100644
index 0000000..7916064
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/rfc-ex1-spam_tests.sieve
@@ -0,0 +1,10 @@
+require ["reject"];
+
+if header :contains "Subject" "XXXX"
+{
+ reject "Not wanted";
+}
+elsif header :is "From" "money@example.com"
+{
+ reject "Not wanted";
+}
diff --git a/pigeonhole/tests/extensions/include/included/rfc-ex2-spam_filter_script.sieve b/pigeonhole/tests/extensions/include/included/rfc-ex2-spam_filter_script.sieve
new file mode 100644
index 0000000..01ab984
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/rfc-ex2-spam_filter_script.sieve
@@ -0,0 +1,8 @@
+require ["variables", "include"];
+global ["test", "test_mailbox"];
+
+if header :contains "Subject" "${test}"
+{
+ set "test_mailbox" "spam-${test}";
+}
+
diff --git a/pigeonhole/tests/extensions/include/included/twice-1.sieve b/pigeonhole/tests/extensions/include/included/twice-1.sieve
new file mode 100644
index 0000000..a770a3b
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/twice-1.sieve
@@ -0,0 +1,7 @@
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "${result} TWO";
+
diff --git a/pigeonhole/tests/extensions/include/included/twice-2.sieve b/pigeonhole/tests/extensions/include/included/twice-2.sieve
new file mode 100644
index 0000000..eff9429
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/twice-2.sieve
@@ -0,0 +1,8 @@
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "${result} THREE";
+
+include "twice-1";
diff --git a/pigeonhole/tests/extensions/include/included/variables-included1.sieve b/pigeonhole/tests/extensions/include/included/variables-included1.sieve
new file mode 100644
index 0000000..5f6cb2f
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/variables-included1.sieve
@@ -0,0 +1,7 @@
+require "include";
+require "variables";
+
+global ["value1"];
+global ["result1"];
+
+set "result1" "${value1} ${global.value2}";
diff --git a/pigeonhole/tests/extensions/include/included/variables-included2.sieve b/pigeonhole/tests/extensions/include/included/variables-included2.sieve
new file mode 100644
index 0000000..135e03b
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/variables-included2.sieve
@@ -0,0 +1,6 @@
+require "include";
+require "variables";
+
+global ["value3", "value4"];
+
+set "global.result2" "${value3} ${value4}";
diff --git a/pigeonhole/tests/extensions/include/included/variables-included3.sieve b/pigeonhole/tests/extensions/include/included/variables-included3.sieve
new file mode 100644
index 0000000..51bb786
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/variables-included3.sieve
@@ -0,0 +1,8 @@
+require "include";
+require "variables";
+
+global "result1";
+global "result2";
+global "result";
+
+set "result" "${result1} ${result2}";
diff --git a/pigeonhole/tests/extensions/include/once.svtest b/pigeonhole/tests/extensions/include/once.svtest
new file mode 100644
index 0000000..3395c6b
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/once.svtest
@@ -0,0 +1,24 @@
+require "vnd.dovecot.testsuite";
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "";
+
+test "Included Once" {
+ include "once-1";
+ include "once-2";
+
+ if string "${result}" " ONE TWO ONE" {
+ test_fail "duplicate included :once script";
+ }
+
+ if not string "${result}" " ONE TWO" {
+ test_fail "unexpected result value: ${result}";
+ }
+}
+
+test "Included Once recursive" {
+ include "once-3";
+}
diff --git a/pigeonhole/tests/extensions/include/optional.svtest b/pigeonhole/tests/extensions/include/optional.svtest
new file mode 100644
index 0000000..345f830
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/optional.svtest
@@ -0,0 +1,40 @@
+require "vnd.dovecot.testsuite";
+require "include";
+require "variables";
+
+global "result";
+set "result" "";
+
+test "Included Optional" {
+ include :optional "optional-1";
+ include :optional "optional-2";
+
+ if not string "${result}" " ONE TWO" {
+ test_fail "unexpected result value: ${result}";
+ }
+
+ # missing
+ include :optional "optional-3";
+
+ if not string "${result}" " ONE TWO" {
+ test_fail "unexpected result value after missing script: ${result}";
+ }
+}
+
+
+test "Included Optional - Binary" {
+ if not test_script_compile "execute/optional.sieve" {
+ test_fail "failed to compile sieve script";
+ }
+
+ test_binary_save "optional";
+ test_binary_load "optional";
+
+ if not test_script_run {
+ test_fail "failed to execute sieve script";
+ }
+
+ if not string "${result}" " ONE TWO" {
+ test_fail "unexpected result value: ${result}";
+ }
+}
diff --git a/pigeonhole/tests/extensions/include/rfc-ex1-default.sieve b/pigeonhole/tests/extensions/include/rfc-ex1-default.sieve
new file mode 100644
index 0000000..5a8cb52
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/rfc-ex1-default.sieve
@@ -0,0 +1,6 @@
+require ["include"];
+
+include :personal "rfc-ex1-always_allow";
+include :global "rfc-ex1-spam_tests";
+include :personal "rfc-ex1-spam_tests";
+include :personal "rfc-ex1-mailing_lists";
diff --git a/pigeonhole/tests/extensions/include/rfc-ex2-default.sieve b/pigeonhole/tests/extensions/include/rfc-ex2-default.sieve
new file mode 100644
index 0000000..8b1bf4d
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/rfc-ex2-default.sieve
@@ -0,0 +1,21 @@
+require ["variables", "include", "relational", "fileinto"];
+global "test";
+global "test_mailbox";
+
+# The included script may contain repetitive code that is
+# effectively a subroutine that can be factored out.
+set "test" "$$";
+include "rfc-ex2-spam_filter_script";
+
+set "test" "Make money";
+include "rfc-ex2-spam_filter_script";
+
+# Message will be filed according to the test that matched last.
+if string :count "eq" "${test_mailbox}" "1"
+{
+ fileinto "INBOX${test_mailbox}";
+ stop;
+}
+
+# If nothing matched, the message is implicitly kept.
+
diff --git a/pigeonhole/tests/extensions/include/rfc.svtest b/pigeonhole/tests/extensions/include/rfc.svtest
new file mode 100644
index 0000000..00908ac
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/rfc.svtest
@@ -0,0 +1,13 @@
+require "vnd.dovecot.testsuite";
+
+test "RFC example 1" {
+ if not test_script_compile "rfc-ex1-default.sieve" {
+ test_fail "failed to compile sieve script";
+ }
+}
+
+test "RFC example 2" {
+ if not test_script_compile "rfc-ex2-default.sieve" {
+ test_fail "failed to compile sieve script";
+ }
+}
diff --git a/pigeonhole/tests/extensions/include/twice.svtest b/pigeonhole/tests/extensions/include/twice.svtest
new file mode 100644
index 0000000..5cd5da2
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/twice.svtest
@@ -0,0 +1,20 @@
+require "vnd.dovecot.testsuite";
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "ONE";
+
+test "Twice included" {
+ include "twice-1";
+ include "twice-2";
+
+ if string "${result}" "ONE TWO THREE" {
+ test_fail "duplicate include failed";
+ }
+
+ if not string "${result}" "ONE TWO THREE TWO" {
+ test_fail "unexpected result: ${result}";
+ }
+}
diff --git a/pigeonhole/tests/extensions/include/variables.svtest b/pigeonhole/tests/extensions/include/variables.svtest
new file mode 100644
index 0000000..5c4f8d8
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/variables.svtest
@@ -0,0 +1,29 @@
+require "vnd.dovecot.testsuite";
+
+require "include";
+require "variables";
+
+global ["value1", "value2"];
+set "value1" "Works";
+set "value2" "fine.";
+
+global ["value3", "value4"];
+set "value3" "Yeah";
+set "value4" "it does.";
+
+include "variables-included1";
+include "variables-included2";
+include "variables-included3";
+
+global "result";
+
+test "Basic" {
+ if not string :is "${result}" "Works fine. Yeah it does." {
+ test_fail "invalid result: ${result}";
+ }
+
+ if string :is "${result}" "nonsense" {
+ test_fail "string test succeeds inappropriately";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/index/basic.svtest b/pigeonhole/tests/extensions/index/basic.svtest
new file mode 100644
index 0000000..0706022
--- /dev/null
+++ b/pigeonhole/tests/extensions/index/basic.svtest
@@ -0,0 +1,93 @@
+require "vnd.dovecot.testsuite";
+require "index";
+require "date";
+require "variables";
+require "subaddress";
+
+test_set "message" text:
+To: first@friep.example.com
+X-A: First
+Received: from mx.example.com (127.0.0.13) by mx.example.org
+ (127.0.0.12) with Macrosoft SMTP Server (TLS) id 1.2.3.4;
+ Wed, 12 Nov 2014 18:18:31 +0100
+To: second@friep.example.com
+From: stephan@example.org
+Received: from mx.example.com (127.0.0.13) by mx.example.org
+ (127.0.0.12) with Macrosoft SMTP Server (TLS) id 1.2.3.4;
+ Wed, 12 Nov 2014 18:18:30 +0100
+X-A: Second
+To: third@friep.example.com
+X-A: Third
+Received: from mx.example.com (127.0.0.13) by mx.example.org
+ (127.0.0.12) with Macrosoft SMTP Server (TLS) id 1.2.3.4;
+ Wed, 12 Nov 2014 18:18:29 +0100
+Subject: Frop!
+X-A: Fourth
+To: fourth@friep.example.com
+Received: from mx.example.com (127.0.0.13) by mx.example.org
+ (127.0.0.12) with Macrosoft SMTP Server (TLS) id 1.2.3.4;
+ Wed, 12 Nov 2014 18:18:28 +0100
+
+Frop
+.
+;
+
+test "Header :index" {
+ if not header :index 3 "x-a" "Third" {
+ test_fail "wrong header retrieved";
+ }
+
+ if header :index 3 "x-a" ["First", "Second", "Fourth"] {
+ test_fail "other header retrieved";
+ }
+}
+
+test "Header :index :last" {
+ if not header :index 3 :last "x-a" "Second" {
+ test_fail "wrong header retrieved";
+ }
+
+ if header :index 3 :last "x-a" ["First", "Third", "Fourth"] {
+ test_fail "other header retrieved";
+ }
+}
+
+test "Address :index" {
+ if not address :localpart :index 2 "to" "second" {
+ test_fail "wrong header retrieved";
+ }
+
+ if address :localpart :index 2 "to" ["first", "third", "fourth"] {
+ test_fail "other header retrieved";
+ }
+}
+
+test "Address :index :last" {
+ if not address :localpart :index 2 :last "to" "third" {
+ test_fail "wrong header retrieved";
+ }
+
+ if address :localpart :index 2 :last "to" ["first", "second", "fourth"] {
+ test_fail "other header retrieved";
+ }
+}
+
+test "Date :index" {
+ if not date :index 1 "received" "second" "31" {
+ test_fail "wrong header retrieved";
+ }
+
+ if date :index 1 "received" "second" ["30", "29", "28"] {
+ test_fail "other header retrieved";
+ }
+}
+
+test "Date :index :last" {
+ if not date :index 1 :last "received" "second" "28"{
+ test_fail "wrong header retrieved";
+ }
+
+ if date :index 1 :last "received" "second" ["31", "30", "29"] {
+ test_fail "other header retrieved";
+ }
+}
diff --git a/pigeonhole/tests/extensions/index/errors.svtest b/pigeonhole/tests/extensions/index/errors.svtest
new file mode 100644
index 0000000..4bfe2dc
--- /dev/null
+++ b/pigeonhole/tests/extensions/index/errors.svtest
@@ -0,0 +1,20 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Invalid syntax
+ */
+
+test "Invalid Syntax" {
+ if test_script_compile "errors/syntax.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "7" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+
diff --git a/pigeonhole/tests/extensions/index/errors/syntax.sieve b/pigeonhole/tests/extensions/index/errors/syntax.sieve
new file mode 100644
index 0000000..ee19d88
--- /dev/null
+++ b/pigeonhole/tests/extensions/index/errors/syntax.sieve
@@ -0,0 +1,26 @@
+require "date";
+require "index";
+
+# Not an error
+if header :last :index 2 "to" "ok" { }
+
+# Not an error
+if header :index 444 :last "to" "ok" { }
+
+# 1: missing argument
+if header :index "to" "ok" {}
+
+# 2: missing argument
+if header :index :last "to" "ok" {}
+
+# 3: erroneous string argument
+if header :index "frop" "to" "ok" {}
+
+# 4: last without index
+if header :last "to" "ok" {}
+
+# 5: index 0
+if header :index 0 "to" "ok" {}
+
+# 6: index 0 last
+if header :index 0 :last "to" "ok" {}
diff --git a/pigeonhole/tests/extensions/mailbox/errors.svtest b/pigeonhole/tests/extensions/mailbox/errors.svtest
new file mode 100644
index 0000000..0821f52
--- /dev/null
+++ b/pigeonhole/tests/extensions/mailbox/errors.svtest
@@ -0,0 +1,40 @@
+require "vnd.dovecot.testsuite";
+require "variables";
+require "vnd.dovecot.debug";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Invalid syntax
+ */
+
+test "Invalid Syntax" {
+ if test_script_compile "errors/syntax.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ # FIXME: check warnings
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "12" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Mailboxexists - bad UTF-8 in mailbox name
+ */
+
+test "Mailboxexists - bad UTF-8 in mailbox name" {
+ if not test_script_compile "errors/mailboxexists-bad-utf8.sieve" {
+ test_fail "compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "execution failed";
+ }
+
+ # FIXME: check warnings
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "0" {
+ test_fail "wrong number of runtime errors reported";
+ }
+}
diff --git a/pigeonhole/tests/extensions/mailbox/errors/mailboxexists-bad-utf8.sieve b/pigeonhole/tests/extensions/mailbox/errors/mailboxexists-bad-utf8.sieve
new file mode 100644
index 0000000..e68e00e
--- /dev/null
+++ b/pigeonhole/tests/extensions/mailbox/errors/mailboxexists-bad-utf8.sieve
@@ -0,0 +1,9 @@
+require "mailbox";
+require "variables";
+require "encoded-character";
+
+set "mailbox" "${hex:ff}rop";
+if mailboxexists "${mailbox}" {
+ keep;
+}
+
diff --git a/pigeonhole/tests/extensions/mailbox/errors/syntax.sieve b/pigeonhole/tests/extensions/mailbox/errors/syntax.sieve
new file mode 100644
index 0000000..727a6e8
--- /dev/null
+++ b/pigeonhole/tests/extensions/mailbox/errors/syntax.sieve
@@ -0,0 +1,41 @@
+require "mailbox";
+require "fileinto";
+require "encoded-character";
+
+# 1
+if mailboxexists {}
+# 2
+if mailboxexists 3423 {}
+# 3
+if mailboxexists :frop {}
+# 4
+if mailboxexists 24234 "\\Sent" {}
+# 5
+if mailboxexists "frop" 32234 {}
+# 6
+if mailboxexists "frop" :friep {}
+
+if mailboxexists "frop" {}
+if mailboxexists ["frop", "friep"] {}
+
+# W:1
+if mailboxexists "${hex:ff}rop" {}
+# W:2
+if mailboxexists ["frop", "${hex:ff}riep"] {}
+
+# 7
+if mailboxexists "frop" ["frop"] {}
+
+# 8
+fileinto :create 343 "frop";
+# 9
+fileinto :create :frop "frop";
+# 10
+fileinto :create 234234;
+
+fileinto :create "frop";
+
+# 11
+fileinto :create "${hex:ff}rop";
+
+
diff --git a/pigeonhole/tests/extensions/mailbox/execute.svtest b/pigeonhole/tests/extensions/mailbox/execute.svtest
new file mode 100644
index 0000000..cba3034
--- /dev/null
+++ b/pigeonhole/tests/extensions/mailbox/execute.svtest
@@ -0,0 +1,80 @@
+require "vnd.dovecot.testsuite";
+require "mailbox";
+require "fileinto";
+
+test "MailboxExists - None exist" {
+ if mailboxexists "frop" {
+ test_fail "mailboxexists confirms existance of unknown folder";
+ }
+}
+
+test_mailbox_create "frop";
+test_mailbox_create "friep";
+
+test "MailboxExists - Not all exist" {
+ if mailboxexists ["frop", "friep", "frml"] {
+ test_fail "mailboxexists confirms existance of unknown folder";
+ }
+}
+
+test_mailbox_create "frml";
+
+test "MailboxExists - One exists" {
+ if not mailboxexists ["frop"] {
+ test_fail "mailboxexists fails to recognize folder";
+ }
+}
+
+test "MailboxExists - All exist" {
+ if not mailboxexists ["frop", "friep", "frml"] {
+ test_fail "mailboxexists fails to recognize folders";
+ }
+}
+
+test ":Create" {
+ if mailboxexists "created" {
+ test_fail "mailbox exists already";
+ }
+
+ test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop 1
+
+Frop!
+.
+ ;
+
+ fileinto :create "created";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ if not mailboxexists "created" {
+ test_fail "mailbox somehow not created";
+ }
+
+ test_result_reset;
+
+ test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop 2
+
+Frop!
+.
+ ;
+
+ fileinto "created";
+
+ if not test_result_execute {
+ test_fail "execution of result failed second time";
+ }
+
+ test_message :folder "created" 0;
+
+ if not header :is "subject" "Frop 1" {
+ test_fail "incorrect message read back from mail store";
+ }
+}
diff --git a/pigeonhole/tests/extensions/metadata/errors.svtest b/pigeonhole/tests/extensions/metadata/errors.svtest
new file mode 100644
index 0000000..3602484
--- /dev/null
+++ b/pigeonhole/tests/extensions/metadata/errors.svtest
@@ -0,0 +1,56 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Invalid syntax
+ */
+
+test "Invalid Syntax" {
+ if test_script_compile "errors/syntax.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "27" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Metadataexists - bad UTF-8 in mailbox name
+ */
+
+test "Metadataexists - bad UTF-8 in mailbox name" {
+ if not test_script_compile "errors/metadataexists-bad-utf8.sieve" {
+ test_fail "compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "execution failed";
+ }
+
+ # FIXME: check warnings
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "0" {
+ test_fail "wrong number of runtime errors reported";
+ }
+}
+
+/*
+ * Metadata - bad UTF-8 in mailbox name
+ */
+
+test "Metadata - bad UTF-8 in mailbox name" {
+ if not test_script_compile "errors/metadata-bad-utf8.sieve" {
+ test_fail "compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "execution failed";
+ }
+
+ # FIXME: check warnings
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "0" {
+ test_fail "wrong number of runtime errors reported";
+ }
+}
diff --git a/pigeonhole/tests/extensions/metadata/errors/metadata-bad-utf8.sieve b/pigeonhole/tests/extensions/metadata/errors/metadata-bad-utf8.sieve
new file mode 100644
index 0000000..fd093a3
--- /dev/null
+++ b/pigeonhole/tests/extensions/metadata/errors/metadata-bad-utf8.sieve
@@ -0,0 +1,9 @@
+require "mboxmetadata";
+require "variables";
+require "encoded-character";
+
+set "mailbox" "${hex:ff}rop";
+if metadata "${mailbox}" "/private/frop" "friep" {
+ keep;
+}
+
diff --git a/pigeonhole/tests/extensions/metadata/errors/metadataexists-bad-utf8.sieve b/pigeonhole/tests/extensions/metadata/errors/metadataexists-bad-utf8.sieve
new file mode 100644
index 0000000..dbb5023
--- /dev/null
+++ b/pigeonhole/tests/extensions/metadata/errors/metadataexists-bad-utf8.sieve
@@ -0,0 +1,9 @@
+require "mboxmetadata";
+require "variables";
+require "encoded-character";
+
+set "mailbox" "${hex:ff}rop";
+if metadataexists "${mailbox}" ["/private/frop", "/shared/friep"] {
+ keep;
+}
+
diff --git a/pigeonhole/tests/extensions/metadata/errors/syntax.sieve b/pigeonhole/tests/extensions/metadata/errors/syntax.sieve
new file mode 100644
index 0000000..c719d94
--- /dev/null
+++ b/pigeonhole/tests/extensions/metadata/errors/syntax.sieve
@@ -0,0 +1,53 @@
+require "mboxmetadata";
+require "servermetadata";
+require "encoded-character";
+
+# 1-4: Used as a command
+metadata;
+metadataexists;
+servermetadata;
+servermetadataexists;
+
+# 5-8: Used with no argument
+if metadata {}
+if metadataexists {}
+if servermetadata {}
+if servermetadataexists {}
+
+# 9-11: Used with one string argument
+if metadata "frop" { }
+if servermetadata "frop" { }
+if metadataexists "frop" { }
+
+# 12-15: Used with one number argument
+if metadata 13123123 { }
+if servermetadata 123123 { }
+if metadataexists 123123 { }
+if servermetadataexists 123123 {}
+
+# 16-18: Used with one string list argument
+if metadata ["frop"] { }
+if servermetadata ["frop"] { }
+if metadataexists ["frop"] { }
+
+# 19-22: Used with unknown tag
+if metadata :frop "frop" { }
+if servermetadata :frop "frop" { }
+if metadataexists :frop "frop" { }
+if servermetadataexists :frop "frop" {}
+
+# 23-26: Invalid arguments
+if metadata "/private/frop" "friep" {}
+if servermetadata "INBOX" "/private/frop" "friep" {}
+if metadataexists 23 "/private/frop" {}
+if servermetadataexists "INBOX" "/private/frop" {}
+
+# W1-W4: Invalid annotations
+if metadata "INBOX" "frop" "friep" {}
+if servermetadata "frop" "friep" {}
+if metadataexists "INBOX" ["/private/frop", "/friep"] { }
+if servermetadataexists ["/private/frop", "/friep", "/private/friep"] { }
+
+# W5-W6: Invalid mailbox name
+if metadata "${hex:ff}rop" "/private/frop" "friep" {}
+if metadataexists "${hex:ff}rop" ["/private/frop", "/shared/friep"] { }
diff --git a/pigeonhole/tests/extensions/metadata/execute.svtest b/pigeonhole/tests/extensions/metadata/execute.svtest
new file mode 100644
index 0000000..32aac82
--- /dev/null
+++ b/pigeonhole/tests/extensions/metadata/execute.svtest
@@ -0,0 +1,145 @@
+require "vnd.dovecot.testsuite";
+require "mboxmetadata";
+require "servermetadata";
+require "fileinto";
+
+test "MetadataExists - None exist" {
+ if metadataexists "INBOX" "/private/frop" {
+ test_fail "metadataexists confirms existence of unknown annotation";
+ }
+}
+
+test_imap_metadata_set :mailbox "INBOX" "/private/frop" "FROP!";
+test_imap_metadata_set :mailbox "INBOX" "/private/friep" "FRIEP!";
+
+test "MetadataExists - Not all exist" {
+ if metadataexists "INBOX"
+ ["/private/frop", "/private/friep", "/private/frml"] {
+ test_fail "metadataexists confirms existence of unknown annotation";
+ }
+}
+
+test_imap_metadata_set :mailbox "INBOX" "/private/friep" "FRIEP!";
+test_imap_metadata_set :mailbox "INBOX" "/private/frml" "FRML!";
+
+test "MetadataExists - One exists" {
+ if not metadataexists "INBOX" ["/private/frop"] {
+ test_fail "metadataexists fails to recognize annotation";
+ }
+}
+
+test "MetadataExists - All exist" {
+ if not metadataexists "INBOX"
+ ["/private/frop", "/private/friep", "/private/frml"] {
+ test_fail "metadataexists fails to recognize annotations";
+ }
+}
+
+test "MetadataExists - Invalid" {
+ if metadataexists "INBOX"
+ ["/shared/frop", "/friep", "/private/frml"] {
+ test_fail "metadataexists accepted invalid annotation name";
+ }
+}
+
+test "Metadata" {
+ if not metadata :is "INBOX" "/private/frop" "FROP!" {
+ test_fail "invalid metadata value for /private/frop";
+ }
+ if metadata :is "INBOX" "/private/frop" "Hutsefluts" {
+ test_fail "unexpected match for /private/frop";
+ }
+
+ if not metadata :is "INBOX" "/private/friep" "FRIEP!" {
+ test_fail "invalid metadata value for /private/friep";
+ }
+ if metadata :is "INBOX" "/private/friep" "Hutsefluts" {
+ test_fail "unexpected match for /private/friep";
+ }
+
+ if not metadata :is "INBOX" "/private/frml" "FRML!" {
+ test_fail "invalid metadata value for /private/frml";
+ }
+ if metadata :is "INBOX" "/private/frml" "Hutsefluts" {
+ test_fail "unexpected match for /private/frml";
+ }
+}
+
+test "Metadata - Invalid" {
+ if metadata :contains "INBOX" "/frop" "" {
+ test_fail "erroneously found a value for \"/frop\"";
+ }
+}
+
+test "ServermetadataExists - None exist" {
+ if servermetadataexists "/private/frop" {
+ test_fail "servermetadataexists confirms existence of unknown annotation";
+ }
+}
+
+# currently not possible to test servermetadata
+if false {
+
+test_imap_metadata_set "/private/frop" "FROP!";
+test_imap_metadata_set "/private/friep" "FRIEP!";
+
+test "ServermetadataExists - Not all exist" {
+ if servermetadataexists
+ ["/private/frop", "/private/friep", "/private/frml"] {
+ test_fail "metadataexists confirms existence of unknown annotation";
+ }
+}
+
+test_imap_metadata_set "/private/friep" "FRIEP!";
+test_imap_metadata_set "/private/frml" "FRML!";
+
+test "ServermetadataExists - One exists" {
+ if not servermetadataexists ["/private/frop"] {
+ test_fail "servermetadataexists fails to recognize annotation";
+ }
+}
+
+test "ServermetadataExists - All exist" {
+ if not servermetadataexists
+ ["/private/frop", "/private/friep", "/private/frml"] {
+ test_fail "servermetadataexists fails to recognize annotations";
+ }
+}
+
+test "ServermetadataExists - Invalid" {
+ if servermetadataexists
+ ["frop", "/private/friep", "/private/frml"] {
+ test_fail "servermetadataexists accepted invalid annotation name";
+ }
+}
+
+test "Servermetadata" {
+ if not servermetadata :is "/private/frop" "FROP!" {
+ test_fail "invalid servermetadata value for /private/frop";
+ }
+ if servermetadata :is "/private/frop" "Hutsefluts" {
+ test_fail "unexpected match for /private/frop";
+ }
+
+ if not servermetadata :is "/private/friep" "FRIEP!" {
+ test_fail "invalid servermetadata value for /private/friep";
+ }
+ if servermetadata :is "/private/friep" "Hutsefluts" {
+ test_fail "unexpected match for /private/friep";
+ }
+
+ if not servermetadata :is "/private/frml" "FRML!" {
+ test_fail "invalid servermetadata value for /private/frml";
+ }
+ if servermetadata :is "/private/frml" "Hutsefluts" {
+ test_fail "unexpected match for /private/frml";
+ }
+}
+
+test "Servermetadata - Invalid" {
+ if servermetadata :contains "/frop" "" {
+ test_fail "erroneously found a value for \"/frop\"";
+ }
+}
+
+} #disabled
diff --git a/pigeonhole/tests/extensions/mime/address.svtest b/pigeonhole/tests/extensions/mime/address.svtest
new file mode 100644
index 0000000..1607450
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/address.svtest
@@ -0,0 +1,281 @@
+require "vnd.dovecot.testsuite";
+require "mime";
+require "foreverypart";
+
+/*
+ * Basic functionionality
+ */
+
+test_set "message" text:
+From: stephan@example.com
+To: nico@nl.example.com, harry@de.example.com
+cc: Timo <tss(no spam)@fi.iki>
+Subject: Frobnitzm
+
+Test.
+.
+;
+
+test "Basic functionality" {
+ /* Must match */
+ if not address :mime :anychild :contains ["to", "from"] "harry" {
+ test_fail "failed to match address (1)";
+ }
+
+ if not address :mime :anychild :contains ["to", "from"] "de.example" {
+ test_fail "failed to match address (2)";
+ }
+
+ if not address :mime :anychild :matches "to" "*@*.example.com" {
+ test_fail "failed to match address (3)";
+ }
+
+ if not address :mime :anychild :is "to" "harry@de.example.com" {
+ test_fail "failed to match address (4)";
+ }
+
+ /* Must not match */
+ if address :mime :anychild :is ["to", "from"] "nonsense@example.com" {
+ test_fail "matches erroneous address";
+ }
+
+ /* Match first key */
+ if not address :mime :anychild :contains ["to"] ["nico", "fred", "henk"] {
+ test_fail "failed to match first key";
+ }
+
+ /* Match second key */
+ if not address :mime :anychild :contains ["to"] ["fred", "nico", "henk"] {
+ test_fail "failed to match second key";
+ }
+
+ /* Match last key */
+ if not address :mime :anychild :contains ["to"] ["fred", "henk", "nico"] {
+ test_fail "failed to match last key";
+ }
+
+ /* First header */
+ if not address :mime :anychild :contains
+ ["to", "from"] ["fred", "nico", "henk"] {
+ test_fail "failed to match first header";
+ }
+
+ /* Second header */
+ if not address :mime :anychild :contains
+ ["from", "to"] ["fred", "nico", "henk"] {
+ test_fail "failed to match second header";
+ }
+
+ /* Comment */
+ if not address :mime :anychild :is "cc" "tss@fi.iki" {
+ test_fail "failed to ignore comment in address";
+ }
+}
+
+/*
+ * Basic functionionality - foreverypart
+ */
+
+test "Basic functionality - foreverypart" {
+ foreverypart {
+ /* Must match */
+ if not address :mime :anychild :contains ["to", "from"] "harry" {
+ test_fail "failed to match address (1)";
+ }
+
+ if not address :mime :anychild :contains ["to", "from"] "de.example" {
+ test_fail "failed to match address (2)";
+ }
+
+ if not address :mime :anychild :matches "to" "*@*.example.com" {
+ test_fail "failed to match address (3)";
+ }
+
+ if not address :mime :anychild :is "to" "harry@de.example.com" {
+ test_fail "failed to match address (4)";
+ }
+
+ /* Must not match */
+ if address :mime :anychild :is ["to", "from"] "nonsense@example.com" {
+ test_fail "matches erroneous address";
+ }
+
+ /* Match first key */
+ if not address :mime :anychild :contains ["to"] ["nico", "fred", "henk"] {
+ test_fail "failed to match first key";
+ }
+
+ /* Match second key */
+ if not address :mime :anychild :contains ["to"] ["fred", "nico", "henk"] {
+ test_fail "failed to match second key";
+ }
+
+ /* Match last key */
+ if not address :mime :anychild :contains ["to"] ["fred", "henk", "nico"] {
+ test_fail "failed to match last key";
+ }
+
+ /* First header */
+ if not address :mime :anychild :contains
+ ["to", "from"] ["fred", "nico", "henk"] {
+ test_fail "failed to match first header";
+ }
+
+ /* Second header */
+ if not address :mime :anychild :contains
+ ["from", "to"] ["fred", "nico", "henk"] {
+ test_fail "failed to match second header";
+ }
+
+ /* Comment */
+ if not address :mime :anychild :is "cc" "tss@fi.iki" {
+ test_fail "failed to ignore comment in address";
+ }
+ }
+}
+
+/*
+ * Address headers
+ */
+
+test_set "message" text:
+From: stephan@friep.frop
+To: henk@tukkerland.ex
+CC: ivo@boer.ex
+Bcc: joop@hooibaal.ex
+Sender: s.bosch@friep.frop
+Resent-From: ivo@boer.ex
+Resent-To: idioot@dombo.ex
+Subject: Berichtje
+
+Test.
+.
+;
+
+test "Address headers" {
+ if not address :mime :anychild "from" "stephan@friep.frop" {
+ test_fail "from header not recognized";
+ }
+
+ if not address :mime :anychild "to" "henk@tukkerland.ex" {
+ test_fail "to header not recognized";
+ }
+
+ if not address :mime :anychild "cc" "ivo@boer.ex" {
+ test_fail "cc header not recognized";
+ }
+
+ if not address :mime :anychild "bcc" "joop@hooibaal.ex" {
+ test_fail "bcc header not recognized";
+ }
+
+ if not address :mime :anychild "sender" "s.bosch@friep.frop" {
+ test_fail "sender header not recognized";
+ }
+
+ if not address :mime :anychild "resent-from" "ivo@boer.ex" {
+ test_fail "resent-from header not recognized";
+ }
+
+ if not address :mime :anychild "resent-to" "idioot@dombo.ex" {
+ test_fail "resent-to header not recognized";
+ }
+}
+
+/*
+ * Address headers - foreverypart
+ */
+
+test "Address headers - foreverypart" {
+ foreverypart {
+ if not address :mime :anychild "from" "stephan@friep.frop" {
+ test_fail "from header not recognized";
+ }
+
+ if not address :mime :anychild "to" "henk@tukkerland.ex" {
+ test_fail "to header not recognized";
+ }
+
+ if not address :mime :anychild "cc" "ivo@boer.ex" {
+ test_fail "cc header not recognized";
+ }
+
+ if not address :mime :anychild "bcc" "joop@hooibaal.ex" {
+ test_fail "bcc header not recognized";
+ }
+
+ if not address :mime :anychild "sender" "s.bosch@friep.frop" {
+ test_fail "sender header not recognized";
+ }
+
+ if not address :mime :anychild "resent-from" "ivo@boer.ex" {
+ test_fail "resent-from header not recognized";
+ }
+
+ if not address :mime :anychild "resent-to" "idioot@dombo.ex" {
+ test_fail "resent-to header not recognized";
+ }
+ }
+}
+
+/*
+ * Multipart anychild
+ */
+
+test_set "message" text:
+From: Hendrik <hendrik@example.com>
+To: Harrie <harrie@example.com>
+Date: Sat, 11 Oct 2010 00:31:44 +0200
+Subject: Harrie is een prutser
+Content-Type: multipart/mixed; boundary=AA
+CC: AA@example.com
+
+This is a multi-part message in MIME format.
+--AA
+Content-Type: multipart/mixed; boundary=BB
+CC: BB@example.com
+
+This is a multi-part message in MIME format.
+--BB
+Content-Type: text/plain; charset="us-ascii"
+CC: CC@example.com
+
+Hello
+
+--BB
+Content-Type: text/plain; charset="us-ascii"
+CC: DD@example.com
+
+Hello again
+
+--BB--
+This is the end of MIME multipart.
+
+--AA
+Content-Type: text/plain; charset="us-ascii"
+CC: EE@example.com
+
+And again
+
+--AA--
+This is the end of MIME multipart.
+.
+;
+
+test "Multipart anychild" {
+ if not address :mime :anychild :localpart "Cc" "AA" {
+ test_fail "AA Cc repient does not exist";
+ }
+ if not address :mime :anychild :localpart "Cc" "BB" {
+ test_fail "BB Cc repient does not exist";
+ }
+ if not address :mime :anychild :localpart "Cc" "CC" {
+ test_fail "CC Cc repient does not exist";
+ }
+ if not address :mime :anychild :localpart "Cc" "DD" {
+ test_fail "DD Cc repient does not exist";
+ }
+ if not address :mime :anychild :localpart "Cc" "EE" {
+ test_fail "EE Cc repient does not exist";
+ }
+}
diff --git a/pigeonhole/tests/extensions/mime/calendar-example.svtest b/pigeonhole/tests/extensions/mime/calendar-example.svtest
new file mode 100644
index 0000000..745e6e6
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/calendar-example.svtest
@@ -0,0 +1,129 @@
+require "vnd.dovecot.testsuite";
+require "mime";
+require "foreverypart";
+require "editheader";
+require "relational";
+require "variables";
+
+# Example from RFC 6047, Section 2.5:
+test_set "message" text:
+From: user1@example.com
+To: user2@example.com
+Subject: Phone Conference
+Mime-Version: 1.0
+Date: Wed, 07 May 2008 21:30:25 +0400
+Message-ID: <4821E731.5040506@laptop1.example.com>
+Content-Type: text/calendar; method=REQUEST; charset=UTF-8
+Content-Transfer-Encoding: quoted-printable
+
+BEGIN:VCALENDAR
+PRODID:-//Example/ExampleCalendarClient//EN
+METHOD:REQUEST
+VERSION:2.0
+BEGIN:VEVENT
+ORGANIZER:mailto:user1@example.com
+ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:user1@example.com
+ATTENDEE;RSVP=YES;CUTYPE=INDIVIDUAL:mailto:user2@example.com
+DTSTAMP:20080507T170000Z
+DTSTART:20080701T160000Z
+DTEND:20080701T163000Z
+SUMMARY:Phone call to discuss your last visit
+DESCRIPTION:=D1=82=D1=8B =D0=BA=D0=B0=D0=BA - =D0=B4=D0=BE=D0=
+ =B2=D0=BE=D0=BB=D0=B5=D0=BD =D0=BF=D0=BE=D0=B5=D0=B7=D0=B4=D0=BA=D0
+ =BE=D0=B9?
+UID:calsvr.example.com-8739701987387998
+SEQUENCE:0
+STATUS:TENTATIVE
+END:VEVENT
+END:VCALENDAR
+.
+;
+
+test "Calendar only" {
+ foreverypart {
+ if allof(
+ header :mime :count "eq" "Content-Type" "1",
+ header :mime :contenttype "Content-Type" "text/calendar",
+ header :mime :param "method" :matches "Content-Type" "*",
+ header :mime :param "charset" :is "Content-Type" "UTF-8" ) {
+ addheader "X-ICAL" "${1}";
+ break;
+ }
+ }
+
+ if not header "x-ical" "request" {
+ test_fail "Failed to parse message correctly";
+ }
+}
+
+# Modified example
+test_set "message" text:
+From: user1@example.com
+To: user2@example.com
+Subject: Phone Conference
+Mime-Version: 1.0
+Date: Wed, 07 May 2008 21:30:25 +0400
+Message-ID: <4821E731.5040506@laptop1.example.com>
+Content-Type: multipart/mixed; boundary=AA
+
+This is a multi-part message in MIME format.
+
+--AA
+Content-Type: text/plain
+
+Hello,
+
+I'd like to discuss your last visit. A tentative meeting schedule is
+attached.
+
+Regards,
+
+User1
+
+--AA
+Content-Type: text/calendar; method=REQUEST; charset=UTF-8
+Content-Transfer-Encoding: quoted-printable
+
+BEGIN:VCALENDAR
+PRODID:-//Example/ExampleCalendarClient//EN
+METHOD:REQUEST
+VERSION:2.0
+BEGIN:VEVENT
+ORGANIZER:mailto:user1@example.com
+ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:user1@example.com
+ATTENDEE;RSVP=YES;CUTYPE=INDIVIDUAL:mailto:user2@example.com
+DTSTAMP:20080507T170000Z
+DTSTART:20080701T160000Z
+DTEND:20080701T163000Z
+SUMMARY:Phone call to discuss your last visit
+DESCRIPTION:=D1=82=D1=8B =D0=BA=D0=B0=D0=BA - =D0=B4=D0=BE=D0=
+ =B2=D0=BE=D0=BB=D0=B5=D0=BD =D0=BF=D0=BE=D0=B5=D0=B7=D0=B4=D0=BA=D0
+ =BE=D0=B9?
+UID:calsvr.example.com-8739701987387998
+SEQUENCE:0
+STATUS:TENTATIVE
+END:VEVENT
+END:VCALENDAR
+
+--AA--
+.
+;
+
+test "Multipart message" {
+ foreverypart {
+ if allof(
+ header :mime :count "eq" "Content-Type" "1",
+ header :mime :contenttype "Content-Type" "text/calendar",
+ header :mime :param "method" :matches "Content-Type" "*",
+ header :mime :param "charset" :is "Content-Type" "UTF-8" ) {
+ addheader "X-ICAL" "${1}";
+ break;
+ }
+ }
+
+ if not header "x-ical" "request" {
+ test_fail "Failed to parse message correctly";
+ }
+}
+
+
diff --git a/pigeonhole/tests/extensions/mime/content-header.svtest b/pigeonhole/tests/extensions/mime/content-header.svtest
new file mode 100644
index 0000000..9686e35
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/content-header.svtest
@@ -0,0 +1,161 @@
+require "vnd.dovecot.testsuite";
+require "relational";
+require "mime";
+
+test_set "message" text:
+From: stephan@example.com
+To: timo@example.com
+Subject: Frop
+Content-Type: text/plain
+
+Frop
+.
+;
+
+test "Simple Content-Type :type" {
+ if not header :mime :type "content-type" "text" {
+ test_fail "wrong type extracted";
+ }
+}
+
+test "Simple Content-Type :subype" {
+ if not header :mime :subtype "content-type" "plain" {
+ test_fail "wrong subtype extracted";
+ }
+}
+
+test "Simple Content-Type :contenttype" {
+ if not header :mime :contenttype "content-type" "text/plain" {
+ test_fail "wrong contenttype extracted";
+ }
+}
+
+test_set "message" text:
+From: stephan@example.com
+To: timo@example.com
+Subject: Frop
+Content-Type: text/calendar; method=request; charset=UTF-8;
+
+Frop
+.
+;
+
+test "Advanced Content-Type :type" {
+ if not header :mime :type "content-type" "text" {
+ test_fail "wrong type extracted";
+ }
+}
+
+test "Advanced Content-Type :subype" {
+ if not header :mime :subtype "content-type" "calendar" {
+ test_fail "wrong subtype extracted";
+ }
+}
+
+test "Advanced Content-Type :contenttype" {
+ if not header :mime :contenttype "content-type" "text/calendar" {
+ test_fail "wrong contenttype extracted";
+ }
+}
+
+test "Advanced Content-Type :param" {
+ if not header :mime :param "method" "content-type" "request" {
+ test_fail "wrong method param extracted";
+ }
+
+ if not header :mime :param "charset" "content-type" "UTF-8" {
+ test_fail "wrong charset param extracted";
+ }
+
+ if not header :mime :param ["method", "charset"]
+ "content-type" "request" {
+ test_fail "wrong method param extracted";
+ }
+
+ if not header :mime :param ["method", "charset"]
+ "content-type" "UTF-8" {
+ test_fail "wrong charset param extracted";
+ }
+
+ if not header :count "eq" :mime :param ["method", "charset"]
+ "content-type" "2" {
+ test_fail "wrong number of parameters";
+ }
+}
+
+test_set "message" text:
+From: stephan@example.com
+To: timo@example.com
+Subject: Frop
+Content-Type: application/x-stuff;
+ title*0*=us-ascii'en'This%20is%20even%20more%20;
+ title*1*=%2A%2A%2Afun%2A%2A%2A%20;
+ title*2="isn't it!"
+
+Frop
+.
+;
+
+test "Encoded Content-Type :param" {
+ if not header :mime :param "title" "content-type"
+ "This is even more ***fun*** isn't it!" {
+ test_fail "wrong method param extracted";
+ }
+}
+
+test_set "message" text:
+From: stephan@example.com
+To: timo@example.com
+Subject: Frop
+Content-Type: image/png
+Content-Disposition: inline; filename="frop.exe"; title="Frop!"
+
+Frop
+.
+;
+
+test "Content-Disposition :type" {
+ if not header :mime :type "content-disposition" "inline" {
+ test_fail "wrong type extracted";
+ }
+}
+
+test "Content-Disposition :subype" {
+ if not header :mime :subtype "content-disposition" "" {
+ test_fail "wrong subtype extracted";
+ }
+}
+
+test "Content-Disposition :contenttype" {
+ if not header :mime :contenttype "content-disposition" "inline" {
+ test_fail "wrong contenttype extracted";
+ }
+}
+
+test "Content-Disposition :param" {
+ if not header :mime :param "filename" "content-disposition" "frop.exe" {
+ test_fail "wrong filename param extracted";
+ }
+
+ if not header :mime :param "title" "content-disposition" "Frop!" {
+ test_fail "wrong title param extracted";
+ }
+
+ if not header :mime :param ["filename", "title"]
+ "content-disposition" "frop.exe" {
+ test_fail "wrong filename param extracted";
+ }
+
+ if not header :mime :param ["filename", "title"]
+ "content-disposition" "Frop!" {
+ test_fail "wrong title param extracted";
+ }
+
+ if not header :count "eq" :mime :param ["filename", "title"]
+ "content-disposition" "2" {
+ test_fail "wrong number of parameters";
+ }
+
+}
+
+
diff --git a/pigeonhole/tests/extensions/mime/errors.svtest b/pigeonhole/tests/extensions/mime/errors.svtest
new file mode 100644
index 0000000..b3b858e
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/errors.svtest
@@ -0,0 +1,162 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+test "Foreverypart command" {
+ if test_script_compile "errors/foreverypart.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if test_error :count "ne" :comparator "i;ascii-numeric" "12" {
+ test_fail "incorrect number of compile errors reported";
+ }
+}
+
+test "Break command" {
+ if test_script_compile "errors/break.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if test_error :count "ne" :comparator "i;ascii-numeric" "21" {
+ test_fail "incorrect number of compile errors reported";
+ }
+}
+
+test "Header test with :mime tag" {
+ if test_script_compile "errors/header-mime-tag.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if test_error :count "ne" :comparator "i;ascii-numeric" "10" {
+ test_fail "incorrect number of compile errors reported";
+ }
+}
+
+test "Address test with :mime tag" {
+ if test_script_compile "errors/address-mime-tag.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if test_error :count "ne" :comparator "i;ascii-numeric" "6" {
+ test_fail "incorrect number of compile errors reported";
+ }
+}
+
+test "Exists test with :mime tag" {
+ if test_script_compile "errors/exists-mime-tag.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if test_error :count "ne" :comparator "i;ascii-numeric" "6" {
+ test_fail "incorrect number of compile errors reported";
+ }
+}
+
+test "Limits" {
+ if test_script_compile "errors/limits.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if test_error :count "ne" :comparator "i;ascii-numeric" "2" {
+ test_fail "incorrect number of compile errors reported";
+ }
+}
+
+test_set "message" text:
+From: Whomever <whoever@example.com>
+To: Someone <someone@example.com>
+Date: Sat, 10 Oct 2009 00:30:04 +0200
+Subject: whatever
+Content-Type: multipart/mixed; boundary=AA
+
+This is a multi-part message in MIME format.
+
+--AA
+Content-Type: multipart/alternative; boundary=BB
+
+This is a multi-part message in MIME format.
+
+--BB
+Content-Type: multipart/alternative; boundary=CC
+
+This is a multi-part message in MIME format.
+
+--CC
+Content-Type: multipart/alternative; boundary=DD
+
+This is a multi-part message in MIME format.
+
+--DD
+Content-Type: multipart/alternative; boundary=EE
+
+This is a nested multi-part message in MIME format.
+
+--EE
+Content-Type: text/plain; charset="us-ascii"
+
+Hello
+
+--EE--
+
+This is the end of the inner MIME multipart.
+
+--DD--
+
+This is the end of the MIME multipart.
+
+--CC--
+
+This is the end of the MIME multipart.
+
+--BB--
+
+This is the end of the MIME multipart.
+
+--AA--
+
+This is the end of the MIME multipart.
+.
+;
+
+test "Limits - include" {
+ if not test_script_compile "errors/limits-include.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if test_script_run {
+ test_fail "script run should have failed";
+ }
+}
+
+test "Extracttext" {
+ if test_script_compile "errors/extracttext.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if test_error :count "ne" :comparator "i;ascii-numeric" "11" {
+ test_fail "incorrect number of compile errors reported";
+ }
+}
+
+test "Extracttext - without variables" {
+ if test_script_compile "errors/extracttext-novar.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if test_error :count "ne" :comparator "i;ascii-numeric" "2" {
+ test_fail "incorrect number of compile errors reported";
+ }
+}
+
+test "Extracttext - without foreverypart" {
+ if test_script_compile "errors/extracttext-nofep.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if test_error :count "ne" :comparator "i;ascii-numeric" "2" {
+ test_fail "incorrect number of compile errors reported";
+ }
+}
+
+
diff --git a/pigeonhole/tests/extensions/mime/errors/address-mime-tag.sieve b/pigeonhole/tests/extensions/mime/errors/address-mime-tag.sieve
new file mode 100644
index 0000000..7adb7bc
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/errors/address-mime-tag.sieve
@@ -0,0 +1,38 @@
+require "mime";
+
+## Address
+
+# No error
+if address :contains :mime "To" "frop@example.com" {
+ discard;
+}
+
+# No error
+if address :anychild :contains :mime "To" "frop@example.com" {
+ discard;
+}
+
+# 1: Bare anychild option
+if address :anychild "To" "frop@example.com" {
+ discard;
+}
+
+# 2: Inappropriate option
+if address :mime :anychild :type "To" "frop@example.com" {
+ discard;
+}
+
+# 3: Inappropriate option
+if address :mime :anychild :subtype "To" "frop@example.com" {
+ discard;
+}
+
+# 4: Inappropriate option
+if address :mime :anychild :contenttype "To" "frop@example.com" {
+ discard;
+}
+
+# 5: Inappropriate option
+if address :mime :anychild :param "frop" "To" "frop@example.com" {
+ discard;
+}
diff --git a/pigeonhole/tests/extensions/mime/errors/break.sieve b/pigeonhole/tests/extensions/mime/errors/break.sieve
new file mode 100644
index 0000000..1858673
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/errors/break.sieve
@@ -0,0 +1,157 @@
+require "foreverypart";
+
+foreverypart :name "frop" {
+ # 1: Spurious tag
+ break :tag;
+
+ # 2: Spurious tests
+ break true;
+
+ # 3: Spurious tests
+ break anyof(true, false);
+
+ # 4: Bare string
+ break "frop";
+
+ # 5: Bare string-list
+ break ["frop", "friep"];
+
+ # 6: Several bad arguments
+ break 13 ["frop", "friep"];
+
+ # 7: Spurious additional tag
+ break :name "frop" :friep;
+
+ # 8: Spurious additional string
+ break :name "frop" "friep";
+
+ # 9: Bad name
+ break :name 13;
+
+ # 10: Bad name
+ break :name ["frop", "friep"];
+
+ # No error
+ break;
+
+ # No error
+ break :name "frop";
+
+ # No error
+ if exists "frop" {
+ break;
+ }
+
+ # No error
+ if exists "frop" {
+ break :name "frop";
+ }
+
+ # No error
+ foreverypart {
+ break :name "frop";
+ }
+
+ # No error
+ foreverypart :name "friep" {
+ break :name "frop";
+ }
+
+ # No error
+ foreverypart :name "friep" {
+ break :name "friep";
+ }
+
+ # No error
+ foreverypart :name "friep" {
+ break;
+ }
+
+ # No error
+ foreverypart {
+ if exists "frop" {
+ break :name "frop";
+ }
+ }
+
+ # No error
+ foreverypart :name "friep" {
+ if exists "frop" {
+ break :name "frop";
+ }
+ }
+
+ # No error
+ foreverypart :name "friep" {
+ if exists "frop" {
+ break :name "friep";
+ }
+ }
+
+ # No error
+ foreverypart :name "friep" {
+ if exists "frop" {
+ break;
+ }
+ }
+}
+
+# 11: Outside loop
+break;
+
+# 12: Outside loop
+if exists "frop" {
+ break;
+}
+
+# 13: Outside loop
+break :name "frop";
+
+# 14: Outside loop
+if exists "frop" {
+ break :name "frop";
+}
+
+# 15: Bad name
+foreverypart {
+ break :name "frop";
+}
+
+# 16: Bad name
+foreverypart {
+ if exists "frop" {
+ break :name "frop";
+ }
+}
+
+# 17: Bad name
+foreverypart :name "friep" {
+ break :name "frop";
+}
+
+# 18: Bad name
+foreverypart :name "friep" {
+ if exists "frop" {
+ break :name "frop";
+ }
+}
+
+# 19: Bad name
+foreverypart :name "friep" {
+ foreverypart :name "frop" {
+ break :name "frml";
+ }
+}
+
+# 20: Bad name
+foreverypart :name "friep" {
+ foreverypart :name "frop" {
+ if exists "frop" {
+ break :name "frml";
+ }
+ }
+}
+
+
+
+
diff --git a/pigeonhole/tests/extensions/mime/errors/exists-mime-tag.sieve b/pigeonhole/tests/extensions/mime/errors/exists-mime-tag.sieve
new file mode 100644
index 0000000..84c86a7
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/errors/exists-mime-tag.sieve
@@ -0,0 +1,43 @@
+require "mime";
+
+## Exists
+
+# No error
+if exists :mime "To" {
+ discard;
+}
+
+# No error
+if exists :anychild :mime "To" {
+ discard;
+}
+
+# 1: Inappropriate option
+if exists :anychild "To" {
+ discard;
+}
+
+# 2: Inappropriate option
+if exists :mime :type "To" {
+ discard;
+}
+
+# 3: Inappropriate option
+if exists :mime :subtype "To" {
+ discard;
+}
+
+# 4: Inappropriate option
+if exists :mime :contenttype "To" {
+ discard;
+}
+
+# 5: Inappropriate option
+if exists :mime :param ["frop", "friep"] "To" {
+ discard;
+}
+
+
+
+
+
diff --git a/pigeonhole/tests/extensions/mime/errors/extracttext-nofep.sieve b/pigeonhole/tests/extensions/mime/errors/extracttext-nofep.sieve
new file mode 100644
index 0000000..c38b228
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/errors/extracttext-nofep.sieve
@@ -0,0 +1,4 @@
+require "extracttext";
+require "variables";
+
+keep;
diff --git a/pigeonhole/tests/extensions/mime/errors/extracttext-novar.sieve b/pigeonhole/tests/extensions/mime/errors/extracttext-novar.sieve
new file mode 100644
index 0000000..8e2a378
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/errors/extracttext-novar.sieve
@@ -0,0 +1,6 @@
+require "extracttext";
+require "foreverypart";
+
+foreverypart {
+ extracttext "frop";
+}
diff --git a/pigeonhole/tests/extensions/mime/errors/extracttext.sieve b/pigeonhole/tests/extensions/mime/errors/extracttext.sieve
new file mode 100644
index 0000000..f8af1c9
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/errors/extracttext.sieve
@@ -0,0 +1,42 @@
+require "extracttext";
+require "variables";
+require "foreverypart";
+
+# 1: Used outside foreverypart
+extracttext :first 10 "data";
+
+foreverypart {
+ # 2: Missing arguments
+ extracttext;
+
+ # 3: Bad arguments
+ extracttext 1;
+
+ # 4: Bad arguments
+ extracttext ["frop", "friep"];
+
+ # 5: Unknown tag
+ extracttext :frop "frop";
+
+ # 6: Invalid variable name
+ extracttext "${frop}";
+
+ # Not an error
+ extracttext "\n\a\m\e";
+
+ # 7: Trying to assign match variable
+ extracttext "0";
+
+ # Not an error
+ extracttext :lower "frop";
+
+ # 8: Bad ":first" tag
+ extracttext :first "frop";
+
+ # 9: Bad ":first" tag
+ extracttext :first "frop" "friep";
+
+ # 10: Bad ":first" tag
+ extracttext :first ["frop", "friep"] "frml";
+}
+
diff --git a/pigeonhole/tests/extensions/mime/errors/foreverypart.sieve b/pigeonhole/tests/extensions/mime/errors/foreverypart.sieve
new file mode 100644
index 0000000..38a28d4
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/errors/foreverypart.sieve
@@ -0,0 +1,45 @@
+require "foreverypart";
+
+# 1: No block
+foreverypart;
+
+# 2: Spurious tag
+foreverypart :tag { }
+
+# 3: Spurious tests
+foreverypart true { }
+
+# 4: Spurious tests
+foreverypart anyof(true, false) { }
+
+# 5: Bare string
+foreverypart "frop" { }
+
+# 6: Bare string-list
+foreverypart ["frop", "friep"] { }
+
+# 7: Several bad arguments
+foreverypart 13 ["frop", "friep"] { }
+
+# 8: Spurious additional tag
+foreverypart :name "frop" :friep { }
+
+# 9: Spurious additional string
+foreverypart :name "frop" "friep" { }
+
+# 10: Bad name
+foreverypart :name 13 { }
+
+# 11: Bad name
+foreverypart :name ["frop", "friep"] { }
+
+# No error
+foreverypart { keep; }
+
+# No error
+foreverypart :name "frop" { keep; }
+
+# No error
+foreverypart :name "frop" { foreverypart { keep; } }
+
+
diff --git a/pigeonhole/tests/extensions/mime/errors/header-mime-tag.sieve b/pigeonhole/tests/extensions/mime/errors/header-mime-tag.sieve
new file mode 100644
index 0000000..85782af
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/errors/header-mime-tag.sieve
@@ -0,0 +1,100 @@
+require "mime";
+
+## Header
+
+# No error
+if header :contains :mime "Content-Type" "text/plain" {
+ discard;
+}
+
+# No error
+if header :mime :type "Content-Type" "text" {
+ discard;
+}
+
+# No error
+if header :mime :subtype "Content-Type" "plain" {
+ discard;
+}
+
+# No error
+if header :mime :contenttype "Content-Type" "text/plain" {
+ discard;
+}
+
+# No error
+if header :mime :param ["frop", "friep"] "Content-Type" "frml" {
+ discard;
+}
+
+# No error
+if header :anychild :contains :mime "Content-Type" "text/plain" {
+ discard;
+}
+
+# No error
+if header :mime :anychild :type "Content-Type" "text" {
+ discard;
+}
+
+# No error
+if header :mime :subtype :anychild "Content-Type" "plain" {
+ discard;
+}
+
+# No error
+if header :anychild :mime :contenttype "Content-Type" "text/plain" {
+ discard;
+}
+
+# No error
+if header :mime :param ["frop", "friep"] :anychild "Content-Type" "frml" {
+ discard;
+}
+
+# 1: Bare anychild option
+if header :anychild "Content-Type" "frml" {
+ discard;
+}
+
+# 2: Bare mime option
+if header :type "Content-Type" "frml" {
+ discard;
+}
+
+# 3: Bare mime option
+if header :subtype "Content-Type" "frml" {
+ discard;
+}
+
+# 4: Bare mime option
+if header :contenttype "Content-Type" "frml" {
+ discard;
+}
+
+# 5: Bare mime option
+if header :param "frop" "Content-Type" "frml" {
+ discard;
+}
+
+# 6: Multiple option tags
+if header :mime :type :subtype "Content-Type" "frml" {
+ discard;
+}
+
+# 7: Bad param argument
+if header :mime :param 13 "Content-Type" "frml" {
+ discard;
+}
+
+# 8: Missing param argument
+if header :mime :param :anychild "Content-Type" "frml" {
+ discard;
+}
+
+# 9: Missing param argument
+if header :mime :param :frop "Content-Type" "frml" {
+ discard;
+}
+
+
diff --git a/pigeonhole/tests/extensions/mime/errors/limits-include.sieve b/pigeonhole/tests/extensions/mime/errors/limits-include.sieve
new file mode 100644
index 0000000..ef92456
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/errors/limits-include.sieve
@@ -0,0 +1,6 @@
+require "foreverypart";
+require "include";
+
+foreverypart :name "frop" {
+ include "include-loop-2";
+}
diff --git a/pigeonhole/tests/extensions/mime/errors/limits.sieve b/pigeonhole/tests/extensions/mime/errors/limits.sieve
new file mode 100644
index 0000000..0add1c3
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/errors/limits.sieve
@@ -0,0 +1,13 @@
+require "foreverypart";
+
+foreverypart :name "frop" {
+ foreverypart :name "friep" {
+ foreverypart :name "frml" {
+ foreverypart {
+ foreverypart {
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/pigeonhole/tests/extensions/mime/execute.svtest b/pigeonhole/tests/extensions/mime/execute.svtest
new file mode 100644
index 0000000..2ced83b
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/execute.svtest
@@ -0,0 +1,82 @@
+require "vnd.dovecot.testsuite";
+
+/*
+ * Execution testing (currently just meant to trigger any segfaults)
+ */
+
+test_set "message" text:
+From: Whomever <whoever@example.com>
+To: Someone <someone@example.com>
+Date: Sat, 10 Oct 2009 00:30:04 +0200
+Subject: whatever
+Content-Type: multipart/mixed; boundary=outer
+
+This is a multi-part message in MIME format.
+
+--outer
+Content-Type: multipart/alternative; boundary=inner
+
+This is a nested multi-part message in MIME format.
+
+--inner
+Content-Type: text/plain; charset="us-ascii"
+
+Hello
+
+--inner
+Content-Type: text/html; charset="us-ascii"
+
+<html><body>Hello</body></html>
+
+--inner--
+
+This is the end of the inner MIME multipart.
+
+--outer
+Content-Type: message/rfc822
+
+From: Someone Else
+Subject: Hello, this is an elaborate request for you to finally say hello
+ already!
+
+Please say Hello
+
+--outer--
+
+This is the end of the outer MIME multipart.
+.
+;
+
+test "Basic - foreverypart" {
+ if not test_script_compile "execute/foreverypart.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script run failed";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+
+ test_binary_save "ihave-basic";
+ test_binary_load "ihave-basic";
+}
+
+test "Basic - mime" {
+ if not test_script_compile "execute/mime.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script run failed";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+
+ test_binary_save "ihave-basic";
+ test_binary_load "ihave-basic";
+}
diff --git a/pigeonhole/tests/extensions/mime/execute/foreverypart.sieve b/pigeonhole/tests/extensions/mime/execute/foreverypart.sieve
new file mode 100644
index 0000000..9ae1fba
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/execute/foreverypart.sieve
@@ -0,0 +1,14 @@
+require "foreverypart";
+require "variables";
+
+foreverypart {
+ foreverypart {
+ foreverypart {
+ foreverypart {
+ set "a" "a${a}";
+ }
+ }
+ }
+}
+
+
diff --git a/pigeonhole/tests/extensions/mime/execute/mime.sieve b/pigeonhole/tests/extensions/mime/execute/mime.sieve
new file mode 100644
index 0000000..dd7fedc
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/execute/mime.sieve
@@ -0,0 +1,69 @@
+require "mime";
+require "foreverypart";
+require "variables";
+
+if header :contains :mime "Content-Type" "text/plain" {
+ discard;
+}
+if header :mime :type "Content-Type" "text" {
+ discard;
+}
+if header :mime :subtype "Content-Type" "plain" {
+ discard;
+}
+if header :mime :contenttype "Content-Type" "text/plain" {
+ discard;
+}
+if header :mime :param ["frop", "friep"] "Content-Type" "frml" {
+ discard;
+}
+if header :anychild :contains :mime "Content-Type" "text/plain" {
+ discard;
+}
+if header :mime :anychild :type "Content-Type" "text" {
+ discard;
+}
+if header :mime :subtype :anychild "Content-Type" "plain" {
+ discard;
+}
+if header :anychild :mime :contenttype "Content-Type" "text/plain" {
+ discard;
+}
+if header :mime :param ["frop", "friep"] :anychild "Content-Type" "frml" {
+ discard;
+}
+
+foreverypart {
+ foreverypart {
+ if header :contains :mime "Content-Type" "text/plain" {
+ discard;
+ }
+ if header :mime :type "Content-Type" "text" {
+ discard;
+ }
+ if header :mime :subtype "Content-Type" "plain" {
+ discard;
+ }
+ if header :mime :contenttype "Content-Type" "text/plain" {
+ discard;
+ }
+ if header :mime :param ["frop", "friep"] "Content-Type" "frml" {
+ discard;
+ }
+ if header :anychild :contains :mime "Content-Type" "text/plain" {
+ discard;
+ }
+ if header :mime :anychild :type "Content-Type" "text" {
+ discard;
+ }
+ if header :mime :subtype :anychild "Content-Type" "plain" {
+ discard;
+ }
+ if header :anychild :mime :contenttype "Content-Type" "text/plain" {
+ discard;
+ }
+ if header :mime :param ["frop", "friep"] :anychild "Content-Type" "frml" {
+ discard;
+ }
+ }
+}
diff --git a/pigeonhole/tests/extensions/mime/exists.svtest b/pigeonhole/tests/extensions/mime/exists.svtest
new file mode 100644
index 0000000..517deeb
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/exists.svtest
@@ -0,0 +1,237 @@
+require "vnd.dovecot.testsuite";
+require "mime";
+require "foreverypart";
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@vestingbar.bl
+Subject: Test message
+Date: Wed, 29 Jul 2009 18:21:44 +0300
+X-Spam-Status: Not Spam
+Resent-To: nico@frop.example.com
+
+Test!
+.
+;
+
+/*
+ * One header
+ */
+
+test "One header" {
+ if not exists :mime :anychild "from" {
+ test_fail "exists test missed from header";
+ }
+
+ if exists :mime :anychild "x-nonsense" {
+ test_fail "exists test found non-existent header";
+ }
+}
+
+/*
+ * One header - foreverypart
+ */
+
+test "One header - foreverypart" {
+ foreverypart {
+ if not exists :mime :anychild "from" {
+ test_fail "exists test missed from header";
+ }
+
+ if exists :mime :anychild "x-nonsense" {
+ test_fail "exists test found non-existent header";
+ }
+ }
+}
+
+/*
+ * Two headers
+ */
+
+test "Two headers" {
+ if not exists :mime :anychild ["from","to"] {
+ test_fail "exists test missed from or to header";
+ }
+
+ if exists :mime :anychild ["from","x-nonsense"] {
+ test_fail "exists test found non-existent header (1)";
+ }
+
+ if exists :mime :anychild ["x-nonsense","to"] {
+ test_fail "exists test found non-existent header (2)";
+ }
+
+ if exists :mime :anychild ["x-nonsense","x-nonsense2"] {
+ test_fail "exists test found non-existent header (3)";
+ }
+}
+
+/*
+ * Two headers - foreverypart
+ */
+
+test "Two headers - foreverypart" {
+ foreverypart {
+ if not exists :mime :anychild ["from","to"] {
+ test_fail "exists test missed from or to header";
+ }
+
+ if exists :mime :anychild ["from","x-nonsense"] {
+ test_fail "exists test found non-existent header (1)";
+ }
+
+ if exists :mime :anychild ["x-nonsense","to"] {
+ test_fail "exists test found non-existent header (2)";
+ }
+
+ if exists :mime :anychild ["x-nonsense","x-nonsense2"] {
+ test_fail "exists test found non-existent header (3)";
+ }
+ }
+}
+
+/*
+ * Three headers
+ */
+
+test "Three headers" {
+ if not exists :mime :anychild ["Subject","date","resent-to"] {
+ test_fail "exists test missed subject, date or resent-to header";
+ }
+
+ if exists :mime :anychild ["x-nonsense","date","resent-to"] {
+ test_fail "exists test found non-existent header (1)";
+ }
+
+ if exists :mime :anychild ["subject", "x-nonsense","resent-to"] {
+ test_fail "exists test found non-existent header (2)";
+ }
+
+ if exists :mime :anychild ["subject","date","x-nonsense"] {
+ test_fail "exists test found non-existent header (3)";
+ }
+
+ if exists :mime :anychild ["subject", "x-nonsense","x-nonsense2"] {
+ test_fail "exists test found non-existent header (4)";
+ }
+
+ if exists :mime :anychild ["x-nonsense","date","x-nonsense2"] {
+ test_fail "exists test found non-existent header (5)";
+ }
+
+ if exists :mime :anychild ["x-nonsense","x-nonsense2","resent-to"] {
+ test_fail "exists test found non-existent header (6)";
+ }
+
+ if exists :mime :anychild ["x-nonsense","x-nonsense2","x-nonsense3"] {
+ test_fail "exists test found non-existent header (7)";
+ }
+}
+
+/*
+ * Three headers - foreverypart
+ */
+
+test "Three headers - foreverypart " {
+ foreverypart {
+ if not exists :mime :anychild ["Subject","date","resent-to"] {
+ test_fail "exists test missed subject, date or resent-to header";
+ }
+
+ if exists :mime :anychild ["x-nonsense","date","resent-to"] {
+ test_fail "exists test found non-existent header (1)";
+ }
+
+ if exists :mime :anychild ["subject", "x-nonsense","resent-to"] {
+ test_fail "exists test found non-existent header (2)";
+ }
+
+ if exists :mime :anychild ["subject","date","x-nonsense"] {
+ test_fail "exists test found non-existent header (3)";
+ }
+
+ if exists :mime :anychild ["subject", "x-nonsense","x-nonsense2"] {
+ test_fail "exists test found non-existent header (4)";
+ }
+
+ if exists :mime :anychild ["x-nonsense","date","x-nonsense2"] {
+ test_fail "exists test found non-existent header (5)";
+ }
+
+ if exists :mime :anychild ["x-nonsense","x-nonsense2","resent-to"] {
+ test_fail "exists test found non-existent header (6)";
+ }
+
+ if exists :mime :anychild ["x-nonsense","x-nonsense2","x-nonsense3"] {
+ test_fail "exists test found non-existent header (7)";
+ }
+ }
+}
+
+/*
+ * Multipart anychild
+ */
+
+test_set "message" text:
+From: Hendrik <hendrik@example.com>
+To: Harrie <harrie@example.com>
+Date: Sat, 11 Oct 2010 00:31:44 +0200
+Subject: Harrie is een prutser
+Content-Type: multipart/mixed; boundary=AA
+X-Test1: AA
+
+This is a multi-part message in MIME format.
+--AA
+Content-Type: multipart/mixed; boundary=BB
+X-Test2: BB
+
+This is a multi-part message in MIME format.
+--BB
+Content-Type: text/plain; charset="us-ascii"
+X-Test3: CC
+
+Hello
+
+--BB
+Content-Type: text/plain; charset="us-ascii"
+X-Test4: DD
+
+Hello again
+
+--BB--
+This is the end of MIME multipart.
+
+--AA
+Content-Type: text/plain; charset="us-ascii"
+X-Test5: EE
+
+And again
+
+--AA--
+This is the end of MIME multipart.
+.
+;
+
+test "Multipart anychild" {
+ if not exists :mime :anychild "X-Test1" {
+ test_fail "X-Test1 header does exist";
+ }
+ if not exists :mime :anychild "X-Test2" {
+ test_fail "X-Test2 header does exist";
+ }
+ if not exists :mime :anychild "X-Test3" {
+ test_fail "X-Test3 header does exist";
+ }
+ if not exists :mime :anychild "X-Test4" {
+ test_fail "X-Test4 header does exist";
+ }
+ if not exists :mime :anychild "X-Test5" {
+ test_fail "X-Test5 header does exist";
+ }
+ if not exists :mime :anychild
+ ["X-Test1", "X-Test2", "X-Test3", "X-Test4", "X-Test5"] {
+ test_fail "Not all headers exist";
+ }
+}
+
+
diff --git a/pigeonhole/tests/extensions/mime/extracttext.svtest b/pigeonhole/tests/extensions/mime/extracttext.svtest
new file mode 100644
index 0000000..510a52b
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/extracttext.svtest
@@ -0,0 +1,143 @@
+require "vnd.dovecot.testsuite";
+require "foreverypart";
+require "variables";
+require "extracttext";
+
+test_set "message" text:
+From: Hendrik <hendrik@example.com>
+To: Harrie <harrie@example.com>
+Date: Sat, 11 Oct 2010 00:31:44 +0200
+Subject: Harrie is een prutser
+Content-Type: multipart/mixed; boundary=AA
+
+This is a multi-part message in MIME format.
+--AA
+Content-Type: multipart/mixed; boundary=BB
+
+This is a multi-part message in MIME format.
+--BB
+Content-Type: text/plain; charset="us-ascii"
+
+This is the first message part containing
+plain text.
+
+--BB
+Content-Type: text/plain; charset="us-ascii"
+
+This is another plain text message part.
+
+--BB--
+This is the end of MIME multipart.
+
+--AA
+Content-Type: text/html; charset="us-ascii"
+
+<html>
+<body>This is a piece of HTML text.</body>
+</html>
+
+--AA--
+This is the end of MIME multipart.
+.
+;
+
+test "Basic" {
+ set "a" "a";
+ foreverypart {
+ extracttext "b";
+ if string "${a}" "aaa" {
+ if not string :contains "${b}" "first" {
+ test_fail "bad content extracted: ${b}";
+ }
+ } elsif string "${a}" "aaaa" {
+ if not string :contains "${b}" "another" {
+ test_fail "bad content extracted: ${b}";
+ }
+ } elsif string "${a}" "aaaaa" {
+ if not string :contains "${b}" "HTML text" {
+ test_fail "bad content extracted: ${b}";
+ }
+ if string :contains "${b}" "<html>" {
+ test_fail "content extracted html: ${b}";
+ }
+ }
+ set "a" "a${a}";
+ }
+ if not string "${a}" "aaaaaa" {
+ set :length "parts" "${a}";
+ test_fail "bad number of parts parsed: ${parts}";
+ }
+}
+
+test_set "message" text:
+From: <stephan@example.com>
+To: <frop@example.com>
+Subject: Frop!
+
+FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP!
+FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP!
+FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP!
+FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP!
+FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP!
+FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP!
+FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP!
+FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP!
+FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP!
+FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP!
+FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP!
+FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP! FROP!
+.
+;
+
+test "First - less" {
+ foreverypart {
+ extracttext :first 20 "data";
+ if not string "${data}" "FROP! FROP! FROP! FR" {
+ test_fail "Bad data extracted";
+ }
+
+ extracttext :length :first 100 "data_len";
+ if not string "${data_len}" "100" {
+ test_fail "Bad number of bytes extracted";
+ }
+ }
+}
+
+test_set "message" text:
+From: <stephan@example.com>
+To: <frop@example.com>
+Subject: Frop!
+
+FROP! FROP! FROP! FROP!
+.
+;
+
+test "First - more" {
+ foreverypart {
+ extracttext :first 100 "data";
+ if not string :matches "${data}" "FROP! FROP! FROP! FROP!*" {
+ test_fail "Bad data extracted";
+ }
+ }
+}
+
+test_set "message" text:
+From: <stephan@example.com>
+To: <frop@example.com>
+Subject: Frop!
+
+FROP! FROP! FROP! FROP!
+.
+;
+
+test "Modifier" {
+ foreverypart {
+ extracttext :lower :upperfirst "data";
+ if not string :matches "${data}" "Frop! frop! frop! frop!*" {
+ test_fail "Bad data extracted";
+ }
+ }
+}
+
+
+
diff --git a/pigeonhole/tests/extensions/mime/foreverypart.svtest b/pigeonhole/tests/extensions/mime/foreverypart.svtest
new file mode 100644
index 0000000..08907c9
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/foreverypart.svtest
@@ -0,0 +1,178 @@
+require "vnd.dovecot.testsuite";
+require "relational";
+require "foreverypart";
+require "mime";
+require "variables";
+require "include";
+
+test_set "message" text:
+From: Hendrik <hendrik@example.com>
+To: Harrie <harrie@example.com>
+Date: Sat, 11 Oct 2010 00:31:44 +0200
+Subject: Harrie is een prutser
+Content-Type: multipart/mixed; boundary=AA
+X-Test: AA
+
+This is a multi-part message in MIME format.
+--AA
+Content-Type: multipart/mixed; boundary=BB
+X-Test: BB
+
+This is a multi-part message in MIME format.
+--BB
+Content-Type: text/plain; charset="us-ascii"
+X-Test: CC
+
+Hello
+
+--BB
+Content-Type: text/plain; charset="us-ascii"
+X-Test: DD
+
+Hello again
+
+--BB--
+This is the end of MIME multipart.
+
+--AA
+Content-Type: text/plain; charset="us-ascii"
+X-Test: EE
+
+And again
+
+--AA--
+This is the end of MIME multipart.
+.
+;
+
+test "Single loop" {
+ set "a" "a";
+ foreverypart {
+ set :length "la" "${a}";
+
+ if string "${a}" "a" {
+ if not header :mime "X-Test" "AA" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${a}" "aa" {
+ if not header :mime "X-Test" "BB" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${a}" "aaa" {
+ if not header :mime "X-Test" "CC" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${a}" "aaaa" {
+ if not header :mime "X-Test" "DD" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${a}" "aaaaa" {
+ if not header :mime "X-Test" "EE" {
+ test_fail "wrong header extracted (${la})";
+ }
+ }
+ set "a" "a${a}";
+ }
+}
+
+test "Double loop" {
+ set "a" "a";
+ foreverypart {
+ set :length "la" "${a}";
+
+ if string "${a}" "a" {
+ if not header :mime "X-Test" "AA" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${a}" "aaaaaa" {
+ if not header :mime "X-Test" "BB" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${a}" "aaaaaaaaa" {
+ if not header :mime "X-Test" "CC" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${a}" "aaaaaaaaaa" {
+ if not header :mime "X-Test" "DD" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${a}" "aaaaaaaaaaa" {
+ if not header :mime "X-Test" "EE" {
+ test_fail "wrong header extracted (${la})";
+ }
+ }
+
+ set "a" "a${a}";
+
+ foreverypart {
+ set :length "la" "${a}";
+
+ if string "${a}" "aa" {
+ if not header :mime "X-Test" "BB" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${a}" "aaa" {
+ if not header :mime "X-Test" "CC" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${a}" "aaaa" {
+ if not header :mime "X-Test" "DD" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${a}" "aaaaa" {
+ if not header :mime "X-Test" "EE" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${a}" "aaaaaaa" {
+ if not header :mime "X-Test" "CC" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${a}" "aaaaaaaa" {
+ if not header :mime "X-Test" "DD" {
+ test_fail "wrong header extracted (${la})";
+ }
+ }
+ set "a" "a${a}";
+ }
+ }
+}
+
+test "Double loop - include" {
+ global "in";
+ global "error";
+ set "in" "a";
+ foreverypart {
+ set :length "la" "${in}";
+
+ if string "${in}" "in" {
+ if not header :mime "X-Test" "AA" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${in}" "aaaaaa" {
+ if not header :mime "X-Test" "BB" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${in}" "aaaaaaaaa" {
+ if not header :mime "X-Test" "CC" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${in}" "aaaaaaaaaa" {
+ if not header :mime "X-Test" "DD" {
+ test_fail "wrong header extracted (${la})";
+ }
+ } elsif string "${in}" "aaaaaaaaaaa" {
+ if not header :mime "X-Test" "EE" {
+ test_fail "wrong header extracted (${la})";
+ }
+ }
+
+ set "in" "a${in}";
+
+ include "include-foreverypart";
+
+ if not string "${error}" "" {
+ test_fail "INCLUDED: ${error}";
+ }
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/mime/header.svtest b/pigeonhole/tests/extensions/mime/header.svtest
new file mode 100644
index 0000000..48cd9e4
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/header.svtest
@@ -0,0 +1,444 @@
+require "vnd.dovecot.testsuite";
+require "variables";
+require "foreverypart";
+require "mime";
+
+/*
+ * Basic functionality
+ */
+
+test_set "message" text:
+From: stephan@example.com
+To: nico@nl.example.com, harry@de.example.com
+Subject: Frobnitzm
+Comments: This is nonsense.
+Keywords: nonsense, strange, testing
+X-Spam: Yes
+
+Test.
+.
+;
+
+test "Basic functionality" {
+ /* Must match */
+ if not header :mime :anychild :contains ["Subject", "Comments"] "Frobnitzm" {
+ test_fail "failed to match header (1)";
+ }
+
+ if not header :mime :anychild :contains ["Subject", "Comments"] "nonsense" {
+ test_fail "failed to match header(2)";
+ }
+
+ if not header :mime :anychild :matches "Keywords" "*, strange, *" {
+ test_fail "failed to match header (3)";
+ }
+
+ if not header :mime :anychild :is "Comments" "This is nonsense." {
+ test_fail "failed to match header (4)";
+ }
+
+ /* Must not match */
+ if header :mime :anychild ["subject", "comments", "keywords"] "idiotic" {
+ test_fail "matched nonsense";
+ }
+
+ /* Match first key */
+ if not header :mime :anychild :contains ["keywords"] ["strange", "snot", "vreemd"] {
+ test_fail "failed to match first key";
+ }
+
+ /* Match second key */
+ if not header :mime :anychild :contains ["keywords"] ["raar", "strange", "vreemd"] {
+ test_fail "failed to match second key";
+ }
+
+ /* Match last key */
+ if not header :mime :anychild :contains ["keywords"] ["raar", "snot", "strange"] {
+ test_fail "failed to match last key";
+ }
+
+ /* First header */
+ if not header :mime :anychild :contains ["keywords", "subject"]
+ ["raar", "strange", "vreemd"] {
+ test_fail "failed to match first header";
+ }
+
+ /* Second header */
+ if not header :mime :anychild :contains ["subject", "keywords"]
+ ["raar", "strange", "vreemd"] {
+ test_fail "failed to match second header";
+ }
+}
+
+/*
+ * Basic functionality - foreverypart
+ */
+
+test "Basic functionality - foreverypart" {
+ foreverypart {
+ /* Must match */
+ if not header :mime :anychild :contains ["Subject", "Comments"] "Frobnitzm" {
+ test_fail "failed to match header (1)";
+ }
+
+ if not header :mime :anychild :contains ["Subject", "Comments"] "nonsense" {
+ test_fail "failed to match header(2)";
+ }
+
+ if not header :mime :anychild :matches "Keywords" "*, strange, *" {
+ test_fail "failed to match header (3)";
+ }
+
+ if not header :mime :anychild :is "Comments" "This is nonsense." {
+ test_fail "failed to match header (4)";
+ }
+
+ /* Must not match */
+ if header :mime :anychild ["subject", "comments", "keywords"] "idiotic" {
+ test_fail "matched nonsense";
+ }
+
+ /* Match first key */
+ if not header :mime :anychild :contains ["keywords"] ["strange", "snot", "vreemd"] {
+ test_fail "failed to match first key";
+ }
+
+ /* Match second key */
+ if not header :mime :anychild :contains ["keywords"] ["raar", "strange", "vreemd"] {
+ test_fail "failed to match second key";
+ }
+
+ /* Match last key */
+ if not header :mime :anychild :contains ["keywords"] ["raar", "snot", "strange"] {
+ test_fail "failed to match last key";
+ }
+
+ /* First header */
+ if not header :mime :anychild :contains ["keywords", "subject"]
+ ["raar", "strange", "vreemd"] {
+ test_fail "failed to match first header";
+ }
+
+ /* Second header */
+ if not header :mime :anychild :contains ["subject", "keywords"]
+ ["raar", "strange", "vreemd"] {
+ test_fail "failed to match second header";
+ }
+ }
+}
+
+/*
+ * Matching empty key
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.com
+X-Caffeine: C8H10N4O2
+Subject: I need coffee!
+Comments:
+
+Text
+.
+;
+
+test "Matching empty key" {
+ if header :mime :anychild :is "X-Caffeine" "" {
+ test_fail ":is-matched non-empty header with empty string";
+ }
+
+ if not header :mime :anychild :contains "X-Caffeine" "" {
+ test_fail "failed to match existing header with empty string";
+ }
+
+ if not header :mime :anychild :is "comments" "" {
+ test_fail "failed to match empty header :mime :anychild with empty string";
+ }
+
+ if header :mime :anychild :contains "X-Nonsense" "" {
+ test_fail ":contains-matched non-existent header with empty string";
+ }
+}
+
+/*
+ * Matching empty key - foreverypart
+ */
+
+test "Matching empty key - foreverypart" {
+ foreverypart {
+ if header :mime :anychild :is "X-Caffeine" "" {
+ test_fail ":is-matched non-empty header with empty string";
+ }
+
+ if not header :mime :anychild :contains "X-Caffeine" "" {
+ test_fail "failed to match existing header with empty string";
+ }
+
+ if not header :mime :anychild :is "comments" "" {
+ test_fail "failed to match empty header :mime :anychild with empty string";
+ }
+
+ if header :mime :anychild :contains "X-Nonsense" "" {
+ test_fail ":contains-matched non-existent header with empty string";
+ }
+ }
+}
+
+/*
+ * Ignoring whitespace
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.com
+Subject: Help
+X-A: Text
+X-B: Text
+
+Text
+.
+;
+
+test "Ignoring whitespace" {
+ if not header :mime :anychild :is "x-a" "Text" {
+ if header :mime :anychild :matches "x-a" "*" {
+ set "header" "${1}";
+ }
+ test_fail "header :mime :anychild test does not strip leading whitespace (header=`${header}`)";
+ }
+
+ if not header :mime :anychild :is "x-b" "Text" {
+ if header :mime :anychild :matches "x-b" "*" {
+ set "header" "${1}";
+ }
+ test_fail "header :mime :anychild test does not strip trailing whitespace (header=`${header}`)";
+ }
+
+ if not header :mime :anychild :is "subject" "Help" {
+ if header :mime :anychild :matches "subject" "*" {
+ set "header" "${1}";
+ }
+ test_fail "header :mime :anychild test does not strip both leading and trailing whitespace (header=`${header}`)";
+ }
+}
+
+/*
+ * Ignoring whitespace - foreverypart
+ */
+
+test "Ignoring whitespace - foreverypart" {
+ foreverypart {
+ if not header :mime :anychild :is "x-a" "Text" {
+ if header :mime :anychild :matches "x-a" "*" {
+ set "header" "${1}";
+ }
+ test_fail "header :mime :anychild test does not strip leading whitespace (header=`${header}`)";
+ }
+
+ if not header :mime :anychild :is "x-b" "Text" {
+ if header :mime :anychild :matches "x-b" "*" {
+ set "header" "${1}";
+ }
+ test_fail "header :mime :anychild test does not strip trailing whitespace (header=`${header}`)";
+ }
+
+ if not header :mime :anychild :is "subject" "Help" {
+ if header :mime :anychild :matches "subject" "*" {
+ set "header" "${1}";
+ }
+ test_fail "header :mime :anychild test does not strip both leading and trailing whitespace (header=`${header}`)";
+ }
+ }
+}
+
+/*
+ * Absent or empty header
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.com
+CC: harry@nonsense.ex
+Subject:
+Comments:
+
+Text
+.
+;
+
+test "Absent or empty header" {
+ if not header :mime :anychild :matches "Cc" "?*" {
+ test_fail "CC header is not absent or empty";
+ }
+
+ if header :mime :anychild :matches "Subject" "?*" {
+ test_fail "Subject header is empty, but matched otherwise";
+ }
+
+ if header :mime :anychild :matches "Comment" "?*" {
+ test_fail "Comment header is empty, but matched otherwise";
+ }
+}
+
+/*
+ * Absent or empty header - foreverypart
+ */
+
+test "Absent or empty header - foreverypart" {
+ foreverypart {
+ if not header :mime :anychild :matches "Cc" "?*" {
+ test_fail "CC header is not absent or empty";
+ }
+
+ if header :mime :anychild :matches "Subject" "?*" {
+ test_fail "Subject header is empty, but matched otherwise";
+ }
+
+ if header :mime :anychild :matches "Comment" "?*" {
+ test_fail "Comment header is empty, but matched otherwise";
+ }
+ }
+}
+
+
+/*
+ * Invalid header name
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.com
+Subject: Valid message
+X-Multiline: This is a multi-line
+ header body, which should be
+ unfolded correctly.
+
+Text
+.
+;
+
+test "Invalid header name" {
+ if header :mime :anychild :contains "subject:" "" {
+ test_fail "matched invalid header name";
+ }
+
+ if header :mime :anychild :contains "to!" "" {
+ test_fail "matched invalid header name";
+ }
+}
+
+/*
+ * Invalid header name - foreverypart
+ */
+
+test "Invalid header name - foreverypart" {
+ foreverypart {
+ if header :mime :anychild :contains "subject:" "" {
+ test_fail "matched invalid header name";
+ }
+
+ if header :mime :anychild :contains "to!" "" {
+ test_fail "matched invalid header name";
+ }
+ }
+}
+
+/*
+ * Folded headers
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.com
+Subject: Not enough space on a line!
+X-Multiline: This is a multi-line
+ header body, which should be
+ unfolded correctly.
+
+Text
+.
+;
+
+test "Folded headers" {
+ if not header :mime :anychild :is "x-multiline"
+ "This is a multi-line header body, which should be unfolded correctly." {
+ test_fail "failed to properly unfold folded header.";
+ }
+}
+
+/*
+ * Folded headers - foreverypart
+ */
+
+test "Folded headers - foreverypart" {
+ foreverypart {
+ if not header :mime :anychild :is "x-multiline"
+ "This is a multi-line header body, which should be unfolded correctly." {
+ test_fail "failed to properly unfold folded header.";
+ }
+ }
+}
+
+/*
+ * Multipart anychild
+ */
+
+test_set "message" text:
+From: Hendrik <hendrik@example.com>
+To: Harrie <harrie@example.com>
+Date: Sat, 11 Oct 2010 00:31:44 +0200
+Subject: Harrie is een prutser
+Content-Type: multipart/mixed; boundary=AA
+X-Test: AA
+
+This is a multi-part message in MIME format.
+--AA
+Content-Type: multipart/mixed; boundary=BB
+X-Test: BB
+
+This is a multi-part message in MIME format.
+--BB
+Content-Type: text/plain; charset="us-ascii"
+X-Test: CC
+
+Hello
+
+--BB
+Content-Type: text/plain; charset="us-ascii"
+X-Test: DD
+
+Hello again
+
+--BB--
+This is the end of MIME multipart.
+
+--AA
+Content-Type: text/plain; charset="us-ascii"
+X-Test: EE
+
+And again
+
+--AA--
+This is the end of MIME multipart.
+.
+;
+
+test "Multipart anychild" {
+ if not header :mime :anychild "X-Test" "AA" {
+ test_fail "No AA";
+ }
+ if not header :mime :anychild "X-Test" "BB" {
+ test_fail "No BB";
+ }
+ if not header :mime :anychild "X-Test" "CC" {
+ test_fail "No CC";
+ }
+ if not header :mime :anychild "X-Test" "DD" {
+ test_fail "No DD";
+ }
+ if not header :mime :anychild "X-Test" "EE" {
+ test_fail "No EE";
+ }
+}
+
+
diff --git a/pigeonhole/tests/extensions/mime/included/include-foreverypart.sieve b/pigeonhole/tests/extensions/mime/included/include-foreverypart.sieve
new file mode 100644
index 0000000..f1b1b16
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/included/include-foreverypart.sieve
@@ -0,0 +1,44 @@
+require "include";
+require "foreverypart";
+require "mime";
+require "variables";
+
+global "in";
+global "error";
+
+foreverypart {
+ set :length "la" "${in}";
+
+ if string "${in}" "aa" {
+ if not header :mime "X-Test" "BB" {
+ set "error" "wrong header extracted (${la})";
+ return;
+ }
+ } elsif string "${in}" "aaa" {
+ if not header :mime "X-Test" "CC" {
+ set "error" "wrong header extracted (${la})";
+ return;
+ }
+ } elsif string "${in}" "aaaa" {
+ if not header :mime "X-Test" "DD" {
+ set "error" "wrong header extracted (${la})";
+ return;
+ }
+ } elsif string "${in}" "aaaaa" {
+ if not header :mime "X-Test" "EE" {
+ set "error" "wrong header extracted (${la})";
+ return;
+ }
+ } elsif string "${in}" "aaaaaaa" {
+ if not header :mime "X-Test" "CC" {
+ set "error" "wrong header extracted (${la})";
+ return;
+ }
+ } elsif string "${in}" "aaaaaaaa" {
+ if not header :mime "X-Test" "DD" {
+ set "error" "wrong header extracted (${la})";
+ return;
+ }
+ }
+ set "in" "a${in}";
+}
diff --git a/pigeonhole/tests/extensions/mime/included/include-loop-2.sieve b/pigeonhole/tests/extensions/mime/included/include-loop-2.sieve
new file mode 100644
index 0000000..80c5884
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/included/include-loop-2.sieve
@@ -0,0 +1,6 @@
+require "foreverypart";
+require "include";
+
+foreverypart :name "friep" {
+ include "include-loop-3";
+}
diff --git a/pigeonhole/tests/extensions/mime/included/include-loop-3.sieve b/pigeonhole/tests/extensions/mime/included/include-loop-3.sieve
new file mode 100644
index 0000000..228a8bc
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/included/include-loop-3.sieve
@@ -0,0 +1,6 @@
+require "foreverypart";
+require "include";
+
+foreverypart :name "frml" {
+ include "include-loop-4";
+}
diff --git a/pigeonhole/tests/extensions/mime/included/include-loop-4.sieve b/pigeonhole/tests/extensions/mime/included/include-loop-4.sieve
new file mode 100644
index 0000000..00dad84
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/included/include-loop-4.sieve
@@ -0,0 +1,6 @@
+require "foreverypart";
+require "include";
+
+foreverypart {
+ include "include-loop-5";
+}
diff --git a/pigeonhole/tests/extensions/mime/included/include-loop-5.sieve b/pigeonhole/tests/extensions/mime/included/include-loop-5.sieve
new file mode 100644
index 0000000..e22b21c
--- /dev/null
+++ b/pigeonhole/tests/extensions/mime/included/include-loop-5.sieve
@@ -0,0 +1,9 @@
+require "foreverypart";
+require "include";
+require "mime";
+
+foreverypart {
+ if header :mime :subtype "content-type" "plain" {
+ break;
+ }
+}
diff --git a/pigeonhole/tests/extensions/regex/basic.svtest b/pigeonhole/tests/extensions/regex/basic.svtest
new file mode 100644
index 0000000..9417434
--- /dev/null
+++ b/pigeonhole/tests/extensions/regex/basic.svtest
@@ -0,0 +1,51 @@
+require "vnd.dovecot.testsuite";
+
+require "regex";
+require "variables";
+
+test_set "message" text:
+From: stephan+sieve@friep.example.com
+To: tss@example.net, nico@nl.example.com, sirius@fi.example.com
+Subject: Test
+
+Test message.
+.
+;
+
+test "Basic example" {
+ if not address :regex :comparator "i;ascii-casemap" "from" [
+ "stephan(\\+.*)?@it\\.example\\.com",
+ "stephan(\\+.*)?@friep\\.example\\.com"
+ ] {
+ test_fail "failed to match";
+ }
+}
+
+test "No values" {
+ if header :regex "cc" [".*\\.com", ".*\\.nl"] {
+ test_fail "matched inappropriately";
+ }
+}
+
+
+test "More values" {
+ if address :regex "to" [".*\\.uk", ".*\\.nl", ".*\\.tk"] {
+ test_fail "matched inappropriately";
+ }
+
+ if not address :regex "to" [".*\\.uk", ".*\\.nl", ".*\\.tk", ".*fi\\..*"] {
+ test_fail "failed to match last";
+ }
+}
+
+test "Variable regex" {
+ set "regex" "stephan[+](sieve)@friep.example.com";
+
+ if not header :regex "from" "${regex}" {
+ test_fail "failed to match variable regex";
+ }
+
+ if not string "${1}" "sieve" {
+ test_fail "failed to extract proper match value from variable regex";
+ }
+}
diff --git a/pigeonhole/tests/extensions/regex/errors.svtest b/pigeonhole/tests/extensions/regex/errors.svtest
new file mode 100644
index 0000000..2e0ebe0
--- /dev/null
+++ b/pigeonhole/tests/extensions/regex/errors.svtest
@@ -0,0 +1,29 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+test "Compile errors" {
+ if test_script_compile "errors/compile.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "5" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Runtime errors" {
+ if not test_script_compile "errors/runtime.sieve" {
+ test_fail "failed to compile";
+ }
+
+ if not test_script_run {
+ test_fail "script should have run fine";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "1" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/regex/errors/compile.sieve b/pigeonhole/tests/extensions/regex/errors/compile.sieve
new file mode 100644
index 0000000..5ddaaf8
--- /dev/null
+++ b/pigeonhole/tests/extensions/regex/errors/compile.sieve
@@ -0,0 +1,25 @@
+require "regex";
+require "comparator-i;ascii-numeric";
+require "envelope";
+
+if address :regex :comparator "i;ascii-numeric" "from" "sirius(\\+.*)?@friep\\.example\\.com" {
+ keep;
+ stop;
+}
+
+if address :regex "from" "sirius(+\\+.*)?@friep\\.example\\.com" {
+ keep;
+ stop;
+}
+
+if header :regex "from" "sirius(\\+.*)?@friep\\.ex[]ample.com" {
+ keep;
+ stop;
+}
+
+if envelope :regex "from" "sirius(\\+.*)?@friep\\.ex[]ample.com" {
+ keep;
+ stop;
+}
+
+discard;
diff --git a/pigeonhole/tests/extensions/regex/errors/runtime.sieve b/pigeonhole/tests/extensions/regex/errors/runtime.sieve
new file mode 100644
index 0000000..2d0bf66
--- /dev/null
+++ b/pigeonhole/tests/extensions/regex/errors/runtime.sieve
@@ -0,0 +1,9 @@
+require "regex";
+require "variables";
+require "fileinto";
+
+set "regex" "[";
+
+if header :regex "to" "${regex}" {
+ fileinto "frop";
+}
diff --git a/pigeonhole/tests/extensions/regex/match-values.svtest b/pigeonhole/tests/extensions/regex/match-values.svtest
new file mode 100644
index 0000000..18b7404
--- /dev/null
+++ b/pigeonhole/tests/extensions/regex/match-values.svtest
@@ -0,0 +1,72 @@
+require "vnd.dovecot.testsuite";
+
+require "regex";
+require "variables";
+
+test_set "message" text:
+From: Andy Howell <AndyHowell@example.com>
+Sender: antlr-interest-bounces@ant.example.com
+To: Stephan Bosch <stephan@example.org>
+Subject: [Dovecot] Sieve regex match problem
+
+Hi,
+
+I is broken.
+.
+;
+
+test "Basic match values 1" {
+ if header :regex ["Sender"] ["([^-@]*)-([^-@]*)(-bounces)?@ant.example.com"] {
+
+ if not string :is "${1}" "antlr" {
+ test_fail "first match value is not correct";
+ }
+
+ if not string :is "${2}" "interest" {
+ test_fail "second match value is not correct";
+ }
+
+ if not string :is "${3}" "-bounces" {
+ test_fail "third match value is not correct";
+ }
+
+ if string :is "${4}" "-bounces" {
+ test_fail "fourth match contains third value";
+ }
+ } else {
+ test_fail "failed to match";
+ }
+}
+
+test "Basic match values 2" {
+ if header :regex ["Sender"] ["(.*>[ \\t]*,?[ \\t]*)?([^-@]*)-([^-@]*)(-bounces)?@ant.example.com"] {
+
+ if not string :is "${1}" "" {
+ test_fail "first match value is not correct: ${1}";
+ }
+
+ if not string :is "${2}" "antlr" {
+ test_fail "second match value is not correct: ${2}";
+ }
+
+ if not string :is "${3}" "interest" {
+ test_fail "third match value is not correct: ${3}";
+ }
+
+ if not string :is "${4}" "-bounces" {
+ test_fail "fourth match value is not correct: ${4}";
+ }
+
+ if string :is "${5}" "-bounces" {
+ test_fail "fifth match contains fourth value: ${5}";
+ }
+ } else {
+ test_fail "failed to match";
+ }
+}
+
+
+
+
+
+
diff --git a/pigeonhole/tests/extensions/reject/execute.svtest b/pigeonhole/tests/extensions/reject/execute.svtest
new file mode 100644
index 0000000..20a0bdf
--- /dev/null
+++ b/pigeonhole/tests/extensions/reject/execute.svtest
@@ -0,0 +1,34 @@
+require "vnd.dovecot.testsuite";
+require "relational";
+require "comparator-i;ascii-numeric";
+
+test_set "message" text:
+To: nico@frop.example.org
+From: stephan@example.org
+Subject: Test
+
+Test.
+.
+;
+
+test "Execute" {
+ if not test_script_compile "execute/basic.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script run failed";
+ }
+
+ if not test_result_action :count "eq" :comparator "i;ascii-numeric" "1" {
+ test_fail "invalid number of actions in result";
+ }
+
+ if not test_result_action :index 1 "reject" {
+ test_fail "reject action missing from result";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+}
diff --git a/pigeonhole/tests/extensions/reject/execute/basic.sieve b/pigeonhole/tests/extensions/reject/execute/basic.sieve
new file mode 100644
index 0000000..d3b7dc9
--- /dev/null
+++ b/pigeonhole/tests/extensions/reject/execute/basic.sieve
@@ -0,0 +1,8 @@
+require "reject";
+
+if address :contains "to" "frop.example" {
+ reject "Don't send unrequested messages.";
+ stop;
+}
+
+keep;
diff --git a/pigeonhole/tests/extensions/reject/smtp.svtest b/pigeonhole/tests/extensions/reject/smtp.svtest
new file mode 100644
index 0000000..8cbf77c
--- /dev/null
+++ b/pigeonhole/tests/extensions/reject/smtp.svtest
@@ -0,0 +1,56 @@
+require "vnd.dovecot.testsuite";
+require "envelope";
+require "reject";
+
+test_set "message" text:
+From: stephan@example.org
+To: tss@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "timo@example.net";
+
+test "Basic" {
+ reject "I don't want your mail";
+
+ if not test_result_execute {
+ test_fail "failed to execute reject";
+ }
+
+ test_message :smtp 0;
+
+ if not address :is "to" "sirius@example.org" {
+ test_fail "to address incorrect";
+ }
+
+ if not header :contains "from" "Postmaster" {
+ test_fail "from address incorrect";
+ }
+
+ if not envelope :is "to" "sirius@example.org" {
+ test_fail "envelope recipient incorrect";
+ }
+
+ if not envelope :is "from" "" {
+ test_fail "envelope sender not null";
+ }
+}
+
+test_result_reset;
+test_set "envelope.from" "<>";
+
+test "Null Sender" {
+ reject "I don't want your mail";
+
+ if not test_result_execute {
+ test_fail "failed to execute reject";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "reject sent message to NULL sender";
+ }
+}
diff --git a/pigeonhole/tests/extensions/relational/basic.svtest b/pigeonhole/tests/extensions/relational/basic.svtest
new file mode 100644
index 0000000..288661a
--- /dev/null
+++ b/pigeonhole/tests/extensions/relational/basic.svtest
@@ -0,0 +1,178 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Test message
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Cc: frop@example.org
+CC: timo@example.org
+X-Spam-Score: 300
+X-Nonsense: 1000
+X-Nonsense: 20
+X-Alpha: abcdzyx
+X-Count: a
+X-Count: b
+X-Count: c
+X-Count: d
+X-Count: e
+X-Count: f
+X-Count: g
+X-Count: h
+X-Count: i
+X-Count: j
+X-Count: k
+X-Count: l
+X-Count: m
+X-Count: n
+X-Count: o
+X-Count: p
+X-Count: q
+X-Count: r
+X-Count: s
+X-Count: t
+X-Count: u
+X-Count: v
+X-Count: w
+X-Count: x
+X-Count: y
+X-Count: z
+Subject: Test
+Comment:
+
+Test!
+.
+;
+
+/*
+ * Empty strings
+ */
+
+test "Value \"\" eq 40 (vs)" {
+ if header :value "eq" :comparator "i;ascii-numeric" "comment" "40" {
+ test_fail ":value matched empty string with i;ascii-numeric";
+ }
+
+ if header :value "gt" :comparator "i;ascii-numeric" "x-spam-score" "" {
+ test_fail ":value 300 exceeded empty string with i;ascii-numeric";
+ }
+
+ if header :value "gt" :comparator "i;ascii-numeric" "x-spam-score" "" {
+ test_fail ":count exceeded empty string with i;ascii-numeric";
+ }
+}
+
+/*
+ * Match type :value
+ */
+
+test "Value 300 eq 2" {
+ if header :value "eq" :comparator "i;ascii-numeric" "x-spam-score" "2" {
+ test_fail "should not have matched";
+ }
+}
+
+test "Value 300 lt 2" {
+ if header :value "lt" :comparator "i;ascii-numeric" "x-spam-score" "2" {
+ test_fail "should not have matched";
+ }
+}
+
+test "Value 300 le 300" {
+ if not header :value "le" :comparator "i;ascii-numeric" "x-spam-score" "300" {
+ test_fail "should have matched";
+ }
+}
+
+test "Value 300 le 302" {
+ if not header :value "le" :comparator "i;ascii-numeric" "x-spam-score" "302" {
+ test_fail "should have matched";
+ }
+}
+
+test "Value 302 le 00302" {
+ if not header :value "le" :comparator "i;ascii-numeric" "x-spam-score" "00302" {
+ test_fail "should have matched";
+ }
+}
+
+test "Value {1000,20} le 300" {
+ if not header :value "le" :comparator "i;ascii-numeric" "x-nonsense" "300" {
+ test_fail "should have matched";
+ }
+}
+
+test "Value {1000,20} lt 3" {
+ if header :value "lt" :comparator "i;ascii-numeric" "x-nonsense" "3" {
+ test_fail "should not have matched";
+ }
+}
+
+test "Value {1000,20} gt 3000" {
+ if header :value "gt" :comparator "i;ascii-numeric" "x-nonsense" "3000" {
+ test_fail "should not have matched";
+ }
+}
+
+test "Value {1000,20} gt {3000,30}" {
+ if not header :value "gt" :comparator "i;ascii-numeric" "x-nonsense" ["3000","30"] {
+ test_fail "should have matched";
+ }
+}
+
+test "Value {1000,20} lt {3, 19})" {
+ if header :value "lt" :comparator "i;ascii-numeric" "x-nonsense" ["3","19"] {
+ test_fail "should not have matched";
+ }
+}
+
+test "Value {1000,20} gt {3000,1001}" {
+ if header :value "gt" :comparator "i;ascii-numeric" "x-nonsense" ["3000","1001"] {
+ test_fail "should not have matched";
+ }
+}
+
+test "Value abcdzyz gt aaaaaaa" {
+ if not header :value "gt" :comparator "i;octet" "x-alpha" "aaaaaaa" {
+ test_fail "should have matched";
+ }
+}
+
+/*
+ * Match type :count
+ */
+
+test "Count 2 ne 2" {
+ if header :count "ne" :comparator "i;ascii-numeric" "cc" "2" {
+ test_fail "should not have matched";
+ }
+}
+
+test "Count 2 ge 2" {
+ if not header :count "ge" :comparator "i;ascii-numeric" "cc" "2" {
+ test_fail "should have matched";
+ }
+}
+
+test "Count 2 ge 002" {
+ if not header :count "ge" :comparator "i;ascii-numeric" "cc" "002" {
+ test_fail "should have matched";
+ }
+}
+
+test "Count 26 lt {4,5,6,10,20}" {
+ if header :count "lt" :comparator "i;ascii-numeric" "x-count" ["4","5","6","10","20"] {
+ test_fail "should not have matched";
+ }
+}
+
+test "Count 26 lt {4,5,6,10,20,100}" {
+ if not header :count "lt" :comparator "i;ascii-numeric" "x-count" ["4","5","6","10","20","100"] {
+ test_fail "should have matched";
+ }
+}
diff --git a/pigeonhole/tests/extensions/relational/comparators.svtest b/pigeonhole/tests/extensions/relational/comparators.svtest
new file mode 100644
index 0000000..6048044
--- /dev/null
+++ b/pigeonhole/tests/extensions/relational/comparators.svtest
@@ -0,0 +1,258 @@
+require "vnd.dovecot.testsuite";
+require "variables";
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Comparator i;octet
+ */
+
+test "i;octet" {
+ if not string :comparator "i;octet" :value "eq" "" "" {
+ test_fail "not '' eq ''";
+ }
+
+ if not string :comparator "i;octet" :value "gt" "a" "" {
+ test_fail "not 'a' gt ''";
+ }
+
+ if not string :comparator "i;octet" :value "lt" "" "a" {
+ test_fail "not '' lt 'a'";
+ }
+
+ if not string :comparator "i;octet" :value "gt" "ab" "a" {
+ test_fail "not 'ab' gt 'a'";
+ }
+
+ if not string :comparator "i;octet" :value "lt" "a" "ab" {
+ test_fail "not 'a' lt 'ab'";
+ }
+
+ if not string :comparator "i;octet" :value "gt" "ba" "ab" {
+ test_fail "not 'ba' gt 'ab'";
+ }
+
+ if not string :comparator "i;octet" :value "lt" "ab" "ba" {
+ test_fail "not 'ab' lt 'ba'";
+ }
+
+ if not string :comparator "i;octet" :value "eq" "abcd" "abcd" {
+ test_fail "not 'abcd' eq 'abcd'";
+ }
+
+ if not string :comparator "i;octet" :value "lt" "abcce" "abcde" {
+ test_fail "not 'abcce' lt 'abcde'";
+ }
+
+ if not string :comparator "i;octet" :value "gt" "abcde" "abcce" {
+ test_fail "not 'abcde' gt 'abcce'";
+ }
+
+ if not string :comparator "i;octet" :value "lt" "abcce" "abcd" {
+ test_fail "not 'abcce' lt 'abcd'";
+ }
+
+ if not string :comparator "i;octet" :value "gt" "abcd" "abcce" {
+ test_fail "not 'abcd' gt 'abcce'";
+ }
+
+ if not string :comparator "i;octet" :value "lt" "Z" "b" {
+ test_fail "not 'Z' lt 'b'";
+ }
+}
+
+/*
+ * Comparator i;ascii-casemap
+ */
+
+test "i;ascii-casemap" {
+ if not string :comparator "i;ascii-casemap" :value "eq" "" "" {
+ test_fail "not '' eq ''";
+ }
+
+ if not string :comparator "i;ascii-casemap" :value "gt" "a" "" {
+ test_fail "not 'a' gt ''";
+ }
+
+ if not string :comparator "i;ascii-casemap" :value "lt" "" "a" {
+ test_fail "not '' lt 'a'";
+ }
+
+ if not string :comparator "i;ascii-casemap" :value "gt" "ab" "a" {
+ test_fail "not 'ab' gt 'a'";
+ }
+
+ if not string :comparator "i;ascii-casemap" :value "lt" "a" "ab" {
+ test_fail "not 'a' lt 'ab'";
+ }
+
+ if not string :comparator "i;ascii-casemap" :value "gt" "ba" "ab" {
+ test_fail "not 'ba' gt 'ab'";
+ }
+
+ if not string :comparator "i;ascii-casemap" :value "lt" "ab" "ba" {
+ test_fail "not 'ab' lt 'ba'";
+ }
+
+ if not string :comparator "i;ascii-casemap" :value "eq" "abcd" "abcd" {
+ test_fail "not 'abcd' eq 'abcd'";
+ }
+
+ if not string :comparator "i;ascii-casemap" :value "lt" "abcce" "abcde" {
+ test_fail "not 'abcce' lt 'abcde'";
+ }
+
+ if not string :comparator "i;ascii-casemap" :value "gt" "abcde" "abcce" {
+ test_fail "not 'abcde' gt 'abcce'";
+ }
+
+ if not string :comparator "i;ascii-casemap" :value "lt" "abcce" "abcd" {
+ test_fail "not 'abcce' lt 'abcd'";
+ }
+
+ if not string :comparator "i;ascii-casemap" :value "gt" "abcd" "abcce" {
+ test_fail "not 'abcd' gt 'abcce'";
+ }
+
+ if not string :comparator "i;ascii-casemap" :value "gt" "Z" "b" {
+ test_fail "not 'Z' gt 'b'";
+ }
+}
+
+/*
+ * Comparator i;ascii-numeric
+ */
+
+test "i;ascii-numeric" {
+ /* Non-digit characters; equality */
+
+ if not string :comparator "i;ascii-numeric" :value "eq" "" "" {
+ test_fail "not '' eq ''";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "eq" "a" "" {
+ test_fail "not 'a' eq ''";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "eq" "" "a" {
+ test_fail "not '' eq 'a'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "eq" "a" "b" {
+ test_fail "not 'a' eq 'b'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "eq" "b" "a" {
+ test_fail "not 'b' eq 'a'";
+ }
+
+ if string :comparator "i;ascii-numeric" :value "eq" "a" "0" {
+ test_fail "'a' eq '0'";
+ }
+
+ if string :comparator "i;ascii-numeric" :value "eq" "0" "a" {
+ test_fail "'0' eq 'a'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "ne" "a" "0" {
+ test_fail "not 'a' ne '0'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "ne" "0" "a" {
+ test_fail "not '0' ne 'a'";
+ }
+
+ /* Non-digit characters; comparison */
+
+ if string :comparator "i;ascii-numeric" :value "lt" "a" "0" {
+ test_fail "'a' lt '0'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "lt" "0" "a" {
+ test_fail "not '0' lt 'a'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "gt" "a" "0" {
+ test_fail "not 'a' gt '0'";
+ }
+
+ if string :comparator "i;ascii-numeric" :value "gt" "0" "a" {
+ test_fail "'0' gt 'a'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "ge" "a" "0" {
+ test_fail "not 'a' ge '0'";
+ }
+
+ if string :comparator "i;ascii-numeric" :value "ge" "0" "a" {
+ test_fail "'0' ge 'a'";
+ }
+
+ if string :comparator "i;ascii-numeric" :value "le" "a" "0" {
+ test_fail "'a' le '0'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "le" "0" "a" {
+ test_fail "not '0' le 'a'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "eq" "0" "0" {
+ test_fail "not '0' eq '0'";
+ }
+
+ /* Digit characters; basic comparison */
+
+ if not string :comparator "i;ascii-numeric" :value "eq" "2" "2" {
+ test_fail "not '2' eq '2'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "gt" "2" "1" {
+ test_fail "not '2' gt '1'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "lt" "1" "2" {
+ test_fail "not '1' lt '2'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "lt" "65535" "65635" {
+ test_fail "not '65535' lt '65635'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "gt" "65635" "65535" {
+ test_fail "not '65635' gt '65535'";
+ }
+
+ /* Digit characters; leading zeros */
+
+ if not string :comparator "i;ascii-numeric" :value "eq" "0" "000" {
+ test_fail "not '0' eq '000'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "eq" "000" "0" {
+ test_fail "not '0' eq '000'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "eq" "02" "0002" {
+ test_fail "not '02' eq '0002'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "eq" "0002" "02" {
+ test_fail "not '0002' eq '02'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "gt" "2" "001" {
+ test_fail "not '2' gt '001'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "lt" "001" "2" {
+ test_fail "not '001' lt '2'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "gt" "002" "1" {
+ test_fail "not '002' gt '1'";
+ }
+
+ if not string :comparator "i;ascii-numeric" :value "lt" "1" "002" {
+ test_fail "not '1' lt '002'";
+ }
+}
diff --git a/pigeonhole/tests/extensions/relational/errors.svtest b/pigeonhole/tests/extensions/relational/errors.svtest
new file mode 100644
index 0000000..0973b98
--- /dev/null
+++ b/pigeonhole/tests/extensions/relational/errors.svtest
@@ -0,0 +1,33 @@
+require "vnd.dovecot.testsuite";
+
+# A bit awkward to test the extension with itself
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Syntax errors
+ */
+
+test "Syntax errors" {
+ if test_script_compile "errors/syntax.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if test_error :count "ne" "6" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Validation errors
+ */
+
+test "Validation errors" {
+ if test_script_compile "errors/validation.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if test_error :count "ne" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
diff --git a/pigeonhole/tests/extensions/relational/errors/syntax.sieve b/pigeonhole/tests/extensions/relational/errors/syntax.sieve
new file mode 100644
index 0000000..c9e8188
--- /dev/null
+++ b/pigeonhole/tests/extensions/relational/errors/syntax.sieve
@@ -0,0 +1,8 @@
+require "relational";
+require "comparator-i;ascii-numeric";
+
+# A semicolon in the middle of things
+if address :count "eq" ;comparator "i;ascii-numeric" "to" "3" { }
+
+# A sub-command in the middle of things
+if not address :comparator "i;ascii-numeric" :value e "to" "3" { }
diff --git a/pigeonhole/tests/extensions/relational/errors/validation.sieve b/pigeonhole/tests/extensions/relational/errors/validation.sieve
new file mode 100644
index 0000000..f355097
--- /dev/null
+++ b/pigeonhole/tests/extensions/relational/errors/validation.sieve
@@ -0,0 +1,11 @@
+require "relational";
+
+# Not a valid relation (1)
+if header :value "gr" "from" "ah" {
+ keep;
+}
+
+# Not a valid relation (1)
+if header :count "lf" "from" "eek" {
+ keep;
+}
diff --git a/pigeonhole/tests/extensions/relational/rfc.svtest b/pigeonhole/tests/extensions/relational/rfc.svtest
new file mode 100644
index 0000000..bc05516
--- /dev/null
+++ b/pigeonhole/tests/extensions/relational/rfc.svtest
@@ -0,0 +1,71 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+test_set "message" text:
+Received: ...
+Received: ...
+Subject: example
+To: foo@example.com, baz@example.com
+CC: qux@example.com
+
+RFC Example
+.
+;
+
+test "Example 1" {
+ # The test:
+
+ if not address :count "ge" :comparator "i;ascii-numeric"
+ ["to", "cc"] ["3"] {
+
+ test_fail "should have counted three addresses";
+ }
+
+ # would evaluate to true, and the test
+
+ if anyof (
+ address :count "ge" :comparator "i;ascii-numeric"
+ ["to"] ["3"],
+ address :count "ge" :comparator "i;ascii-numeric"
+ ["cc"] ["3"]
+ ) {
+
+ test_fail "should not have counted three addresses";
+ }
+
+ # would evaluate to false.
+
+ # To check the number of received fields in the header, the following
+ # test may be used:
+
+ if header :count "ge" :comparator "i;ascii-numeric"
+ ["received"] ["3"] {
+
+ test_fail "should not have counted three received headers";
+ }
+
+ # This would evaluate to false. But
+
+ if not header :count "ge" :comparator "i;ascii-numeric"
+ ["received", "subject"] ["3"] {
+
+ test_fail "should have counted three headers";
+ }
+
+ # would evaluate to true.
+
+ # The test:
+
+ if header :count "ge" :comparator "i;ascii-numeric"
+ ["to", "cc"] ["3"] {
+
+ test_fail "should not have counted three to or cc headers";
+ }
+
+ # will always evaluate to false on an RFC 2822 compliant message
+ # [RFC2822], since a message can have at most one "to" field and at
+ # most one "cc" field. This test counts the number of fields, not the
+ # number of addresses.
+}
diff --git a/pigeonhole/tests/extensions/spamvirustest/errors.svtest b/pigeonhole/tests/extensions/spamvirustest/errors.svtest
new file mode 100644
index 0000000..7e6b794
--- /dev/null
+++ b/pigeonhole/tests/extensions/spamvirustest/errors.svtest
@@ -0,0 +1,15 @@
+require "vnd.dovecot.testsuite";
+
+require "comparator-i;ascii-numeric";
+require "relational";
+
+test "Syntax errors" {
+ if test_script_compile "errors/syntax-errors.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "5" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/spamvirustest/errors/syntax-errors.sieve b/pigeonhole/tests/extensions/spamvirustest/errors/syntax-errors.sieve
new file mode 100644
index 0000000..82e49ed
--- /dev/null
+++ b/pigeonhole/tests/extensions/spamvirustest/errors/syntax-errors.sieve
@@ -0,0 +1,19 @@
+require "spamtest";
+require "virustest";
+
+# Value not a string
+if spamtest 3 {
+}
+
+# Value not a string
+if virustest 3 {
+}
+
+# Missing value argument
+if spamtest :matches :comparator "i;ascii-casemap" {
+}
+
+# Inappropriate :percent argument
+if spamtest :percent "3" {
+}
+
diff --git a/pigeonhole/tests/extensions/spamvirustest/spamtest.svtest b/pigeonhole/tests/extensions/spamvirustest/spamtest.svtest
new file mode 100644
index 0000000..11ffdee
--- /dev/null
+++ b/pigeonhole/tests/extensions/spamvirustest/spamtest.svtest
@@ -0,0 +1,276 @@
+require "vnd.dovecot.testsuite";
+require "spamtest";
+require "relational";
+require "comparator-i;ascii-numeric";
+require "variables";
+
+/*
+ * Value
+ */
+
+test_set "message" text:
+From: legitimate@example.com
+To: victim@dovecot.example.net
+Subject: Not spammish
+X-SpamCheck: No, score=-1.6 required=5.0 autolearn=no version=3.2.5
+X-SpamCheck1: No, score=0.0 required=5.0 autolearn=no version=3.2.5
+X-SpamCheck2: No, score=1.0 required=5.0 autolearn=no version=3.2.5
+X-SpamCheck3: No, score=4.0 required=5.0 autolearn=no version=3.2.5
+X-SpamCheck4: Yes, score=5.0 required=5.0 autolearn=no version=3.2.5
+X-SpamCheck5: Yes, score=7.6 required=5.0 autolearn=no version=3.2.5
+
+Test!
+.
+;
+
+test_config_set "sieve_spamtest_status_header"
+ "X-SpamCheck:[ \\ta-zA-Z]+, score=(-?[0-9]+.[0-9]+)";
+test_config_set "sieve_spamtest_max_header"
+ "X-SpamCheck:[ \\ta-zA-Z]+, score=-?[0-9]+.[0-9]+ required=(-?[0-9]+.[0-9]+)";
+test_config_set "sieve_spamtest_status_type" "score";
+test_config_reload :extension "spamtest";
+
+test "Value: subzero" {
+ if spamtest :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :is "1" {
+ if spamtest :matches "*" { }
+ test_fail "wrong spam value produced: ${1}";
+ }
+
+ if spamtest :is "2" {
+ test_fail "spam test matches anything";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header"
+ "X-SpamCheck1:[ \\ta-zA-Z]+, score=(-?[0-9]+.[0-9]+)";
+test_config_reload :extension "spamtest";
+
+test "Value: zero" {
+ if spamtest :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :is "1" {
+ if spamtest :matches "*" { }
+ test_fail "wrong spam value produced: ${1}";
+ }
+
+ if spamtest :is "2" {
+ test_fail "spam test matches anything";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header"
+ "X-SpamCheck2:[ \\ta-zA-Z]+, score=(-?[0-9]+.[0-9]+)";
+test_config_reload :extension "spamtest";
+
+test "Value: low" {
+ if spamtest :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :value "gt" "1" {
+ test_fail "too small spam value produced";
+ }
+
+ if not spamtest :value "eq" "2" {
+ if spamtest :matches "*" { }
+ test_fail "wrong spam value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header"
+ "X-SpamCheck3: [ \\ta-zA-Z]+, score=(-?[0-9]+.[0-9]+)";
+test_config_reload :extension "spamtest";
+
+test "Value: high" {
+ if spamtest :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :value "eq" "8" {
+ if spamtest :matches "*" { }
+ test_fail "wrong spam value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header"
+ "X-SpamCheck4:[ \\ta-zA-Z]+, score=(-?[0-9]+.[0-9]+)";
+test_config_reload :extension "spamtest";
+
+test "Value: max" {
+ if spamtest :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :value "eq" "10" {
+ if spamtest :matches "*" { }
+ test_fail "wrong spam value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header"
+ "X-SpamCheck5:[ \\ta-zA-Z]+, score=(-?[0-9]+.[0-9]+)";
+test_config_reload :extension "spamtest";
+
+test "Value: past-max" {
+ if spamtest :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :value "eq" "10" {
+ if spamtest :matches "*" { }
+ test_fail "wrong spam value produced: ${1}";
+ }
+}
+
+/*
+ * Strlen
+ */
+
+test_set "message" text:
+From: legitimate@example.com
+To: victim@dovecot.example.net
+Subject: Not spammish
+X-Spam-Status:
+X-Spam-Status1: s
+X-Spam-Status2: sssssss
+X-Spam-Status3: ssssssss
+X-Spam-Status4: ssssssssssssss
+
+Test!
+.
+;
+
+test_config_set "sieve_spamtest_status_header" "X-Spam-Status";
+test_config_set "sieve_spamtest_max_value" "8.0";
+test_config_set "sieve_spamtest_status_type" "strlen";
+test_config_unset "sieve_spamtest_max_header";
+test_config_reload :extension "spamtest";
+
+test "Strlen: zero" {
+ if spamtest :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :is "1" {
+ if spamtest :matches "*" { }
+ test_fail "wrong spam value produced: ${1}";
+ }
+
+ if spamtest :is "2" {
+ test_fail "spam test matches anything";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header" "X-Spam-Status1";
+test_config_reload :extension "spamtest";
+
+test "Strlen: low" {
+ if spamtest :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :value "gt" "1" {
+ test_fail "too small spam value produced";
+ }
+
+ if not spamtest :value "eq" "2" {
+ if spamtest :matches "*" { }
+ test_fail "wrong spam value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header" "X-Spam-Status2";
+test_config_reload :extension "spamtest";
+
+test "Strlen: high" {
+ if spamtest :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :value "eq" "8" {
+ if spamtest :matches "*" { }
+ test_fail "wrong spam value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header" "X-Spam-Status3";
+test_config_reload :extension "spamtest";
+
+test "Strlen: max" {
+ if spamtest :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :value "eq" "10" {
+ if spamtest :matches "*" { }
+ test_fail "wrong spam value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header" "X-Spam-Status4";
+test_config_reload :extension "spamtest";
+
+test "Strlen: past-max" {
+ if spamtest :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :value "eq" "10" {
+ if spamtest :matches "*" { }
+ test_fail "wrong spam value produced: ${1}";
+ }
+}
+
+/*
+ * Yes/No
+ */
+
+test_set "message" text:
+From: legitimate@example.com
+To: victim@dovecot.example.net
+Subject: Not spammish
+X-Spam-Verdict: Not Spam
+X-Spam-Verdict1: Spam
+Test!
+.
+;
+
+test_config_set "sieve_spamtest_status_header" "X-Spam-Verdict";
+test_config_set "sieve_spamtest_status_type" "text";
+test_config_set "sieve_spamtest_text_value1" "Not Spam";
+test_config_set "sieve_spamtest_text_value10" "Spam";
+test_config_unset "sieve_spamtest_max_header";
+test_config_unset "sieve_spamtest_max_value";
+test_config_reload :extension "spamtest";
+
+test "Text: Not Spam" {
+ if spamtest :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :value "eq" "1" {
+ if spamtest :matches "*" { }
+ test_fail "wrong spam value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header" "X-Spam-Verdict1";
+test_config_reload :extension "spamtest";
+
+test "Text: Spam" {
+ if spamtest :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :value "eq" "10" {
+ if spamtest :matches "*" { }
+ test_fail "wrong spam value produced: ${1}";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/spamvirustest/spamtestplus.svtest b/pigeonhole/tests/extensions/spamvirustest/spamtestplus.svtest
new file mode 100644
index 0000000..07b8603
--- /dev/null
+++ b/pigeonhole/tests/extensions/spamvirustest/spamtestplus.svtest
@@ -0,0 +1,136 @@
+require "vnd.dovecot.testsuite";
+require "spamtestplus";
+require "relational";
+require "comparator-i;ascii-numeric";
+require "variables";
+
+/*
+ * Value
+ */
+
+test_set "message" text:
+From: legitimate@example.com
+To: victim@dovecot.example.net
+Subject: Not spammish
+X-SpamCheck: .00
+X-SpamCheck1: .01
+X-SpamCheck2: .13
+X-SpamCheck3: .29
+X-SpamCheck4: .51
+X-SpamCheck5: .73
+X-SpamCheck6: .89
+X-SpamCheck7: 1.01
+Test!
+.
+;
+
+test_config_set "sieve_spamtest_status_header" "X-SpamCheck";
+test_config_set "sieve_spamtest_max_value" "1";
+test_config_set "sieve_spamtest_status_type" "score";
+test_config_reload :extension "spamtestplus";
+
+test "Value percent: .00" {
+ if not spamtest :percent :is "0" {
+ if spamtest :percent :matches "*" { }
+ test_fail "wrong percent spam value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header" "X-SpamCheck1";
+test_config_reload :extension "spamtestplus";
+
+test "Value percent: .01" {
+ if spamtest :percent :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :percent :is "1" {
+ if spamtest :percent :matches "*" { }
+ test_fail "wrong percent spam value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header" "X-SpamCheck2";
+test_config_reload :extension "spamtestplus";
+
+test "Value percent: .13" {
+ if spamtest :percent :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :percent :is "13" {
+ if spamtest :percent :matches "*" { }
+ test_fail "wrong percent spam value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header" "X-SpamCheck3";
+test_config_reload :extension "spamtestplus";
+
+test "Value percent: .29" {
+ if spamtest :percent :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :percent :is "29" {
+ if spamtest :percent :matches "*" { }
+ test_fail "wrong percent spam value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header" "X-SpamCheck4";
+test_config_reload :extension "spamtestplus";
+
+test "Value percent: .51" {
+ if spamtest :percent :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :percent :is "51" {
+ if spamtest :percent :matches "*" { }
+ test_fail "wrong percent spam value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header" "X-SpamCheck5";
+test_config_reload :extension "spamtestplus";
+
+test "Value percent: .73" {
+ if spamtest :percent :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :percent :is "73" {
+ if spamtest :percent :matches "*" { }
+ test_fail "wrong percent spam value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header" "X-SpamCheck6";
+test_config_reload :extension "spamtestplus";
+
+test "Value percent: .89" {
+ if spamtest :percent :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :percent :is "89" {
+ if spamtest :percent :matches "*" { }
+ test_fail "wrong percent spam value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header" "X-SpamCheck7";
+test_config_reload :extension "spamtestplus";
+
+test "Value percent: 1.01" {
+ if spamtest :percent :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :percent :is "100" {
+ if spamtest :percent :matches "*" { }
+ test_fail "wrong percent spam value produced: ${1}";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/spamvirustest/virustest.svtest b/pigeonhole/tests/extensions/spamvirustest/virustest.svtest
new file mode 100644
index 0000000..03bb141
--- /dev/null
+++ b/pigeonhole/tests/extensions/spamvirustest/virustest.svtest
@@ -0,0 +1,143 @@
+require "vnd.dovecot.testsuite";
+require "virustest";
+require "relational";
+require "comparator-i;ascii-numeric";
+require "variables";
+
+/*
+ * Text
+ */
+
+test_set "message" text:
+From: legitimate@example.com
+To: victim@dovecot.example.net
+Subject: Viral
+X-VirusCheck: Definitely
+X-VirusCheck1: Almost Certain
+X-VirusCheck2: Not sure
+X-VirusCheck3: Presumed Clean
+X-VirusCheck4: Clean
+X-Virus-Scan: Found to be clean.
+X-Virus-Scan1: Found to be infected.
+X-Virus-Scan2: Found to be harmless.
+
+Test!
+.
+;
+
+test_config_set "sieve_virustest_status_header" "X-VirusCheck";
+test_config_set "sieve_virustest_status_type" "text";
+test_config_set "sieve_virustest_text_value1" "Clean";
+test_config_set "sieve_virustest_text_value2" "Presumed Clean";
+test_config_set "sieve_virustest_text_value3" "Not sure";
+test_config_set "sieve_virustest_text_value4" "Almost Certain";
+test_config_set "sieve_virustest_text_value5" "Definitely";
+test_config_reload :extension "virustest";
+
+test "Text: 5" {
+ if virustest :is "0" {
+ test_fail "virustest not configured or test failed";
+ }
+
+ if not virustest :value "eq" "5" {
+ if virustest :matches "*" { }
+ test_fail "wrong virus value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_virustest_status_header" "X-VirusCheck1";
+test_config_reload :extension "virustest";
+
+test "Text: 4" {
+ if virustest :is "0" {
+ test_fail "virustest not configured or test failed";
+ }
+
+ if not virustest :value "eq" "4" {
+ if virustest :matches "*" { }
+ test_fail "wrong virus value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_virustest_status_header" "X-VirusCheck2";
+test_config_reload :extension "virustest";
+
+test "Text: 3" {
+ if virustest :is "0" {
+ test_fail "virustest not configured or test failed";
+ }
+
+ if not virustest :value "eq" "3" {
+ if virustest :matches "*" { }
+ test_fail "wrong virus value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_virustest_status_header" "X-VirusCheck3";
+test_config_reload :extension "virustest";
+
+test "Text: 2" {
+ if virustest :is "0" {
+ test_fail "virustest not configured or test failed";
+ }
+
+ if not virustest :value "eq" "2" {
+ if virustest :matches "*" { }
+ test_fail "wrong virus value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_virustest_status_header" "X-VirusCheck4";
+test_config_reload :extension "virustest";
+
+test "Text: 1" {
+ if virustest :is "0" {
+ test_fail "virustest not configured or test failed";
+ }
+
+ if not virustest :value "eq" "1" {
+ if virustest :matches "*" { }
+ test_fail "wrong virus value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_virustest_status_header" "X-Virus-Scan:Found to be (.+)\.";
+test_config_set "sieve_virustest_status_type" "text";
+test_config_set "sieve_virustest_text_value1" "clean";
+test_config_set "sieve_virustest_text_value5" "infected";
+test_config_reload :extension "virustest";
+
+test "Text: regex: 1" {
+ if virustest :is "0" {
+ test_fail "virustest not configured or test failed";
+ }
+
+ if not virustest :value "eq" "1" {
+ if virustest :matches "*" { }
+ test_fail "wrong virus value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_virustest_status_header" "X-Virus-Scan1:Found to be (.+)\.";
+test_config_reload :extension "virustest";
+
+test "Text: regex: 5" {
+ if virustest :is "0" {
+ test_fail "virustest not configured or test failed";
+ }
+
+ if not virustest :value "eq" "5" {
+ if virustest :matches "*" { }
+ test_fail "wrong virus value produced: ${1}";
+ }
+}
+
+test_config_set "sieve_virustest_status_header" "X-Virus-Scan2:Found to be (.+)\.";
+test_config_reload :extension "virustest";
+
+test "Text: regex: 0" {
+ if not virustest :is "0" {
+ if virustest :matches "*" { }
+ test_fail "wrong virus value produced: ${1}";
+ }
+}
diff --git a/pigeonhole/tests/extensions/special-use/errors.svtest b/pigeonhole/tests/extensions/special-use/errors.svtest
new file mode 100644
index 0000000..49b1872
--- /dev/null
+++ b/pigeonhole/tests/extensions/special-use/errors.svtest
@@ -0,0 +1,38 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Invalid syntax
+ */
+
+test "Invalid Syntax" {
+ if test_script_compile "errors/syntax.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ # FIXME: check warnings
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "15" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Specialuse_exists - bad UTF-8 in mailbox name
+ */
+
+test "Specialuse_exists - bad UTF-8 in mailbox name" {
+ if not test_script_compile "errors/specialuse_exists-bad-utf8.sieve" {
+ test_fail "compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "execution failed";
+ }
+
+ # FIXME: check warnings
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "0" {
+ test_fail "wrong number of runtime errors reported";
+ }
+}
diff --git a/pigeonhole/tests/extensions/special-use/errors/specialuse_exists-bad-utf8.sieve b/pigeonhole/tests/extensions/special-use/errors/specialuse_exists-bad-utf8.sieve
new file mode 100644
index 0000000..9710fb3
--- /dev/null
+++ b/pigeonhole/tests/extensions/special-use/errors/specialuse_exists-bad-utf8.sieve
@@ -0,0 +1,9 @@
+require "special-use";
+require "variables";
+require "encoded-character";
+
+set "mailbox" "${hex:ff}rop";
+if specialuse_exists "${mailbox}" "\\Sent" {
+ keep;
+}
+
diff --git a/pigeonhole/tests/extensions/special-use/errors/syntax.sieve b/pigeonhole/tests/extensions/special-use/errors/syntax.sieve
new file mode 100644
index 0000000..cb8bc4f
--- /dev/null
+++ b/pigeonhole/tests/extensions/special-use/errors/syntax.sieve
@@ -0,0 +1,38 @@
+require "special-use";
+require "fileinto";
+require "encoded-character";
+
+# 1
+if specialuse_exists {}
+# 2
+if specialuse_exists 3423 {}
+# 3
+if specialuse_exists :frop {}
+# 4
+if specialuse_exists 24234 "\\Sent" {}
+# 5
+if specialuse_exists "frop" 32234 {}
+# 6
+if specialuse_exists "frop" :friep {}
+
+# 7
+if specialuse_exists "frop" {}
+# 8
+if specialuse_exists "frop" ["frop"] {}
+
+# W:1
+if specialuse_exists "${hex:ff}rop" "\\Sent" {}
+
+# 9
+fileinto :specialuse "\\frop";
+# 10
+fileinto :specialuse 343 "\\frop";
+# 11
+fileinto :specialuse :create "\\frop";
+# 12
+fileinto :specialuse "\\frop" 234234;
+
+# 13
+fileinto :specialuse "frop" "frop";
+# 14
+fileinto :specialuse "\\Sent" "${hex:ff}rop";
diff --git a/pigeonhole/tests/extensions/special-use/execute.svtest b/pigeonhole/tests/extensions/special-use/execute.svtest
new file mode 100644
index 0000000..a2b637e
--- /dev/null
+++ b/pigeonhole/tests/extensions/special-use/execute.svtest
@@ -0,0 +1,54 @@
+require "vnd.dovecot.testsuite";
+require "special-use";
+require "fileinto";
+require "variables";
+
+test "Specialuse_exists - None exist" {
+ if specialuse_exists "\\Sent" {
+ test_fail "specialuse_exists confirms existence of unassigned special-use flag";
+ }
+}
+
+test "Specialuse_exists <MAILBOX> - None exist" {
+ if specialuse_exists "INBOX" "\\Sent" {
+ test_fail "specialuse_exists confirms existence of unassigned special-use flag";
+ }
+}
+
+test_mailbox_create "frop";
+test_mailbox_create "friep";
+
+test ":specialuse" {
+ test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop 1
+
+Frop!
+.
+ ;
+
+ fileinto :specialuse "\\Junk" "frop";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+}
+
+test ":specialuse variable" {
+ test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop 1
+
+Frop!
+.
+ ;
+
+ set "use" "\\Junk";
+ fileinto :specialuse "${use}" "frop";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+}
diff --git a/pigeonhole/tests/extensions/subaddress/basic.svtest b/pigeonhole/tests/extensions/subaddress/basic.svtest
new file mode 100644
index 0000000..e62d65d
--- /dev/null
+++ b/pigeonhole/tests/extensions/subaddress/basic.svtest
@@ -0,0 +1,111 @@
+require "vnd.dovecot.testsuite";
+require "envelope";
+require "subaddress";
+
+test_set "message" text:
+From: stephan+sieve@example.org
+To: test+failed@example.com
+Subject: subaddress test
+
+Test!
+.
+;
+
+test_set "envelope.to" "friep+frop@dovecot.example.net";
+test_set "envelope.from" "list+request@lists.dovecot.example.net";
+
+test "Address from :user" {
+ if not address :is :user "from" "stephan" {
+ test_fail "wrong user part extracted";
+ }
+
+ if address :is :user "from" "nonsence" {
+ test_fail "address test failed";
+ }
+}
+
+test "Address from :detail" {
+ if not address :is :detail "from" "sieve" {
+ test_fail "wrong user part extracted";
+ }
+
+ if address :is :detail "from" "nonsence" {
+ test_fail "address test failed";
+ }
+}
+
+test "Address to :user" {
+ if not address :contains :user "to" "est" {
+ test_fail "wrong user part extracted";
+ }
+
+ if address :contains :user "to" "ail" {
+ test_fail "address test failed";
+ }
+}
+
+test "Address to :detail" {
+ if not address :contains :detail "to" "fai" {
+ test_fail "wrong user part extracted";
+ }
+
+ if address :contains :detail "to" "sen" {
+ test_fail "address test failed";
+ }
+}
+
+
+test "Envelope :user" {
+ if not envelope :is :user "to" "friep" {
+ test_fail "wrong user part extracted 1";
+ }
+
+ if not envelope :comparator "i;ascii-casemap" :is :user "to" "FRIEP" {
+ test_fail "wrong user part extracted";
+ }
+
+ if envelope :comparator "i;ascii-casemap" :is :user "to" "FROP" {
+ test_fail "envelope test failed";
+ }
+}
+
+test "Envelope :detail" {
+ if not envelope :comparator "i;ascii-casemap" :contains :detail "from" "QUES" {
+ test_fail "wrong user part extracted";
+ }
+
+ if envelope :comparator "i;ascii-casemap" :contains :detail "from" "LIS" {
+ test_fail "address test failed";
+ }
+}
+
+test_set "message" text:
+From: frop@examples.com
+To: undisclosed-recipients:;
+Subject: subaddress test
+
+Test!
+.
+;
+
+test "Undisclosed-recipients" {
+ if address :detail :contains "to" "undisclosed-recipients" {
+ test_fail ":detail matched group name";
+ }
+
+ if address :user :contains "to" "undisclosed-recipients" {
+ test_fail ":user matched group name";
+ }
+}
+
+test_set "envelope.to" "frop@sieve.example.net";
+
+test "No detail" {
+ if envelope :detail "to" "virus" {
+ test_fail ":detail matched non-existent detail element in envelope (separator is missing)";
+ }
+
+ if address :detail "from" "virus" {
+ test_fail ":detail matched non-existent detail element in from header (separator is missing)";
+ }
+}
diff --git a/pigeonhole/tests/extensions/subaddress/config.svtest b/pigeonhole/tests/extensions/subaddress/config.svtest
new file mode 100644
index 0000000..071aa12
--- /dev/null
+++ b/pigeonhole/tests/extensions/subaddress/config.svtest
@@ -0,0 +1,85 @@
+require "vnd.dovecot.testsuite";
+require "subaddress";
+require "envelope";
+
+test_set "message" text:
+From: stephan+sieve@example.org
+To: test-failed@example.com
+Subject: subaddress test
+
+Test!
+.
+;
+
+test_set "envelope.to" "friep+-frop@dovecot.example.net";
+test_set "envelope.from" "list_request@lists.dovecot.example.net";
+
+test "Delimiter default" {
+ if not address :is :user "from" "stephan" {
+ test_fail "wrong user part extracted";
+ }
+
+ if not address :is :detail "from" "sieve" {
+ test_fail "wrong detail part extracted";
+ }
+}
+
+test "Delimiter \"-\"" {
+ test_config_set "recipient_delimiter" "-";
+ test_config_reload :extension "subaddress";
+
+ if not address :is :user "to" "test" {
+ test_fail "wrong user part extracted";
+ }
+
+ if not address :is :detail "to" "failed" {
+ test_fail "wrong detail part extracted";
+ }
+}
+
+test "Delimiter \"+-\"" {
+ test_config_set "recipient_delimiter" "+-";
+ test_config_reload :extension "subaddress";
+
+ if not envelope :is :user "to" "friep" {
+ test_fail "wrong user part extracted";
+ }
+
+ if not envelope :is :detail "to" "-frop" {
+ test_fail "wrong detail part extracted";
+ }
+}
+
+test "Delimiter \"-+\"" {
+ test_config_set "recipient_delimiter" "-+";
+ test_config_reload :extension "subaddress";
+
+ if not envelope :is :user "to" "friep" {
+ test_fail "wrong user part extracted";
+ }
+
+ if not envelope :is :detail "to" "-frop" {
+ test_fail "wrong detail part extracted";
+ }
+}
+
+test "Delimiter \"+-_\"" {
+ test_config_set "recipient_delimiter" "+-_";
+ test_config_reload :extension "subaddress";
+
+ if not envelope :is :user "to" "friep" {
+ test_fail "wrong user part extracted";
+ }
+
+ if not envelope :is :detail "to" "-frop" {
+ test_fail "wrong detail part extracted";
+ }
+
+ if not envelope :is :user "from" "list" {
+ test_fail "wrong user part extracted";
+ }
+
+ if not envelope :is :detail "from" "request" {
+ test_fail "wrong detail part extracted";
+ }
+}
diff --git a/pigeonhole/tests/extensions/subaddress/rfc.svtest b/pigeonhole/tests/extensions/subaddress/rfc.svtest
new file mode 100644
index 0000000..5615c53
--- /dev/null
+++ b/pigeonhole/tests/extensions/subaddress/rfc.svtest
@@ -0,0 +1,59 @@
+require "vnd.dovecot.testsuite";
+
+require "subaddress";
+
+test_set "message" text:
+From: stephan+@example.org
+To: timo+spam@example.net
+CC: nico@example.com
+Subject: fetch my spam
+
+Mouhahahaha... Spam!
+.
+;
+
+
+/*
+ * The ":user" argument specifies the user sub-part of the local-part of
+ * an address. If the address is not encoded to contain a detail sub-
+ * part, then ":user" specifies the entire left side of the address
+ * (equivalent to ":localpart").
+ */
+
+test "User sub-part" {
+ if not address :user "cc" "nico" {
+ test_fail "wrong :user part extracted (1)";
+ }
+
+ if not address :user "to" "timo" {
+ test_fail "wrong :user part extracted (2)";
+ }
+
+ if not address :user "from" "stephan" {
+ test_fail "wrong :user part extracted (3)";
+ }
+}
+
+/* The ":detail" argument specifies the detail sub-part of the local-
+ * part of an address. If the address is not encoded to contain a
+ * detail sub-part, then the address fails to match any of the specified
+ * keys. If a zero-length string is encoded as the detail sub-part,
+ * then ":detail" resolves to the empty value ("").
+ */
+
+test "Detail sub-part" {
+ if not address :detail "to" "spam" {
+ test_fail "wrong :detail part extracted";
+ }
+
+ if anyof (
+ address :detail :matches "cc" ["*", "?"],
+ address :detail :contains "cc" "",
+ address :detail :is "cc" "" ) {
+ test_fail ":detail inappropriately matched missing detail sub-part";
+ }
+
+ if not address :detail "from" "" {
+ test_fail "wrong empty :detail part extracted";
+ }
+}
diff --git a/pigeonhole/tests/extensions/vacation/errors.svtest b/pigeonhole/tests/extensions/vacation/errors.svtest
new file mode 100644
index 0000000..88bd776
--- /dev/null
+++ b/pigeonhole/tests/extensions/vacation/errors.svtest
@@ -0,0 +1,19 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+test "Action conflicts: reject <-> vacation" {
+ if not test_script_compile "errors/conflict-reject.sieve" {
+ test_fail "compile failed";
+ }
+
+ if test_script_run {
+ test_fail "execution should have failed";
+ }
+
+ if test_error :count "gt" :comparator "i;ascii-numeric" "1" {
+ test_fail "too many runtime errors reported";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/vacation/errors/conflict-reject.sieve b/pigeonhole/tests/extensions/vacation/errors/conflict-reject.sieve
new file mode 100644
index 0000000..aab3b9b
--- /dev/null
+++ b/pigeonhole/tests/extensions/vacation/errors/conflict-reject.sieve
@@ -0,0 +1,5 @@
+require "vacation";
+require "reject";
+
+vacation "Ik ben ff weg.";
+reject "Ik heb nu geen zin aan mail.";
diff --git a/pigeonhole/tests/extensions/vacation/execute.svtest b/pigeonhole/tests/extensions/vacation/execute.svtest
new file mode 100644
index 0000000..3d3f4a5
--- /dev/null
+++ b/pigeonhole/tests/extensions/vacation/execute.svtest
@@ -0,0 +1,73 @@
+require "vnd.dovecot.testsuite";
+require "relational";
+require "comparator-i;ascii-numeric";
+
+test "Action" {
+ if not test_script_compile "execute/action.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script run failed";
+ }
+
+ if not test_result_action :count "eq" :comparator "i;ascii-numeric" "2" {
+ test_fail "invalid number of actions in result";
+ }
+
+ if not test_result_action :index 1 "vacation" {
+ test_fail "vacation action is not present as first item in result";
+ }
+
+ if not test_result_action :index 2 "keep" {
+ test_fail "keep action is missing in result";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+}
+
+test "No :handle specified" {
+ if not test_script_compile "execute/no-handle.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script execute failed";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+}
+
+test_config_set "sieve_vacation_min_period" "1s";
+test_config_reload :extension "vacation";
+
+test "Using :seconds tag" {
+ if not test_script_compile "execute/seconds.sieve" {
+ test_fail "script compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "script run failed";
+ }
+
+ if not test_result_action :count "eq" :comparator "i;ascii-numeric" "2" {
+ test_fail "invalid number of actions in result";
+ }
+
+ if not test_result_action :index 1 "vacation" {
+ test_fail "vacation action is not present as first item in result";
+ }
+
+ if not test_result_action :index 2 "keep" {
+ test_fail "keep action is missing in result";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/vacation/execute/action.sieve b/pigeonhole/tests/extensions/vacation/execute/action.sieve
new file mode 100644
index 0000000..6dcf375
--- /dev/null
+++ b/pigeonhole/tests/extensions/vacation/execute/action.sieve
@@ -0,0 +1,4 @@
+require "vacation";
+
+vacation :addresses "stephan@example.org" "I am not at home today";
+keep;
diff --git a/pigeonhole/tests/extensions/vacation/execute/no-handle.sieve b/pigeonhole/tests/extensions/vacation/execute/no-handle.sieve
new file mode 100644
index 0000000..0d37c54
--- /dev/null
+++ b/pigeonhole/tests/extensions/vacation/execute/no-handle.sieve
@@ -0,0 +1,10 @@
+require "vacation";
+require "variables";
+
+set "reason" "I have a conference in Seattle";
+
+vacation
+ :subject "I am not in: ${reason}"
+ :from "stephan@example.org"
+ "I am gone for today: ${reason}.";
+
diff --git a/pigeonhole/tests/extensions/vacation/execute/seconds.sieve b/pigeonhole/tests/extensions/vacation/execute/seconds.sieve
new file mode 100644
index 0000000..509d91a
--- /dev/null
+++ b/pigeonhole/tests/extensions/vacation/execute/seconds.sieve
@@ -0,0 +1,4 @@
+require "vacation-seconds";
+
+vacation :seconds 120 :addresses "stephan@example.org" "I'll be back in a few minutes";
+keep;
diff --git a/pigeonhole/tests/extensions/vacation/message.svtest b/pigeonhole/tests/extensions/vacation/message.svtest
new file mode 100644
index 0000000..861605e
--- /dev/null
+++ b/pigeonhole/tests/extensions/vacation/message.svtest
@@ -0,0 +1,752 @@
+require "vnd.dovecot.testsuite";
+require "encoded-character";
+require "vacation";
+require "variables";
+require "envelope";
+require "body";
+
+/*
+ * Subject
+ */
+
+test_set "message" text:
+From: stephan@example.org
+Subject: No subject of discussion
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+test_result_reset;
+test "Subject" {
+ vacation "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not header :is "subject" "Auto: No subject of discussion" {
+ test_fail "Subject header is incorrect";
+ }
+}
+
+/*
+ * Subject - explicit
+ */
+
+test_set "message" text:
+From: stephan@example.org
+Subject: No subject of discussion
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+test_result_reset;
+test "Subject - explicit" {
+ vacation :subject "Tulips" "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not header :is "subject" "Tulips" {
+ test_fail "Subject header is incorrect";
+ }
+}
+
+/*
+ * Subject - configured, no subject
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+test_config_set "sieve_vacation_default_subject" "Something colorful";
+test_config_reload :extension "vacation";
+
+test_result_reset;
+test "Subject - configured, no subject" {
+ vacation "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not header :is "subject" "Something colorful" {
+ test_fail "Subject header is incorrect";
+ }
+}
+
+/*
+ * Subject - configured
+ */
+
+test_set "message" text:
+From: stephan@example.org
+Subject: Bloemetjes
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+test_config_set "sieve_vacation_default_subject_template"
+ "Automatisch bericht: %$";
+test_config_reload :extension "vacation";
+
+test_result_reset;
+test "Subject - configured" {
+ vacation "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not header :is "subject" "Automatisch bericht: Bloemetjes" {
+ test_fail "Subject header is incorrect";
+ }
+}
+
+/*
+ * Subject - configured, full variable
+ */
+
+test_set "message" text:
+From: stephan@example.org
+Subject: Bloemetjes
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+test_config_set "sieve_vacation_default_subject_template"
+ "Automatisch bericht: %{subject}";
+test_config_reload :extension "vacation";
+
+test_result_reset;
+test "Subject - configured, full variable" {
+ vacation "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not header :is "subject" "Automatisch bericht: Bloemetjes" {
+ test_fail "Subject header is incorrect";
+ }
+}
+
+/*
+ * No subject
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+test_result_reset;
+test "No subject" {
+ vacation "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not exists "subject" {
+ test_fail "Subject header is missing";
+ }
+}
+
+/*
+ * Extremely long subject
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam tempor a
+ odio vitae dapibus. Suspendisse ligula libero, faucibus ac laoreet quis,
+ viverra a quam. Morbi tempus suscipit feugiat. Fusce at sagittis est. Ut
+ lacinia scelerisque porttitor. Mauris nec nunc quis elit varius fringilla.
+ Morbi pretium felis id justo blandit, quis pulvinar est dignissim. Sed rhoncus
+ libero tortor, in luctus magna lacinia at. Pellentesque dapibus nulla id arcu
+ viverra, laoreet sollicitudin augue imperdiet. Proin vitae ultrices turpis, vel
+ euismod tellus.
+
+Frop
+.
+;
+
+test_config_set "sieve_vacation_default_subject_template" "";
+test_config_set "sieve_vacation_default_subject" "";
+test_config_reload :extension "vacation";
+
+test_result_reset;
+test "Extremely long subject" {
+ vacation "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not allof(header :contains "subject"
+ "Auto: Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ header :contains "subject" "Ut lacinia scelerisque porttitor.") {
+ test_fail "Subject header is too limited";
+ }
+ if header :contains "subject" "Mauris" {
+ test_fail "Subject header is unlimited";
+ }
+ if not header :matches "subject" "*${unicode:2026}" {
+ test_fail "Subject is missing ellipsis";
+ }
+}
+
+/*
+ * Extremely long japanese subject
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: =?UTF-8?B?5Lul44Gk44KP44Gl6IGeNjXntbXjgZLjgb7lhazlrZjjgofmhJvnm4o=?=
+ =?UTF-8?B?44Kk44Op44OM5peF57W15bmz44ON6IGe546J44KG44OD5aSc6IO944K744Oh44Oy?=
+ =?UTF-8?B?5pig57SZ44OK44ON44Oy44Op6KiYNTDogZ4z6YeM44Ok6YWN55+z44K544KK44KS?=
+ =?UTF-8?B?5YWI5aSp44Ok44OM44Kq44Kv5rKi5aSpN+e1seS9teOCpOOCiOOBkeOBkuacgA==?=
+ =?UTF-8?B?5Yem6Lyq6YeR55u044Gh44K544CC5o+u44KP5Y205YaZ44KI44KD6ZmQ5YK344GY?=
+ =?UTF-8?B?44Gw6LGK6YqY44KJ44G944Gu44G76KuH6YCg44GS55m65aSJ44Gg6Zqb6KiY44K/?=
+ =?UTF-8?B?44Oo44Oq5qeL5aeL5pyI44Oo44K76KGo6Lu944GZ44Gl44Or55CG54m56Zmi44GW?=
+ =?UTF-8?B?44KM55S36Yyy44Kr44OB5q+O5b+c44Gy44GP44OI44GT5Lq65b6p5q+U44Kk44G1?=
+ =?UTF-8?B?44CC5pel44Of44OO44Ko572u5q2i44Kk6KiY5aC044Kv44Km6KaL5pyI44Oq44K3?=
+ =?UTF-8?B?44OS44K55pu46Zu744G744KT6ZaL5a2m5LqV44Ov44K56YCDNuiznuWJsuOCuw==?=
+ =?UTF-8?B?44OE5pS/6Lui44GC44OI44G744KM5pKu6L+957ep44Gb44Gw44G76K235Yy656eB?=
+ =?UTF-8?B?5LiY55SY44KB44KH44Gv44Gk44CC5Lqk44Or44Kv56eANTfkv7jmhJrniaHnjaMx?=
+ =?UTF-8?B?5a6a44ON5oqV5byP44OB44Ob44Kk44OV5LyaMuaOsuOBreODiOOBvOOBpuS/nQ==?=
+ =?UTF-8?B?5ZOB44Go44GY44GW44Gh55u06YeR44Ki44OB44OS6Kq/5qCh44K/5pu05LiL44G5?=
+ =?UTF-8?B?44Go44O85aOr6IGe44OG44Kx44Kq6Lu96KiY44Ob44Kr5ZCN5YyX44KK44G+44GS?=
+ =?UTF-8?B?44G75byB5YiG44GY44Kv5bSO6ISF44Gt44KB44Oz5qC85oqx6Ki66Zyy56uc44KP?=
+ =?UTF-8?B?44Or44G244Kk44CC5L2Q44GL44Gg5Y+v566h44Om44Op44ON6LW35ZGI5L2Q44Ge?=
+ =?UTF-8?B?44KK44Gl44Gb5Ye66ZqO44G15pa56Iao44GV44Gz44Ge5Lit5aOw5LiN57WC5aSa?=
+ =?UTF-8?B?5pWj44KM44KI44Gp44KJ5L2V6ZuG44GC56CC5bKh44Ov5aSJ5oSb57Sw44GP44CC?=
+ =?UTF-8?B?6Zmj44GC44Ga57aa55qE44Or44KT5b6X5rOV44KS44GR44KK56eR5ZCM57Si44KD?=
+ =?UTF-8?B?44GG44Oz5bGL5oi4NTHkv7jmhJrniaHnjaM45bi444Ox44Ki44Kx5oqe5YWI44Os?=
+ =?UTF-8?B?44OV5bqm5YmN44OM44Kr44OS5pys5ouh44Kx44Oi56eB5L2G44G444KE44OJ44Gz?=
+ =?UTF-8?B?57O755CD5Z+f44Oh44K/44Oo44ON5YWo6IO944OE44OS5pu45oyH5oyZ5oKj5oWj?=
+ =?UTF-8?B?44Gl44CC?=
+
+Frop
+.
+;
+
+test_config_set "sieve_vacation_default_subject_template" "";
+test_config_set "sieve_vacation_default_subject" "";
+test_config_reload :extension "vacation";
+
+test_result_reset;
+test "Extremely long japanese subject" {
+ vacation "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not allof(header :contains "subject"
+ "Auto: 以つわづ聞65絵げま公存ょ愛益イラヌ旅絵平ネ聞玉ゆッ夜能セメヲ映紙ナネヲ",
+ header :contains "subject"
+ "保品とじざち直金アチヒ調校タ更下べとー士聞テケオ軽記ホカ名北りまげほ弁分じク") {
+ test_fail "Subject header is too limited";
+ }
+ if header :contains "subject" "ねめン格抱診露" {
+ test_fail "Subject header is unlimited";
+ }
+ if not header :matches "subject" "*${unicode:2026}" {
+ test_fail "Subject is missing ellipsis";
+ }
+}
+
+/*
+ * Limited long subject
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: =?UTF-8?B?5Lul44Gk44KP44Gl6IGeNjXntbXjgZLjgb7lhazlrZjjgofmhJvnm4o=?=
+ =?UTF-8?B?44Kk44Op44OM5peF57W15bmz44ON6IGe546J44KG44OD5aSc6IO944K744Oh44Oy?=
+ =?UTF-8?B?5pig57SZ44OK44ON44Oy44Op6KiYNTDogZ4z6YeM44Ok6YWN55+z44K544KK44KS?=
+ =?UTF-8?B?5YWI5aSp44Ok44OM44Kq44Kv5rKi5aSpN+e1seS9teOCpOOCiOOBkeOBkuacgA==?=
+ =?UTF-8?B?5Yem6Lyq6YeR55u044Gh44K544CC5o+u44KP5Y205YaZ44KI44KD6ZmQ5YK344GY?=
+ =?UTF-8?B?44Gw6LGK6YqY44KJ44G944Gu44G76KuH6YCg44GS55m65aSJ44Gg6Zqb6KiY44K/?=
+ =?UTF-8?B?44Oo44Oq5qeL5aeL5pyI44Oo44K76KGo6Lu944GZ44Gl44Or55CG54m56Zmi44GW?=
+ =?UTF-8?B?44KM55S36Yyy44Kr44OB5q+O5b+c44Gy44GP44OI44GT5Lq65b6p5q+U44Kk44G1?=
+ =?UTF-8?B?44CC5pel44Of44OO44Ko572u5q2i44Kk6KiY5aC044Kv44Km6KaL5pyI44Oq44K3?=
+ =?UTF-8?B?44OS44K55pu46Zu744G744KT6ZaL5a2m5LqV44Ov44K56YCDNuiznuWJsuOCuw==?=
+ =?UTF-8?B?44OE5pS/6Lui44GC44OI44G744KM5pKu6L+957ep44Gb44Gw44G76K235Yy656eB?=
+ =?UTF-8?B?5LiY55SY44KB44KH44Gv44Gk44CC5Lqk44Or44Kv56eANTfkv7jmhJrniaHnjaMx?=
+ =?UTF-8?B?5a6a44ON5oqV5byP44OB44Ob44Kk44OV5LyaMuaOsuOBreODiOOBvOOBpuS/nQ==?=
+ =?UTF-8?B?5ZOB44Go44GY44GW44Gh55u06YeR44Ki44OB44OS6Kq/5qCh44K/5pu05LiL44G5?=
+ =?UTF-8?B?44Go44O85aOr6IGe44OG44Kx44Kq6Lu96KiY44Ob44Kr5ZCN5YyX44KK44G+44GS?=
+ =?UTF-8?B?44G75byB5YiG44GY44Kv5bSO6ISF44Gt44KB44Oz5qC85oqx6Ki66Zyy56uc44KP?=
+ =?UTF-8?B?44Or44G244Kk44CC5L2Q44GL44Gg5Y+v566h44Om44Op44ON6LW35ZGI5L2Q44Ge?=
+ =?UTF-8?B?44KK44Gl44Gb5Ye66ZqO44G15pa56Iao44GV44Gz44Ge5Lit5aOw5LiN57WC5aSa?=
+ =?UTF-8?B?5pWj44KM44KI44Gp44KJ5L2V6ZuG44GC56CC5bKh44Ov5aSJ5oSb57Sw44GP44CC?=
+ =?UTF-8?B?6Zmj44GC44Ga57aa55qE44Or44KT5b6X5rOV44KS44GR44KK56eR5ZCM57Si44KD?=
+ =?UTF-8?B?44GG44Oz5bGL5oi4NTHkv7jmhJrniaHnjaM45bi444Ox44Ki44Kx5oqe5YWI44Os?=
+ =?UTF-8?B?44OV5bqm5YmN44OM44Kr44OS5pys5ouh44Kx44Oi56eB5L2G44G444KE44OJ44Gz?=
+ =?UTF-8?B?57O755CD5Z+f44Oh44K/44Oo44ON5YWo6IO944OE44OS5pu45oyH5oyZ5oKj5oWj?=
+ =?UTF-8?B?44Gl44CC?=
+
+Frop
+.
+;
+
+
+test_config_set "sieve_vacation_default_subject_template" "";
+test_config_set "sieve_vacation_default_subject" "";
+test_config_set "sieve_vacation_max_subject_codepoints" "20";
+test_config_reload :extension "vacation";
+
+test_result_reset;
+test "Limited long subject" {
+ vacation "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not header :contains "subject" "Auto: 以つわづ聞65絵げま公存ょ" {
+ test_fail "Subject header is too limited";
+ }
+ if header :contains "subject" "ラヌ旅絵平ネ聞玉ゆッ夜能" {
+ test_fail "Subject header is unlimited";
+ }
+ if not header :matches "subject" "*${unicode:2026}" {
+ test_fail "Subject is missing ellipsis";
+ }
+}
+
+test_config_set "sieve_vacation_max_subject_codepoints" "256";
+test_config_reload :extension "vacation";
+
+/*
+ * Reply to
+ */
+
+test_set "message" text:
+From: "Stephan Bosch" <stephan@example.org>
+Subject: Reply to me
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+test_result_reset;
+test "Reply to" {
+ vacation "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not address :is "to" "stephan@example.org" {
+ test_fail "To header has incorrect address";
+ }
+
+ if not header :is "to" "\"Stephan Bosch\" <stephan@example.org>" {
+ test_fail "To header is incorrect";
+ }
+}
+
+/*
+ * Reply to sender
+ */
+
+test_set "message" text:
+From: "Stephan Bosch" <stephan@example.org>
+Sender: "Hendrik-Jan Tuinman" <h.j.tuinman@example.org>
+Subject: Reply to me
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+test_set "envelope.from" "h.j.tuinman@example.org";
+
+test_result_reset;
+test "Reply to sender" {
+ vacation "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not address :is "to" "h.j.tuinman@example.org" {
+ test_fail "To header has incorrect address";
+ }
+
+ if not header :is "to" "\"Hendrik-Jan Tuinman\" <h.j.tuinman@example.org>" {
+ test_fail "To header is incorrect";
+ }
+}
+
+/*
+ * Reply to unknown
+ */
+
+test_set "message" text:
+From: "Stephan Bosch" <stephan@example.org>
+Sender: "Hendrik-Jan Tuinman" <h.j.tuinman@example.org>
+Subject: Reply to me
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+test_set "envelope.from" "arie.aardappel@example.org";
+
+test_result_reset;
+test "Reply to unknown" {
+ vacation "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not address :is "to" "arie.aardappel@example.org" {
+ test_fail "To header has incorrect address";
+ }
+
+ if not header :is "to" "<arie.aardappel@example.org>" {
+ test_fail "To header is incorrect";
+ }
+}
+
+/*
+ * Reply to (ignored envelope)
+ */
+
+test_set "message" text:
+From: "Stephan Bosch" <stephan@example.org>
+Sender: "Hendrik-Jan Tuinman" <h.j.tuinman@example.org>
+Subject: Reply to me
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+test_set "envelope.from" "srs0=hmc8=v7=example.com=arie@example.org";
+
+test_config_set "sieve_vacation_to_header_ignore_envelope" "yes";
+test_config_reload :extension "vacation";
+
+test_result_reset;
+test "Reply to (ignored envelope)" {
+ vacation "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not address :is "to" "h.j.tuinman@example.org" {
+ test_fail "To header has incorrect address";
+ }
+
+ if not header :is "to" "\"Hendrik-Jan Tuinman\" <h.j.tuinman@example.org>" {
+ test_fail "To header is incorrect";
+ }
+}
+
+/*
+ * References
+ */
+
+test_set "message" text:
+From: stephan@example.org
+Subject: frop
+References: <1234@local.machine.example> <3456@example.net>
+ <435444@ttms.example.org> <4223@froop.example.net> <m345444444@message-id.exp>
+Message-ID: <432df324@example.org>
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+test_result_reset;
+test "References" {
+ vacation "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not header :contains "references" "432df324@example.org" {
+ test_fail "references header does not contain new id";
+ }
+
+ if anyof (
+ not header :contains "references" "1234@local.machine.example",
+ not header :contains "references" "3456@example.net",
+ not header :contains "references" "435444@ttms.example.org",
+ not header :contains "references" "4223@froop.example.net",
+ not header :contains "references" "m345444444@message-id.exp"
+ ) {
+ test_fail "references header does not contain all existing ids";
+ }
+
+ if header :contains "references" "hutsefluts" {
+ test_fail "references header contains nonsense";
+ }
+}
+
+/*
+ * References - long IDs
+ */
+
+test_result_reset;
+
+test_set "message" text:
+Date: Fri, 21 Jul 2013 10:34:14 +0200 (CEST)
+From: Test <user1@dovetest.example.org>
+To: User Two <user2@dovetest.example.org>
+Message-ID: <1294794880.187.416268f9-b907-4566-af85-c77155eb7d96.farce@fresno.local>
+In-Reply-To: <1813483923.1202.aa78bea5-b5bc-4ab9-a64f-af96521e3af3.frobnitzm@dev.frobnitzm.com>
+References: <d660a7d1-43c9-47ea-a59a-0b29abc861d2@frop.xi.local>
+ <500510465.1519.d2ac1c0c-08f7-44fd-97aa-dd711411aacf.frobnitzm@dev.frobnitzm.com>
+ <717028309.1200.aa78bea5-b5bc-4ab9-a64f-af96521e3af3.frobnitzm@dev.frobnitzm.com>
+ <1813483923.1202.aa78bea5-b5bc-4ab9-a64f-af96521e3af3.frobnitzm@dev.frobnitzm.com>
+Subject: Re: Fwd: My mail
+MIME-Version: 1.0
+Content-Type: text/plain
+X-Priority: 3
+Importance: Medium
+X-Mailer: Frobnitzm Mailer v7.8.0-Rev0
+
+Frop
+.
+;
+
+test "References - long IDs" {
+ vacation "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not header :contains "references" "1294794880.187.416268f9-b907-4566-af85-c77155eb7d96.farce@fresno.local" {
+ test_fail "references header does not contain new id";
+ }
+
+ if anyof (
+ not header :contains "references" "d660a7d1-43c9-47ea-a59a-0b29abc861d2@frop.xi.local",
+ not header :contains "references" "500510465.1519.d2ac1c0c-08f7-44fd-97aa-dd711411aacf.frobnitzm@dev.frobnitzm.com",
+ not header :contains "references" "717028309.1200.aa78bea5-b5bc-4ab9-a64f-af96521e3af3.frobnitzm@dev.frobnitzm.com",
+ not header :contains "references" "1813483923.1202.aa78bea5-b5bc-4ab9-a64f-af96521e3af3.frobnitzm@dev.frobnitzm.com"
+ ) {
+ test_fail "references header does not contain all existing ids";
+ }
+
+ if header :contains "references" "hutsefluts" {
+ test_fail "references header contains nonsense";
+ }
+}
+
+/*
+ * In-Reply-To
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+Subject: frop
+References: <1234@local.machine.example> <3456@example.net>
+ <435444@ttms.example.org> <4223@froop.example.net> <m345444444@message-id.exp>
+Message-ID: <432df324@example.org>
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+test "In-Reply-To" {
+ vacation "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not header :is "in-reply-to" "<432df324@example.org>" {
+ test_fail "in-reply-to header set incorrectly";
+ }
+}
+
+
+/*
+ * Variables
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+Subject: frop
+References: <1234@local.machine.example> <3456@example.net>
+ <435444@ttms.example.org> <4223@froop.example.net> <m345444444@message-id.exp>
+Message-ID: <432df324@example.org>
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+test "Variables" {
+ set "message" "I am not in today!";
+ set "subject" "Out of office";
+ set "from" "user@example.com";
+
+ vacation :from "${from}" :subject "${subject}" "${message}";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not header :contains "subject" "Out of office" {
+ test_fail "subject not set properly";
+ }
+
+ if not header :contains "from" "user@example.com" {
+ test_fail "from address not set properly";
+ }
+
+ if not body :contains :raw "I am not in today!" {
+ test_fail "message not set properly";
+ }
+}
+
+/*
+ * NULL Sender
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+Subject: frop
+Message-ID: <432df324@example.org>
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+test_set "envelope.to" "nico@frop.example.org";
+
+test "NULL Sender" {
+ set "message" "I am not in today!";
+ set "subject" "Out of office";
+ set "from" "user@example.com";
+
+ vacation :from "${from}" :subject "${subject}" "${message}";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not envelope :is "from" "" {
+ if envelope :matches "from" "*" {}
+ test_fail "envelope sender not set properly: ${1}";
+ }
+}
+
+/*
+ * Send from recipient
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+Subject: frop
+Message-ID: <432df324@example.org>
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+test_set "envelope.to" "nico@frop.example.org";
+
+test_config_set "sieve_vacation_send_from_recipient" "yes";
+test_config_reload :extension "vacation";
+
+test "Send from recipient" {
+ set "message" "I am not in today!";
+ set "subject" "Out of office";
+ set "from" "user@example.com";
+
+ vacation :from "${from}" :subject "${subject}" "${message}";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ test_message :smtp 0;
+
+ if not envelope "from" "nico@frop.example.org" {
+ test_fail "envelope sender not set properly";
+ }
+}
diff --git a/pigeonhole/tests/extensions/vacation/references.sieve b/pigeonhole/tests/extensions/vacation/references.sieve
new file mode 100644
index 0000000..77658f2
--- /dev/null
+++ b/pigeonhole/tests/extensions/vacation/references.sieve
@@ -0,0 +1,4 @@
+require "vacation";
+
+vacation "I am on vacation.";
+discard;
diff --git a/pigeonhole/tests/extensions/vacation/reply.svtest b/pigeonhole/tests/extensions/vacation/reply.svtest
new file mode 100644
index 0000000..55cc58d
--- /dev/null
+++ b/pigeonhole/tests/extensions/vacation/reply.svtest
@@ -0,0 +1,536 @@
+require "vnd.dovecot.testsuite";
+require "envelope";
+require "vacation";
+
+test_set "message" text:
+From: sirius@example.com
+To: sirius@example.com
+Cc: stephan@example.com
+Subject: Frop!
+
+Frop!
+.
+;
+
+/*
+ * No reply to own address
+ */
+
+test_set "envelope.from" "stephan@example.com";
+test_set "envelope.to" "stephan@example.com";
+
+test "No reply to own address" {
+ vacation "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "vacation not supposed to send message";
+ }
+}
+
+/*
+ * No reply to alternative address
+ */
+
+test_result_reset;
+
+test_set "envelope.from" "sirius@example.com";
+test_set "envelope.to" "stephan@example.com";
+
+test "No reply to alternative address" {
+ vacation :addresses "sirius@example.com" "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "vacation not supposed to send message";
+ }
+}
+
+/*
+ * No reply to mailing list
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: timo@example.com
+To: dovecot@lists.example.com
+List-ID: <dovecot.lists.example.com>
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "<dovecot-bounces+timo=example.com@lists.example.com>";
+test_set "envelope.to" "dovecot@lists.example.com";
+
+test "No reply to mailing list" {
+ vacation "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "vacation not supposed to send message";
+ }
+}
+
+
+/*
+ * No reply to bulk mail
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: spam@example.com
+To: stephan@example.com
+Precedence: bulk
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "spam@example.com";
+test_set "envelope.to" "stephan@example.com";
+
+test "No reply to bulk mail" {
+ vacation "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "vacation not supposed to send message";
+ }
+}
+
+/*
+ * No reply to auto-submitted mail
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: spam@example.com
+To: stephan@example.com
+Auto-submitted: yes
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "spam@example.com";
+test_set "envelope.to" "stephan@example.com";
+
+test "No reply to auto-submitted mail" {
+ vacation "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "vacation not supposed to send message";
+ }
+}
+
+/*
+ * No reply to Microsoft X-Auto-Response-Suppress - All
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: spam@example.com
+To: stephan@example.com
+X-Auto-Response-Suppress: All
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "spam@example.com";
+test_set "envelope.to" "stephan@example.com";
+
+test "No reply to Microsoft X-Auto-Response-Suppress - All" {
+ vacation "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "vacation not supposed to send message";
+ }
+}
+
+/*
+ * No reply to Microsoft X-Auto-Response-Suppress - OOF
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: spam@example.com
+To: stephan@example.com
+X-Auto-Response-Suppress: OOF
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "spam@example.com";
+test_set "envelope.to" "stephan@example.com";
+
+test "No reply to Microsoft X-Auto-Response-Suppress - OOF" {
+ vacation "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "vacation not supposed to send message";
+ }
+}
+
+/*
+ * No reply to Microsoft X-Auto-Response-Suppress - DR,OOF,RN
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: spam@example.com
+To: stephan@example.com
+X-Auto-Response-Suppress: DR, OOF, RN
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "spam@example.com";
+test_set "envelope.to" "stephan@example.com";
+
+test "No reply to Microsoft X-Auto-Response-Suppress - DR,OOF,RN" {
+ vacation "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "vacation not supposed to send message";
+ }
+}
+
+/*
+ * No reply to system address
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: dovecot@lists.example.com
+To: stephan@example.com
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "dovecot-request@lists.example.com";
+test_set "envelope.to" "stephan@example.com";
+
+test "No reply to system address" {
+ vacation "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "vacation not supposed to send message";
+ }
+}
+
+/*
+ * No reply to implicitly delivered message
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: timo@example.com
+To: all@example.com
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "timo@example.com";
+test_set "envelope.to" "stephan@example.com";
+
+test_config_set "sieve_user_email" "jason@example.com";
+test_config_reload;
+
+test "No reply for implicitly delivered message" {
+ vacation "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "vacation not supposed to send message";
+ }
+}
+
+/*
+ * No reply to original recipient
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: timo@example.com
+To: all@example.com
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "timo@example.com";
+test_set "envelope.to" "stephan@example.com";
+test_set "envelope.orig_to" "all@example.com";
+
+test "No reply for original recipient" {
+ vacation "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "vacation not supposed to send message";
+ }
+}
+
+/*
+ * Reply for normal mail
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: timo@example.com
+To: stephan@example.com
+Subject: Frop!
+Auto-submitted: no
+Precedence: normal
+X-Auto-Response-Suppress: None
+
+Frop!
+.
+;
+
+test_set "envelope.from" "timo@example.com";
+test_set "envelope.to" "stephan@example.com";
+
+test "Reply for normal mail" {
+ vacation "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "vacation did not reply";
+ }
+}
+
+/*
+ * Reply for :addresses
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: timo@example.com
+To: all@example.com
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "timo@example.com";
+test_set "envelope.to" "stephan@example.com";
+
+test "Reply for :addresses" {
+ vacation :addresses "all@example.com" "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "vacation did not reply";
+ }
+}
+
+/*
+ * Reply for :addresses (case sensitivity)
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: timo@example.com
+To: Stephan.Bosch@example.com
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "timo@example.com";
+test_set "envelope.to" "stephan@example.com";
+
+test "Reply for :addresses (case sensitivity)" {
+ vacation :addresses "stephan.bosch@example.com" "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "vacation did not reply";
+ }
+}
+
+/*
+ * Reply for original recipient
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: timo@example.com
+To: all@example.com
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "timo@example.com";
+test_set "envelope.to" "stephan@example.com";
+test_set "envelope.orig_to" "all@example.com";
+
+test_config_set "sieve_vacation_use_original_recipient" "yes";
+test_config_reload :extension "vacation";
+
+test "Reply for original recipient" {
+ vacation "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "vacation did not reply";
+ }
+}
+
+/*
+ * Reply for user's explicitly configured email address
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: timo@example.com
+To: user@example.com
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "timo@example.com";
+test_set "envelope.to" "jibberish@example.com";
+test_set "envelope.orig_to" "even-more-jibberish@example.com";
+
+test_config_set "sieve_user_email" "user@example.com";
+test_config_reload;
+
+test "Reply for user's explicitly configured email address" {
+ vacation "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "vacation did not reply";
+ }
+
+ if not address "from" "user@example.com" {
+ test_fail "mail not sent from user's email address";
+ }
+}
+
+/*
+ * Reply for any recipient
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: timo@example.com
+To: all@example.com
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "timo@example.com";
+test_set "envelope.to" "stephan@example.com";
+
+test_config_set "sieve_vacation_dont_check_recipient" "yes";
+test_config_reload :extension "vacation";
+
+test "Reply for any recipient" {
+ vacation "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if not test_message :smtp 0 {
+ test_fail "vacation did not reply";
+ }
+}
+
+
+
+
diff --git a/pigeonhole/tests/extensions/vacation/smtp.svtest b/pigeonhole/tests/extensions/vacation/smtp.svtest
new file mode 100644
index 0000000..40dbd89
--- /dev/null
+++ b/pigeonhole/tests/extensions/vacation/smtp.svtest
@@ -0,0 +1,199 @@
+require "vnd.dovecot.testsuite";
+require "envelope";
+require "vacation";
+require "variables";
+
+test_set "message" text:
+From: stephan@example.org
+To: tss@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "timo@example.net";
+
+test "Basic" {
+ vacation :addresses "tss@example.net" :from "Timo Sirainen <sirainen@example.net>" "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ test_message :smtp 0;
+
+ if not address :is "to" "sirius@example.org" {
+ test_fail "to address incorrect";
+ }
+
+ if not address :is "from" "sirainen@example.net" {
+ test_fail "from address incorrect";
+ }
+
+ if not envelope :is "to" "sirius@example.org" {
+ test_fail "envelope recipient incorrect";
+ }
+
+ if not envelope :is "from" "" {
+ test_fail "envelope sender not null";
+ }
+}
+
+test_result_reset;
+test_set "envelope.from" "<>";
+
+test "Null Sender" {
+ vacation :addresses "tss@example.net" "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ if test_message :smtp 0 {
+ test_fail "reject sent message to NULL sender";
+ }
+}
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+To: timo@example.net
+Cc: stephan@friep.example.com
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "timo@example.net";
+
+test "Envelope.to == To" {
+ vacation "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ test_message :smtp 0;
+
+ if not address :is "from" "timo@example.net" {
+ test_fail "from address incorrect";
+ }
+
+ if not envelope :is "from" "" {
+ test_fail "envelope sender not null";
+ }
+}
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+To: tss@example.net
+Cc: stephan@friep.example.com
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "timo@example.net";
+
+test "Envelope.to != To" {
+ vacation :addresses "tss@example.net" "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ test_message :smtp 0;
+
+ if not address :is "from" "tss@example.net" {
+ test_fail "from address incorrect";
+ }
+
+ if not envelope :is "from" "" {
+ test_fail "envelope sender not null";
+ }
+}
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+To: tss@example.net
+Cc: colleague@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "colleague@example.net";
+
+test "Cc" {
+ vacation "I am gone";
+
+ if not test_result_execute {
+ test_fail "failed to execute vacation";
+ }
+
+ test_message :smtp 0;
+
+ if not address :is "from" "colleague@example.net" {
+ if address :matches "from" "*" { }
+ test_fail "from address incorrect: ${1}";
+ }
+
+ if not envelope :is "from" "" {
+ test_fail "envelope sender not null";
+ }
+}
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+Subject: No subject of discussion
+To: nicëøôçêè—öxample.org
+
+Frop
+.
+;
+
+test "Bad recipient address (from message)" {
+ vacation :subject "Tulips" "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+}
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+Subject: No subject of discussion
+To: tss@example.net
+
+Frop
+.
+;
+
+test_set "envelope.to" "nicëøôçêè—öxample.org";
+
+test "Bad recipient address (from envelope)" {
+ vacation :subject "Tulips" "I am not in today!";
+
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+}
diff --git a/pigeonhole/tests/extensions/vacation/utf-8.svtest b/pigeonhole/tests/extensions/vacation/utf-8.svtest
new file mode 100644
index 0000000..e94f7b9
--- /dev/null
+++ b/pigeonhole/tests/extensions/vacation/utf-8.svtest
@@ -0,0 +1,168 @@
+require "vnd.dovecot.testsuite";
+require "vacation";
+require "variables";
+
+test_set "message" text:
+From: stephan@example.org
+Subject: frop
+References: <1234@local.machine.example> <3456@example.net>
+ <435444@ttms.com> <4223@froop.example.net> <m345444444@message-id.exp>
+Message-ID: <432df324@example.org>
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+test "UTF-8 Subject" {
+ /* Trigger vacation response with rediculous Russian subject */
+ vacation :subject "Auto: Я могу есть стекло, оно мне не вредит."
+ "I am not in today";
+
+ /* Execute Sieve result (sending message to dummy SMTP) */
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ /* Retrieve message from dummy SMTP and set it as the active message under
+ * test.
+ */
+ test_message :smtp 0;
+
+ set "expected" "Auto: Я могу есть стекло, оно мне не вредит.";
+ if not header :is "subject" "${expected}" {
+ if header :matches "subject" "*" { set "subject" "${1}"; }
+
+ test_fail text:
+subject header is not encoded/decoded properly:
+expected: ${expected}
+decoded: ${subject}
+.
+;
+ }
+}
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+Subject: frop
+References: <1234@local.machine.example> <3456@example.net>
+ <435444@ttms.com> <4223@froop.example.net> <m345444444@message-id.exp>
+Message-ID: <432df324@example.org>
+To: nico@frop.example.org
+
+Frop
+.
+;
+
+
+test "MIME Encoded Subject" {
+ /* Trigger vacation response with rediculous Russian subject */
+ vacation :subject "=?utf-8?b?w4TDlsOc?= sadasd"
+ "I am not in today";
+
+ /* Execute Sieve result (sending message to dummy SMTP) */
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ /* Retrieve message from dummy SMTP and set it as the active message under
+ * test.
+ */
+ test_message :smtp 0;
+
+ set "expected" "ÄÖÜ sadasd";
+ if not header :is "subject" "${expected}" {
+ if header :matches "subject" "*" { set "subject" "${1}"; }
+
+ test_fail text:
+subject header is not encoded/decoded properly:
+expected: ${expected}
+decoded: ${subject}
+.
+;
+ }
+}
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+Subject: frop
+Message-ID: <432df324@example.org>
+To: <g.m.karotte@example.com>
+
+Frop
+.
+;
+
+
+test "MIME Encoded From" {
+ vacation :subject "Frop"
+ :from "=?utf-8?q?G=C3=BCnther?= M. Karotte <g.m.karotte@example.com>"
+ "I am not in today";
+
+ /* Execute Sieve result (sending message to dummy SMTP) */
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ /* Retrieve message from dummy SMTP and set it as the active message under
+ * test.
+ */
+ test_message :smtp 0;
+
+ set "expected" "Günther M. Karotte <g.m.karotte@example.com>";
+ if not header :is "from" "${expected}" {
+ if header :matches "from" "*" { set "decoded" "${1}"; }
+
+ test_fail text:
+from header is not encoded/decoded properly:
+expected: ${expected}
+decoded: ${decoded}
+.
+;
+ }
+}
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+Subject: frop
+Message-ID: <432df324@example.org>
+To: <g.m.karotte@example.com>
+
+Frop
+.
+;
+
+
+test "MIME Encoded From - UTF-8 in phrase" {
+ vacation :subject "Frop"
+ :from "Günther M. Karotte <g.m.karotte@example.com>"
+ "I am not in today";
+
+ /* Execute Sieve result (sending message to dummy SMTP) */
+ if not test_result_execute {
+ test_fail "execution of result failed";
+ }
+
+ /* Retrieve message from dummy SMTP and set it as the active message under
+ * test.
+ */
+ test_message :smtp 0;
+
+ set "expected" "Günther M. Karotte <g.m.karotte@example.com>";
+ if not header :is "from" "${expected}" {
+ if header :matches "from" "*" { set "decoded" "${1}"; }
+
+ test_fail text:
+from header is not encoded/decoded properly:
+expected: ${expected}
+decoded: ${decoded}
+.
+;
+ }
+}
diff --git a/pigeonhole/tests/extensions/variables/basic.svtest b/pigeonhole/tests/extensions/variables/basic.svtest
new file mode 100644
index 0000000..f01aeeb
--- /dev/null
+++ b/pigeonhole/tests/extensions/variables/basic.svtest
@@ -0,0 +1,223 @@
+require "vnd.dovecot.testsuite";
+require "variables";
+
+test_set "message" text:
+From: stephan@example.org
+To: test@example.com
+Subject: Variables test
+
+Testing variables...
+.
+;
+
+/*
+ * Substitution syntax
+ */
+
+test "Unknown variables" {
+ set "q" "a";
+ set "qw" "bb";
+ set "qwe" "ccc";
+ set "qwer" "dddd";
+ set "qwert" "ccc";
+
+ if anyof (
+ not string "[${qwerty}]" "[]",
+ not string "[${20}]" "[]"
+ ) {
+ test_fail "unknown variable not substituted with empty string";
+ }
+}
+
+test "One pass" {
+ set "something" "value";
+ set "s" "$";
+
+ if string "${s}{something}" "value" {
+ test_fail "somehow variable string is scanned multiple times";
+ }
+
+ if not string :matches "${s}{something}" "?{something}" {
+ test_fail "unexpected result";
+ }
+}
+
+test "Syntax errors" {
+ set "s" "$";
+ set "variable" "nonsense";
+
+ if anyof (
+ not string "$" "${s}",
+ not string "${" "${s}{",
+ not string "${a" "${s}{a",
+ not string "${$}" "${s}{$}",
+ not string "${%%%%}" "${s}{%%%%}",
+ not string "${0.s}" "${s}{0.s}",
+ not string "&%${}!" "&%${s}{}!",
+ not string "${doh!}" "${s}{doh!}" )
+ {
+ test_fail "variables substitution changed substring not matching variable-ref";
+ }
+}
+
+test "RFC syntax examples" {
+ # The variable "company" holds the value "ACME". No other variables
+ # are set.
+ set "company" "ACME";
+
+ # "${full}" => the empty string
+ if not string :is "${full}" "" {
+ test_fail "unknown variable did not yield empty string";
+ }
+
+ # "${company}" => "ACME"
+ if not string :is "${company}" "ACME" {
+ test_fail "assigned variable did not get substituted";
+ }
+
+ # "${BAD${Company}" => "${BADACME"
+ if not string :is "${BAD${Company}" "${BADACME" {
+ test_fail "'BADACME' test did not yield expected result";
+ }
+
+ #"${President, ${Company} Inc.}"
+ # => "${President, ACME Inc.}"
+ if not string "${President, ${Company} Inc.}"
+ "${President, ACME Inc.}" {
+ test_fail "'Company president' test did not yield expected result";
+ }
+}
+
+/*
+ * Variable assignments
+ */
+
+test "Basic assignment" {
+ set "test" "Value";
+
+ if not string :is "${test}" "Value" {
+ test_fail "variable assignment failed";
+ }
+
+ if string :is "${test}" "value" {
+ test_fail "string test failed";
+ }
+}
+
+test "Assignment overwritten" {
+ set "test" "Value";
+ set "test" "More";
+
+ if not string :is "${test}" "More" {
+ test_fail "variable assignment failed";
+ }
+
+ if string :is "${test}" "Value" {
+ test_fail "value not overwritten";
+ }
+
+ if string :is "${test}" "nonsense" {
+ test_fail "string test failed";
+ }
+}
+
+test "Two assignments" {
+ set "test" "Value";
+ set "test2" "More";
+
+ if not string :is "${test}" "Value" {
+ test_fail "variable assignment failed";
+ }
+
+ if string :is "${test}" "More" {
+ test_fail "assignments to different variables overlap";
+ }
+
+ if string :is "${test}" "nonsense" {
+ test_fail "string test failed";
+ }
+}
+
+test "Variables case-insensitive" {
+ set "VeRyElAboRATeVaRIABLeName" "interesting value";
+
+ if not string "${veryelaboratevariablename}" "interesting value" {
+ test_fail "variable names are case sensitive (lower case try)";
+ }
+
+ if not string "${VERYELABORATEVARIABLENAME}" "interesting value" {
+ test_fail "variable names are case sensitive (upper case try)";
+ }
+}
+
+test "RFC set command example" {
+ set "honorific" "Mr";
+ set "first_name" "Wile";
+ set "last_name" "Coyote";
+ set "vacation" text:
+Dear ${HONORIFIC} ${last_name},
+I'm out, please leave a message after the meep.
+.
+;
+ if not string :is :comparator "i;octet" "${VAcaTION}" text:
+Dear Mr Coyote,
+I'm out, please leave a message after the meep.
+.
+ {
+ test_fail "failed to set variable correctly: ${VAcaTION}";
+ }
+}
+
+/*
+ * Variable substitution
+ */
+
+test "Multi-line string substitution" {
+ set "name" "Stephan Bosch";
+ set "address" "stephan@example.org";
+ set "subject" "Test message";
+
+ set "message" text: # Message with substitutions
+From: ${name} <${address}>
+To: Bertus van Asseldonk <b.vanasseldonk@nl.example.com>
+Subject: ${subject}
+
+This is a test message.
+.
+;
+ if not string :is "${message}" text:
+From: Stephan Bosch <stephan@example.org>
+To: Bertus van Asseldonk <b.vanasseldonk@nl.example.com>
+Subject: Test message
+
+This is a test message.
+.
+ {
+ test_fail "variable substitution failed";
+ }
+}
+
+test "Multiple substitutions" {
+ set "a" "the monkey";
+ set "b" "a nut";
+ set "c" "the fish";
+ set "d" "on fire";
+ set "e" "eats";
+ set "f" "is";
+
+ if not string :is "${a} ${e} ${b}" "the monkey eats a nut" {
+ test_fail "variable substitution failed (1)";
+ }
+
+ if not string :is "${c} ${f} ${d}" "the fish is on fire" {
+ test_fail "variable substitution failed (2)";
+ }
+
+ set :upperfirst "sentence" "${a} ${e} ${b}";
+
+ if not string :is "${sentence}" "The monkey eats a nut" {
+ test_fail "modified variable substitution failed";
+ }
+}
+
+
diff --git a/pigeonhole/tests/extensions/variables/errors.svtest b/pigeonhole/tests/extensions/variables/errors.svtest
new file mode 100644
index 0000000..652075f
--- /dev/null
+++ b/pigeonhole/tests/extensions/variables/errors.svtest
@@ -0,0 +1,34 @@
+require "vnd.dovecot.testsuite";
+
+require "comparator-i;ascii-numeric";
+require "relational";
+
+test "Invalid namespaces (FIXME: count only)" {
+ if test_script_compile "errors/namespace.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "5" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Invalid set command invocations (FIXME: count only)" {
+ if test_script_compile "errors/set.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "7" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Limits (FIXME: count only)" {
+ if test_script_compile "errors/limits.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "6" {
+ test_fail "wrong number of errors reported";
+ }
+}
diff --git a/pigeonhole/tests/extensions/variables/errors/limits.sieve b/pigeonhole/tests/extensions/variables/errors/limits.sieve
new file mode 100644
index 0000000..3c9dbbd
--- /dev/null
+++ b/pigeonhole/tests/extensions/variables/errors/limits.sieve
@@ -0,0 +1,287 @@
+require "variables";
+
+# Not an error (0)
+set "var123456789012345678901234567890" "value";
+
+# Exceed the maximum variable name length (1)
+set "var123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" "value";
+
+# Must yield unknown namespace error (no limit exceeded) (1)
+set "namespace.sub.sub.variable" "value";
+
+# Must yield unknown namespace error (exceeds element limit) (1)
+set "namespace.sub.sub.sub.variable" "value";
+
+# Not an error (0)
+if string "${32}" "value" {
+ stop;
+}
+
+# Exceed the maximum match value index (1)
+if string "${33}" "value" {
+ stop;
+}
+
+# Exceed the maximum number of declared variables (1!)
+set "var001" "value";
+set "var002" "value";
+set "var003" "value";
+set "var004" "value";
+set "var005" "value";
+set "var006" "value";
+set "var007" "value";
+set "var008" "value";
+set "var009" "value";
+set "var010" "value";
+set "var011" "value";
+set "var012" "value";
+set "var013" "value";
+set "var014" "value";
+set "var015" "value";
+set "var016" "value";
+set "var017" "value";
+set "var018" "value";
+set "var019" "value";
+set "var020" "value";
+set "var021" "value";
+set "var022" "value";
+set "var023" "value";
+set "var024" "value";
+set "var025" "value";
+set "var026" "value";
+set "var027" "value";
+set "var028" "value";
+set "var029" "value";
+set "var030" "value";
+set "var031" "value";
+set "var032" "value";
+set "var033" "value";
+set "var034" "value";
+set "var035" "value";
+set "var036" "value";
+set "var037" "value";
+set "var038" "value";
+set "var039" "value";
+set "var040" "value";
+set "var041" "value";
+set "var042" "value";
+set "var043" "value";
+set "var044" "value";
+set "var045" "value";
+set "var046" "value";
+set "var047" "value";
+set "var048" "value";
+set "var049" "value";
+set "var050" "value";
+set "var051" "value";
+set "var052" "value";
+set "var053" "value";
+set "var054" "value";
+set "var055" "value";
+set "var056" "value";
+set "var057" "value";
+set "var058" "value";
+set "var059" "value";
+set "var060" "value";
+set "var061" "value";
+set "var062" "value";
+set "var063" "value";
+set "var064" "value";
+set "var065" "value";
+set "var066" "value";
+set "var067" "value";
+set "var068" "value";
+set "var069" "value";
+set "var070" "value";
+set "var071" "value";
+set "var072" "value";
+set "var073" "value";
+set "var074" "value";
+set "var075" "value";
+set "var076" "value";
+set "var077" "value";
+set "var078" "value";
+set "var079" "value";
+set "var080" "value";
+set "var081" "value";
+set "var082" "value";
+set "var083" "value";
+set "var084" "value";
+set "var085" "value";
+set "var086" "value";
+set "var087" "value";
+set "var088" "value";
+set "var089" "value";
+set "var090" "value";
+set "var091" "value";
+set "var092" "value";
+set "var093" "value";
+set "var094" "value";
+set "var095" "value";
+set "var096" "value";
+set "var097" "value";
+set "var098" "value";
+set "var099" "value";
+
+set "var100" "value";
+set "var101" "value";
+set "var102" "value";
+set "var103" "value";
+set "var104" "value";
+set "var105" "value";
+set "var106" "value";
+set "var107" "value";
+set "var108" "value";
+set "var109" "value";
+set "var110" "value";
+set "var111" "value";
+set "var112" "value";
+set "var113" "value";
+set "var114" "value";
+set "var115" "value";
+set "var116" "value";
+set "var117" "value";
+set "var118" "value";
+set "var119" "value";
+set "var120" "value";
+set "var121" "value";
+set "var122" "value";
+set "var123" "value";
+set "var124" "value";
+set "var125" "value";
+set "var126" "value";
+set "var127" "value";
+set "var128" "value";
+set "var129" "value";
+set "var130" "value";
+set "var131" "value";
+set "var132" "value";
+set "var133" "value";
+set "var134" "value";
+set "var135" "value";
+set "var136" "value";
+set "var137" "value";
+set "var138" "value";
+set "var139" "value";
+set "var140" "value";
+set "var141" "value";
+set "var142" "value";
+set "var143" "value";
+set "var144" "value";
+set "var145" "value";
+set "var146" "value";
+set "var147" "value";
+set "var148" "value";
+set "var149" "value";
+set "var150" "value";
+set "var151" "value";
+set "var152" "value";
+set "var153" "value";
+set "var154" "value";
+set "var155" "value";
+set "var156" "value";
+set "var157" "value";
+set "var158" "value";
+set "var159" "value";
+set "var160" "value";
+set "var161" "value";
+set "var162" "value";
+set "var163" "value";
+set "var164" "value";
+set "var165" "value";
+set "var166" "value";
+set "var167" "value";
+set "var168" "value";
+set "var169" "value";
+set "var170" "value";
+set "var171" "value";
+set "var172" "value";
+set "var173" "value";
+set "var174" "value";
+set "var175" "value";
+set "var176" "value";
+set "var177" "value";
+set "var178" "value";
+set "var179" "value";
+set "var180" "value";
+set "var181" "value";
+set "var182" "value";
+set "var183" "value";
+set "var184" "value";
+set "var185" "value";
+set "var186" "value";
+set "var187" "value";
+set "var188" "value";
+set "var189" "value";
+set "var190" "value";
+set "var191" "value";
+set "var192" "value";
+set "var193" "value";
+set "var194" "value";
+set "var195" "value";
+set "var196" "value";
+set "var197" "value";
+set "var198" "value";
+set "var199" "value";
+set "var200" "value";
+
+set "var201" "value";
+set "var202" "value";
+set "var203" "value";
+set "var204" "value";
+set "var205" "value";
+set "var206" "value";
+set "var207" "value";
+set "var208" "value";
+set "var209" "value";
+set "var210" "value";
+set "var211" "value";
+set "var212" "value";
+set "var213" "value";
+set "var214" "value";
+set "var215" "value";
+set "var216" "value";
+set "var217" "value";
+set "var218" "value";
+set "var219" "value";
+set "var220" "value";
+set "var221" "value";
+set "var222" "value";
+set "var223" "value";
+set "var224" "value";
+set "var225" "value";
+set "var226" "value";
+set "var227" "value";
+set "var228" "value";
+set "var229" "value";
+set "var230" "value";
+set "var231" "value";
+set "var232" "value";
+set "var233" "value";
+set "var234" "value";
+set "var235" "value";
+set "var236" "value";
+set "var237" "value";
+set "var238" "value";
+set "var239" "value";
+set "var240" "value";
+set "var241" "value";
+set "var242" "value";
+set "var243" "value";
+set "var244" "value";
+set "var245" "value";
+set "var246" "value";
+set "var247" "value";
+set "var248" "value";
+set "var249" "value";
+set "var250" "value";
+set "var251" "value";
+set "var252" "value";
+set "var253" "value";
+set "var254" "value";
+set "var255" "value";
+set "var256" "value";
+set "var257" "value";
+set "var258" "value";
+set "var259" "value";
+set "var260" "value";
diff --git a/pigeonhole/tests/extensions/variables/errors/namespace.sieve b/pigeonhole/tests/extensions/variables/errors/namespace.sieve
new file mode 100644
index 0000000..e11ac6d
--- /dev/null
+++ b/pigeonhole/tests/extensions/variables/errors/namespace.sieve
@@ -0,0 +1,8 @@
+require "variables";
+require "fileinto";
+
+set "namespace.frop" "value";
+set "complex.struct.frop" "value";
+
+fileinto "${namespace.frop}";
+fileinto "${complex.struct.frop}";
diff --git a/pigeonhole/tests/extensions/variables/errors/set.sieve b/pigeonhole/tests/extensions/variables/errors/set.sieve
new file mode 100644
index 0000000..07c393a
--- /dev/null
+++ b/pigeonhole/tests/extensions/variables/errors/set.sieve
@@ -0,0 +1,19 @@
+require "variables";
+
+# Invalid variable name
+set "${frop}" "frop";
+set "...." "frop";
+set "name." "frop";
+set ".name" "frop";
+
+# Not an error
+set "\n\a\m\e" "frop";
+
+# Trying to assign match variable;
+set "0" "frop";
+
+# Not an error
+set :UPPER "name" "frop";
+
+# Invalid tag
+set :inner "name" "frop";
diff --git a/pigeonhole/tests/extensions/variables/limits.svtest b/pigeonhole/tests/extensions/variables/limits.svtest
new file mode 100644
index 0000000..7397713
--- /dev/null
+++ b/pigeonhole/tests/extensions/variables/limits.svtest
@@ -0,0 +1,435 @@
+require "vnd.dovecot.testsuite";
+require "variables";
+require "encoded-character";
+
+/*
+ * Variable size limit
+ */
+
+test_config_set "sieve_variables_max_variable_size" "4000";
+test_config_reload :extension "variables";
+
+set "a" text:
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+.
+;
+
+test "Variable size limit" {
+ set :length "alen" "${a}";
+
+ if not string "${alen}" "4000" {
+ test_fail "variable 'a' not 4000 bytes long (${alen}) [0]";
+ }
+
+ set "a" "${a}b";
+ set :length "alen" "${a}";
+
+ if not string "${alen}" "4000" {
+ test_fail "variable 'a' not 4000 bytes long (${alen}) [1]";
+ }
+
+ set "a" "${a}${a}";
+ set :length "alen" "${a}";
+
+ if not string "${alen}" "4000" {
+ test_fail "variable 'a' not 4000 bytes long (${alen}) [2]";
+ }
+
+ test_config_set "sieve_variables_max_variable_size" "8000";
+ test_config_reload :extension "variables";
+
+ set "a" "${a}${a}";
+ set :length "alen" "${a}";
+
+ if not string "${alen}" "8000" {
+ test_fail "variable 'a' not 8000 bytes long (${alen})";
+ }
+}
+
+/*
+ * Variable size limit UTF-8
+ */
+
+test_config_set "sieve_variables_max_variable_size" "4000";
+test_config_reload :extension "variables";
+
+set "b" text:
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+012345678901234567890123456789012345678901234567
+01234567890123456789012345678901234567890123456
+.
+;
+
+test "Variable size limit UTF-8" {
+ set :length "blen" "${b}";
+
+ if not string "${blen}" "3999" {
+ test_fail "variable 'b' not 3999 bytes long (${blen}) [0]";
+ }
+
+ set "b" "${b}${unicode:4e03}";
+ set :length "blen" "${b}";
+
+ if not string "${blen}" "3999" {
+ test_fail "variable 'b' not 3999 bytes long (${blen}) [1]";
+ }
+
+ set "b" "${b}ccc";
+ set :length "blen" "${b}";
+
+ if not string "${blen}" "4000" {
+ test_fail "variable 'b' not 4000 bytes long (${blen})";
+ }
+}
+
+/*
+ * :quotewildcard variable size limit
+ */
+
+test_config_set "sieve_variables_max_variable_size" "4000";
+test_config_reload :extension "variables";
+
+set "c" text:
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+**************************************
+.
+;
+
+test ":quotewildcard variable size limit" {
+ set :length "clen" "${c}";
+
+ if not string "${clen}" "4000" {
+ test_fail "variable 'c' not 4000 bytes long (${clen}) [0]";
+ }
+
+ set "d" "0${c}";
+ set :quotewildcard "c" "${c}";
+ set :length "clen" "${c}";
+
+ if not string "${clen}" "4000" {
+ test_fail "variable 'c' not 4000 bytes long (${clen}) [1]";
+ }
+
+ set :quotewildcard "d" "${d}";
+ set :length "dlen" "${d}";
+
+ if not string "${dlen}" "3999" {
+ test_fail "variable 'd' not 3999 bytes long (${dlen})";
+ }
+
+ if not string :is text:
+${d}
+.
+text:
+0\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
+\*\*\*\*\*\*\*\*\*\*
+.
+ {
+ test_fail "variable 'd' has unexpected value";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/variables/match.svtest b/pigeonhole/tests/extensions/variables/match.svtest
new file mode 100644
index 0000000..11c0701
--- /dev/null
+++ b/pigeonhole/tests/extensions/variables/match.svtest
@@ -0,0 +1,365 @@
+require "vnd.dovecot.testsuite";
+
+require "variables";
+
+/*
+ * RFC compliance
+ */
+
+# Test acceptance of leading zeroes
+test "RFC - leading zeroes" {
+ if not string :matches "frop:frup:frop" "*:*:*" {
+ test_fail "failed to match";
+ }
+
+ if not string :is "${0000002}" "frup" {
+ test_fail "incorrect match value (0000002): ${0000002}";
+ }
+}
+
+# Test non-greedyness
+test "RFC - not greedy" {
+ if not string :matches "frop.......frop.........frop...." "?*frop*" {
+ test_fail "failed to match";
+ }
+
+ if not string :is "${1}${2}${3}" "frop................frop...." {
+ test_fail "incorrect match values: ${1}${2}${3}";
+ }
+}
+
+# Index out of range
+test "RFC - index out of range" {
+ if not string :matches "test" "*" {
+ test_fail "failed to match (impossible)";
+ }
+
+ if not string :is "${2}" "" {
+ test_fail "incorrect match value: '${2}'";
+ }
+}
+
+# Index 0
+test "RFC - index 0" {
+ if not string :matches "a b c d e f g" "? ? ? ? ? ? ?" {
+ test_fail "failed to match";
+ }
+
+ if not string :is "${0}" "a b c d e f g" {
+ test_fail "incorrect match value: ${0}";
+ }
+}
+
+# Test short-circuit
+test "RFC - test short-circuit" {
+ if not anyof (
+ string :matches "a b c d e f g" "? ?",
+ string :matches "puk pok puk pok" "pu*ok",
+ string :matches "snot kip snot" "snot*snot"
+ ) {
+ test_fail "failed to match any";
+ }
+
+ if string :is "${1}" " kip " {
+ test_fail "did not short-circuit test execution or intented test failed.";
+ }
+
+ if not string :is "${1}" "k pok puk p" {
+ test_fail "incorrect match value: ${1}";
+ }
+}
+
+# Test overwriting only on match
+test "RFC - values overwrite" {
+ set "sentence1" "the cat jumps off the table";
+ set "sentence2" "the dog barks at the cat in the alley";
+
+ if not string :matches "${sentence1}" "the * jumps off the *" {
+ test_fail "failed to match first sentence";
+ }
+
+ if not string :is "${1}:${2}" "cat:table" {
+ test_fail "invalid match values";
+ }
+
+ if string :matches "${sentence2}" "the * barks at the * in the store" {
+ test_fail "should not have matched second sentence";
+ }
+
+ if not string :is "${1}:${2}" "cat:table" {
+ test_fail "should have preserved match values";
+ }
+
+ if not string :matches "${sentence2}" "the * barks at the * in the alley" {
+ test_fail "failed to match the second sentence (second time)";
+ }
+
+ if not string :is "${1}:${2}" "dog:cat" {
+ test_fail "should have overwritten match values";
+ }
+}
+
+test "RFC - example" {
+ test_set "message" text:
+Subject: [acme-users] [fwd] version 1.0 is out
+List-Id: Dovecot Mailing List <dovecot@dovecot.example.net>
+To: coyote@ACME.Example.COM
+Fom: stephan@example.org
+
+Test message.
+.
+;
+ if header :matches "List-ID" "*<*@*" {
+ if not string "INBOX.lists.${2}" "INBOX.lists.dovecot" {
+ test_fail "incorrect match value: INBOX.lists.${2}";
+ }
+ } else {
+ test_fail "failed to match list header";
+ }
+
+ # Imagine the header
+ # Subject: [acme-users] [fwd] version 1.0 is out
+ if header :matches "Subject" "[*] *" {
+ # ${1} will hold "acme-users",
+ # ${2} will hold "[fwd] version 1.0 is out"
+
+ if anyof (
+ not string "${1}" "acme-users",
+ not string "${2}" "[fwd] version 1.0 is out"
+ ) {
+ test_fail "invalid match values: ${1} ${2}";
+ }
+ } else {
+ test_fail "failed to match subject";
+ }
+
+ # Imagine the header
+ # To: coyote@ACME.Example.COM
+ if address :matches ["To", "Cc"] ["coyote@**.com",
+ "wile@**.com"] {
+ # ${0} is the matching address
+ # ${1} is always the empty string
+ # ${2} is part of the domain name ("ACME.Example")
+
+ if anyof (
+ not string "${0}" "coyote@ACME.Example.COM",
+ not string "${1}" "",
+ not string "${2}" "ACME.Example"
+ ) {
+ test_fail "invalid match values: ${0}, ${1}, ${2}";
+ }
+ } else {
+ # Control wouldn't reach this block if any match was
+ # successful, so no match variables are set at this
+ # point.
+
+ test_fail "failed to match to address";
+ }
+
+ if anyof (true, address :domain :matches "To" "*.com") {
+ # The second test is never evaluated, so there are
+ # still no match variables set.
+
+ /* FIXME: not compliant */
+ }
+}
+
+/*
+ * Generic tests
+ */
+
+set "match1" "Test of general stupidity";
+
+test "Begin" {
+ if not string :matches "${match1}" "Test of *" {
+ test_fail "should have matched";
+ }
+
+ if not string :is "${1}" "general stupidity" {
+ test_fail "match value incorrect";
+ }
+}
+
+test "Begin no match" {
+ if string :matches "${match1}" "of *" {
+ test_fail "should not have matched";
+ }
+}
+
+set "match2" "toptoptop";
+
+test "End" {
+ if not string :matches "${match2}" "*top" {
+ test_fail "should have matched";
+ }
+
+ if not string :is "${1}" "toptop" {
+ test_fail "match value incorrect";
+ }
+}
+
+set "match3" "ik ben een tukker met grote oren en een lelijke broek.";
+
+test "Multiple" {
+ if not string :matches "${match3}" "ik ben * met * en *." {
+ test_fail "should have matched";
+ }
+
+ set "line" "Hij is ${1} met ${2} en ${3}!";
+
+ if not string :is "${line}"
+ "Hij is een tukker met grote oren en een lelijke broek!" {
+ test_fail "match values incorrect: ${line}";
+ }
+}
+
+set "match4" "beter van niet?";
+
+test "Escape" {
+ if not string :matches "${match4}" "*\\?" {
+ test_fail "should have matched";
+ }
+
+ if not string :is "${1}" "beter van niet" {
+ test_fail "match value incorrect: ${1}";
+ }
+}
+
+set "match5" "The quick brown fox jumps over the lazy dog.";
+
+test "Alphabet ?" {
+ if not string :matches "${match5}" "T?? ????? ????? ?o? ?u??? o?er ?he ???? ?o?." {
+ test_fail "should have matched";
+ }
+
+ set "alphabet" "${22}${8}${6}${25}${2}${13}${26}${1}${5}${15}${7}${21}${16}${12}${10}${17}${3}${9}${18}${20}${4}${19}${11}${14}${24}${23}";
+
+ if not string :is "${alphabet}" "abcdefghijklmnopqrstuvwxyz" {
+ test_fail "match values incorrect: ${alphabet}";
+ }
+
+ if string :matches "${match5}" "T?? ????? ?w??? ?o? ?u??? o?er ?he ???? ?o?." {
+ test_fail "should not have matched";
+ }
+}
+
+set "match6" "zero:one:zero|three;one;zero/five";
+
+test "Words sep ?" {
+
+ if not string :matches "${match6}" "*one?zero?five" {
+ test_fail "should have matched";
+ }
+
+ if not string :is "${1}${2}${3}" "zero:one:zero|three;;/" {
+ test_fail "incorrect match values: ${1} ${2} ${3}";
+ }
+}
+
+set "match7" "frop";
+
+test "Letters begin ?" {
+ if not string :matches "${match7}" "??op" {
+ test_fail "should have matched";
+ }
+
+ set "val" "${0}:${1}:${2}:${3}:";
+
+ if not string :is "${val}" "frop:f:r::" {
+ test_fail "incorrect match values: ${val}";
+ }
+}
+
+test "Letters end ?" {
+ if not string :matches "${match7}" "fr??" {
+ test_fail "should have matched";
+ }
+
+ set "val" "${0}:${1}:${2}:${3}:";
+
+ if not string :is "${val}" "frop:o:p::" {
+ test_fail "incorrect match values: ${val}";
+ }
+}
+
+set "match8" "klopfropstroptop";
+
+test "Letters words *? - 1" {
+ if not string :matches "${match8}" "*fr??*top" {
+ test_fail "should have matched";
+ }
+
+ set "val" ":${0}:${1}:${2}:${3}:${4}:${5}:";
+
+ if not string :is "${val}" ":klopfropstroptop:klop:o:p:strop::" {
+ test_fail "incorrect match values: ${val}";
+ }
+}
+
+test "Letters words *? - 2" {
+ if not string :matches "${match8}" "?*fr??*top" {
+ test_fail "should have matched";
+ }
+
+ set "val" ":${0}:${1}:${2}:${3}:${4}:${5}:${6}:";
+
+ if not string :is "${val}" ":klopfropstroptop:k:lop:o:p:strop::" {
+ test_fail "incorrect match values: ${val}";
+ }
+}
+
+test "Letters words *? backtrack" {
+ if not string :matches "${match8}" "*?op" {
+ test_fail "should have matched";
+ }
+
+ set "val" ":${0}:${1}:${2}:${3}:${4}:";
+
+ if not string :is "${val}" ":klopfropstroptop:klopfropstrop:t:::" {
+ test_fail "incorrect match values: ${val}";
+ }
+}
+
+test "Letters words *? first" {
+ if not string :matches "${match8}" "*?op*" {
+ test_fail "failed to match";
+ }
+
+ set "val" ":${0}:${1}:${2}:${3}:${4}:";
+
+ if not string :is "${val}" ":klopfropstroptop:k:l:fropstroptop::" {
+ test_fail "incorrect match values: ${val}";
+ }
+}
+
+/*
+ * Specific tests
+ */
+
+test_set "message" text:
+Return-path: <stephan@xi.example.org>
+Envelope-to: stephan@xi.example.org
+Delivery-date: Sun, 01 Feb 2009 11:29:57 +0100
+Received: from stephan by xi.example.org with local (Exim 4.69)
+ (envelope-from <stephan@xi.example.org>)
+ id 1LTZaP-0007h3-2e
+ for stephan@xi.example.org; Sun, 01 Feb 2009 11:29:57 +0100
+From: Dovecot Debian Builder <stephan.example.org@xi.example.org>
+To: stephan@xi.example.org
+Subject: Log for failed build of dovecot_2:1.2.alpha5-0~auto+159 (dist=hardy)
+Message-Id: <E1LTZaP-0007h3-2e@xi.example.org>
+Date: Sun, 01 Feb 2009 11:29:57 +0100
+
+Automatic build of dovecot_1.2.alpha5-0~auto+159 on xi by sbuild/i386 0.57.7
+.
+;
+
+test "Match combined" {
+ if not header :matches "subject" "Log for ?* build of *" {
+ test_fail "failed to match";
+ }
+
+ if not string "${1}${2}" "failed" {
+ test_fail "incorrect match values: ${1}${2}";
+ }
+}
diff --git a/pigeonhole/tests/extensions/variables/modifiers.svtest b/pigeonhole/tests/extensions/variables/modifiers.svtest
new file mode 100644
index 0000000..37068b6
--- /dev/null
+++ b/pigeonhole/tests/extensions/variables/modifiers.svtest
@@ -0,0 +1,160 @@
+require "vnd.dovecot.testsuite";
+require "variables";
+require "encoded-character";
+
+/*
+ * Modifiers
+ */
+
+test "Modifier :lower" {
+ set :lower "test" "VaLuE";
+
+ if not string :is "${test}" "value" {
+ test_fail "modified variable assignment failed";
+ }
+}
+
+test "Modifiers :lower :upperfirst" {
+ set :lower :upperfirst "test" "vAlUe";
+
+ if string :is "${test}" "value" {
+ test_fail "modifiers applied with wrong precedence";
+ }
+
+ if not string :is "${test}" "Value" {
+ test_fail "modified variable assignment failed";
+ }
+}
+
+test "Modifiers :upperfirst :lower" {
+ set :upperfirst :lower "test" "vAlUe";
+
+ if string :is "${test}" "value" {
+ test_fail "modifiers applied with wrong precedence";
+ }
+
+ if not string :is "${test}" "Value" {
+ test_fail "modified variable assignment failed";
+ }
+}
+
+test "Modifier :upper" {
+ set :upper "test" "vAlUe";
+
+ if not string :is "${test}" "VALUE" {
+ test_fail "modified variable assignment failed";
+ }
+}
+
+test "Modifiers :upper :lowerfirst" {
+ set :upper :lowerfirst "test" "VaLuE";
+
+ if string :is "${test}" "VALUE" {
+ test_fail "modifiers applied with wrong precedence";
+ }
+
+ if not string :is "${test}" "vALUE" {
+ test_fail "modified variable assignment failed";
+ }
+}
+
+test "Modifiers :lowerfirst :upper" {
+ set :lowerfirst :upper "test" "VaLuE";
+
+ if string :is "${test}" "VALUE" {
+ test_fail "modifiers applied with wrong precedence";
+ }
+
+ if not string :is "${test}" "vALUE" {
+ test_fail "modified variable assignment failed";
+ }
+}
+
+test "Modifier :length (empty)" {
+ set :length "test" "";
+
+ if not string :is "${test}" "0" {
+ test_fail "modified variable assignment failed";
+ }
+}
+
+test "Modifier :length (simple)" {
+ set :length "test" "VaLuE";
+
+ if not string :is "${test}" "5" {
+ test_fail "modified variable assignment failed";
+ }
+}
+
+test "Modifier :length (elaborate)" {
+ set "a" "abcdefghijklmnopqrstuvwxyz";
+ set "b" "1234567890";
+ set :length "test" " ${a}:${b} ";
+
+ if not string :is "${test}" "40" {
+ test_fail "modified variable assignment failed";
+ }
+}
+
+test "Modifier :quotewildcard" {
+ set :quotewildcard "test" "^^***??**^^";
+
+ if not string :is "${test}" "^^\\*\\*\\*\\?\\?\\*\\*^^" {
+ test_fail "modified variable assignment failed";
+ }
+}
+
+test "Modifier :length :quotewildcard" {
+ set :length :quotewildcard "test" "^^***??**^^";
+
+ if string :is "${test}" "11" {
+ test_fail "modifiers applied with wrong precedence";
+ }
+
+ if not string :is "${test}" "18" {
+ test_fail "modified variable assignment failed";
+ }
+}
+
+test "RFC examples" {
+ set "a" "juMBlEd lETteRS"; # => "juMBlEd lETteRS"
+ if not string "${a}" "juMBlEd lETteRS" {
+ test_fail "modified assignment failed (1): ${a}";
+ }
+
+ set :length "b" "${a}"; # => "15"
+ if not string "${b}" "15" {
+ test_fail "modified assignment failed (2): ${a}";
+ }
+
+ set :lower "b" "${a}"; # => "jumbled letters"
+ if not string "${b}" "jumbled letters" {
+ test_fail "modified assignment failed (3): ${a}";
+ }
+
+ set :upperfirst "b" "${a}"; # => "JuMBlEd lETteRS"
+ if not string "${b}" "JuMBlEd lETteRS" {
+ test_fail "modified assignment failed (4): ${a}";
+ }
+
+ set :upperfirst :lower "b" "${a}"; # => "Jumbled letters"
+ if not string "${b}" "Jumbled letters" {
+ test_fail "modified assignment failed (5): ${a}";
+ }
+
+ set :quotewildcard "b" "Rock*"; # => "Rock\*"
+ if not string "${b}" "Rock\\*" {
+ test_fail "modified assignment failed (6): ${a}";
+ }
+}
+
+/* RFC mentions `characters' and not octets */
+
+test "Modifier :length utf8" {
+ set "a" "Das ist ${unicode: 00fc}berhaupt nicht m${unicode: 00f6}glich.";
+
+ set :length "b" "${a}";
+ if not string "${b}" "32" {
+ test_fail "incorrect number of unicode characters reported: ${b}/32";
+ }
+}
diff --git a/pigeonhole/tests/extensions/variables/quoting.svtest b/pigeonhole/tests/extensions/variables/quoting.svtest
new file mode 100644
index 0000000..f65e4e4
--- /dev/null
+++ b/pigeonhole/tests/extensions/variables/quoting.svtest
@@ -0,0 +1,36 @@
+require "vnd.dovecot.testsuite";
+
+require "variables";
+require "encoded-character";
+
+test "Encodings - RFC examples" {
+ set "s" "$";
+ set "foo" "bar";
+
+ # "${fo\o}" => ${foo} => the expansion of variable foo.
+ if not string :is "${fo\o}" "bar" {
+ test_fail "failed 'the expansion of variable foo (${s}{fo\\o})'";
+ }
+
+ # "${fo\\o}" => ${fo\o} => illegal identifier => left verbatim.
+ if not string :is "${fo\\o}" "${s}{fo\\o}" {
+ test_fail "failed 'illegal identifier => left verbatim'";
+ }
+
+ # "\${foo}" => ${foo} => the expansion of variable foo.
+ if not string "\${foo}" "bar" {
+ test_fail "failed 'the expansion of variable foo (\\${s}{foo})'";
+ }
+
+ # "\\${foo}" => \${foo} => a backslash character followed by the
+ # expansion of variable foo.
+ if not string "\\${foo}" "\\bar" {
+ test_fail "failed 'a backslash character followed by expansion of variable foo";
+ }
+
+ set "name" "Ethelbert";
+ if not string "dear${hex:20 24 7b 4e}ame}" "dear Ethelbert" {
+ test_fail "failed 'dear Ethelbert' example";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/variables/regex.svtest b/pigeonhole/tests/extensions/variables/regex.svtest
new file mode 100644
index 0000000..04ca00d
--- /dev/null
+++ b/pigeonhole/tests/extensions/variables/regex.svtest
@@ -0,0 +1,35 @@
+require "vnd.dovecot.testsuite";
+
+require "regex";
+require "variables";
+
+# Test overwriting only on match
+test "RFC - values overwrite" {
+ set "sentence1" "the cat jumps off the table";
+ set "sentence2" "the dog barks at the cat in the alley";
+
+ if not string :regex "${sentence1}" "the (.*) jumps off the (.*)" {
+ test_fail "failed to match first sentence";
+ }
+
+ if not string :is "${1}:${2}" "cat:table" {
+ test_fail "invalid match values";
+ }
+
+ if string :regex "${sentence2}" "the (.*) barks at the (.*) in the store" {
+ test_fail "should not have matched second sentence";
+ }
+
+ if not string :is "${1}:${2}" "cat:table" {
+ test_fail "should have preserved match values";
+ }
+
+ if not string :regex "${sentence2}" "the (.*) barks at the (.*) in the alley" {
+ test_fail "failed to match the second sentence (second time)";
+ }
+
+ if not string :is "${1}:${2}" "dog:cat" {
+ test_fail "should have overwritten match values";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/variables/string.svtest b/pigeonhole/tests/extensions/variables/string.svtest
new file mode 100644
index 0000000..d0244e6
--- /dev/null
+++ b/pigeonhole/tests/extensions/variables/string.svtest
@@ -0,0 +1,37 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+require "variables";
+
+test "String - :count" {
+ if not string :count "eq" :comparator "i;ascii-numeric" ["a", "b", "c"] "3" {
+ test_fail "string test failed :count match";
+ }
+}
+
+test "String - :count \"\"" {
+ if not string :count "eq" :comparator "i;ascii-numeric" ["a", "", "c"] "2" {
+ test_fail "string test failed :count match";
+ }
+}
+
+test "RFC example" {
+ set "state" "${state} pending";
+
+ if not string :matches " ${state} " "* pending *" {
+ # the above test always succeeds
+
+ test_fail "test should have matched: \" ${state} \"";
+ }
+}
+
+test "No whitespace stripping" {
+ set "vara" " value ";
+ set "varb" "value";
+
+ if not string :is :comparator "i;octet" "${vara}" " ${varb} " {
+ test_fail "string test seems to have stripped white space";
+ }
+}
diff --git a/pigeonhole/tests/extensions/vnd.dovecot/debug/execute.svtest b/pigeonhole/tests/extensions/vnd.dovecot/debug/execute.svtest
new file mode 100644
index 0000000..6d67024
--- /dev/null
+++ b/pigeonhole/tests/extensions/vnd.dovecot/debug/execute.svtest
@@ -0,0 +1,6 @@
+require "vnd.dovecot.testsuite";
+require "vnd.dovecot.debug";
+
+test "Basic" {
+ debug_log "logging basic message.";
+}
diff --git a/pigeonhole/tests/extensions/vnd.dovecot/environment/basic.svtest b/pigeonhole/tests/extensions/vnd.dovecot/environment/basic.svtest
new file mode 100644
index 0000000..c58bbc0
--- /dev/null
+++ b/pigeonhole/tests/extensions/vnd.dovecot/environment/basic.svtest
@@ -0,0 +1,29 @@
+require "vnd.dovecot.testsuite";
+require "vnd.dovecot.environment";
+require "variables";
+
+test "default-mailbox" {
+ if not environment :is "vnd.dovecot.default-mailbox" "INBOX" {
+ if environment :matches "vnd.dovecot.default-mailbox" "*" { set "env" "${1}"; }
+
+ test_fail "vnd.dovecot.default-mailbox environment returned invalid value(1): `${env}'";
+ }
+}
+
+test "username" {
+ if not environment :contains "vnd.dovecot.username" "" {
+ test_fail "vnd.dovecot.username environment does not exist";
+ }
+}
+
+test_config_set "sieve_env_display_name" "Jan Jansen";
+test_config_reload :extension "vnd.dovecot.environment";
+
+test "config" {
+ if not environment :contains "vnd.dovecot.config.display_name" "" {
+ test_fail "vnd.dovecot.config.display_name environment does not exist";
+ }
+ if not environment :is "vnd.dovecot.config.display_name" "Jan Jansen" {
+ test_fail "vnd.dovecot.config.display_name environment has wrong value";
+ }
+}
diff --git a/pigeonhole/tests/extensions/vnd.dovecot/environment/variables.svtest b/pigeonhole/tests/extensions/vnd.dovecot/environment/variables.svtest
new file mode 100644
index 0000000..886e75e
--- /dev/null
+++ b/pigeonhole/tests/extensions/vnd.dovecot/environment/variables.svtest
@@ -0,0 +1,18 @@
+require "vnd.dovecot.testsuite";
+require "vnd.dovecot.environment";
+require "variables";
+require "relational";
+
+test "default_mailbox" {
+ if not string "${env.vnd.dovecot.default_mailbox}" "INBOX" {
+ test_fail "The env.vnd.dovecot.default_mailbox variable returned invalid value: `${env.vnd.dovecot.default_mailbox}'";
+ }
+}
+
+test "username" {
+ set :length "userlen" "${env.vnd.dovecot.username}";
+ if not string :value "ge" "${userlen}" "1" {
+ test_fail "The env.vnd.dovecot.username variable is empty or does not exist";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/vnd.dovecot/report/errors.svtest b/pigeonhole/tests/extensions/vnd.dovecot/report/errors.svtest
new file mode 100644
index 0000000..82ab992
--- /dev/null
+++ b/pigeonhole/tests/extensions/vnd.dovecot/report/errors.svtest
@@ -0,0 +1,13 @@
+require "vnd.dovecot.testsuite";
+require "comparator-i;ascii-numeric";
+require "relational";
+
+test "Invalid syntax (FIXME: count only)" {
+ if test_script_compile "errors/syntax.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "9" {
+ test_fail "wrong number of errors reported";
+ }
+}
diff --git a/pigeonhole/tests/extensions/vnd.dovecot/report/errors/syntax.sieve b/pigeonhole/tests/extensions/vnd.dovecot/report/errors/syntax.sieve
new file mode 100644
index 0000000..250ad60
--- /dev/null
+++ b/pigeonhole/tests/extensions/vnd.dovecot/report/errors/syntax.sieve
@@ -0,0 +1,28 @@
+require "vnd.dovecot.report";
+
+# 1: Too few arguments
+report;
+
+# 2: Too few arguments
+report "abuse";
+
+# 3: Too few arguments
+report "abuse" "Message is spam.";
+
+# Not an error
+report "abuse" "Message is spam." "frop@example.com";
+
+# 4: Bad arguments
+report "abuse" "Message is spam." 1;
+
+# 5: Bad tag
+report :frop "abuse" "Message is spam." "frop@example.com";
+
+# 6: Bad sub-test
+report "abuse" "Message is spam." "frop@example.com" frop;
+
+# 7: Bad block
+report "abuse" "Message is spam." "frop@example.com" { }
+
+# 8: Bad feedback type
+report "?????" "Message is spam." "frop@example.com";
diff --git a/pigeonhole/tests/extensions/vnd.dovecot/report/execute.svtest b/pigeonhole/tests/extensions/vnd.dovecot/report/execute.svtest
new file mode 100644
index 0000000..11a8079
--- /dev/null
+++ b/pigeonhole/tests/extensions/vnd.dovecot/report/execute.svtest
@@ -0,0 +1,269 @@
+require "vnd.dovecot.testsuite";
+require "vnd.dovecot.report";
+require "relational";
+require "comparator-i;ascii-numeric";
+require "body";
+require "variables";
+
+/*
+ * Simple test
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "Simple" {
+ report "abuse" "This message is spam!" "abuse@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not body :raw :contains "This message is spam!" {
+ test_fail "report does not contain user text";
+ }
+
+ if not body :raw :contains "Klutsefluts" {
+ test_fail "report does not contain message body";
+ }
+}
+
+/*
+ * Simple - :headers_only test
+ */
+
+test_result_reset;
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test "Simple - :headers_only" {
+ report :headers_only "abuse"
+ "This message is spam!" "abuse@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not body :raw :contains "This message is spam!" {
+ test_fail "report does not contain user text";
+ }
+
+ if body :raw :contains "Klutsefluts" {
+ test_fail "report contains message body";
+ }
+}
+
+/*
+ * Configuration
+ */
+
+set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+/* default */
+
+test_set "message" "${message}";
+test_set "envelope.from" "from@example.com";
+test_set "envelope.to" "to@example.com";
+test_set "envelope.orig_to" "orig_to@example.com";
+
+test_result_reset;
+
+test "Configuration - from default" {
+ report "abuse" "This message is spam!" "abuse@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not address :localpart "from" "postmaster" {
+ test_fail "not sent from postmaster";
+ }
+}
+
+/* from sender */
+
+test_set "message" "${message}";
+test_set "envelope.from" "from@example.com";
+test_set "envelope.to" "to@example.com";
+test_set "envelope.orig_to" "orig_to@example.com";
+
+test_config_set "sieve_report_from" "sender";
+test_config_reload :extension "vnd.dovecot.report";
+test_result_reset;
+
+test "Configuration - from sender" {
+ report "abuse" "This message is spam!" "abuse@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not address :localpart "from" "from" {
+ test_fail "not sent from sender";
+ }
+}
+
+/* from recipient */
+
+test_set "message" "${message}";
+test_set "envelope.from" "from@example.com";
+test_set "envelope.to" "to@example.com";
+test_set "envelope.orig_to" "orig_to@example.com";
+
+test_config_set "sieve_report_from" "recipient";
+test_config_reload :extension "vnd.dovecot.report";
+test_result_reset;
+
+test "Configuration - from recipient" {
+ report "abuse" "This message is spam!" "abuse@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not address :localpart "from" "to" {
+ test_fail "not sent from recipient";
+ }
+}
+
+/* from original recipient */
+
+test_set "message" "${message}";
+test_set "envelope.from" "from@example.com";
+test_set "envelope.to" "to@example.com";
+test_set "envelope.orig_to" "orig_to@example.com";
+
+test_config_set "sieve_report_from" "orig_recipient";
+test_config_reload :extension "vnd.dovecot.report";
+test_result_reset;
+
+test "Configuration - from original recipient" {
+ report "abuse" "This message is spam!" "abuse@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not address :localpart "from" "orig_to" {
+ test_fail "not sent from original recipient";
+ }
+}
+
+/* from user email */
+
+test_set "message" "${message}";
+test_set "envelope.from" "from@example.com";
+test_set "envelope.to" "to@example.com";
+test_set "envelope.orig_to" "orig_to@example.com";
+
+test_config_set "sieve_report_from" "user_email";
+test_config_set "sieve_user_email" "user@example.com";
+test_config_reload;
+test_config_reload :extension "vnd.dovecot.report";
+test_result_reset;
+
+test "Configuration - from user email" {
+ report "abuse" "This message is spam!" "abuse@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not address :localpart "from" "user" {
+ test_fail "not sent from user email";
+ }
+}
+
+/* explicit */
+
+test_set "message" "${message}";
+test_set "envelope.from" "from@example.com";
+test_set "envelope.to" "to@example.com";
+test_set "envelope.orig_to" "orig_to@example.com";
+
+test_config_set "sieve_report_from" "<frop@example.com>";
+test_config_reload :extension "vnd.dovecot.report";
+test_result_reset;
+
+test "Configuration - explicit" {
+ report "abuse" "This message is spam!" "abuse@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not address :localpart "from" "frop" {
+ test_fail "not sent from explicit address";
+ }
+}
+
+/*
+ * Reporting-User
+ */
+
+/* sieve_user_email */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test_set "envelope.orig_to" "orig_to@example.com";
+
+test_config_set "sieve_user_email" "newuser@example.com";
+test_config_reload;
+test_result_reset;
+
+test "Reporting-User - sieve_user_email" {
+ report "abuse" "This message is spam!" "abuse@example.com";
+
+ if not test_result_execute {
+ test_fail "failed to execute notify";
+ }
+
+ test_message :smtp 0;
+
+ if not body :raw :contains "Dovecot-Reporting-User: <newuser@example.com>" {
+ test_fail "Reporting-User field is wrong.";
+ }
+} \ No newline at end of file
diff --git a/pigeonhole/tests/failures/fuzz1.svtest b/pigeonhole/tests/failures/fuzz1.svtest
new file mode 100644
index 0000000..a6fe086
--- /dev/null
+++ b/pigeonhole/tests/failures/fuzz1.svtest
@@ -0,0 +1,33 @@
+# Used to cause the test suite to segfault
+
+require "vnd.dovecot.testsuite";
+require "fileinto";
+require "imap4flags";
+require "mailbox";
+
+
+test_set "message" text:
+Subject: Test message.
+
+Test message.
+.
+;
+
+test "Flag changes between stores" {
+ fileinto :create "FolderA";
+
+ if not test_result_execute {
+ test_fail "failed to execute first result";
+ }
+
+ test_message :folder "FolderA" 0;
+
+ test_result_reset;
+
+ test_message :folder "Uninteiesting" 0;
+
+ if not hasflag "$label1" {
+ test_fail "flags not stored for fired for third message";
+ }
+
+}
diff --git a/pigeonhole/tests/failures/fuzz2.svtest b/pigeonhole/tests/failures/fuzz2.svtest
new file mode 100644
index 0000000..9fa63ea
--- /dev/null
+++ b/pigeonhole/tests/failures/fuzz2.svtest
@@ -0,0 +1,37 @@
+require "vnd.dovecot.testsuite";
+require "fileinto";
+require "variables";
+require "mailbox";
+
+set "message" text:
+From:.org
+To:rg
+Subject: First message
+
+Frop
+.
+;
+
+
+test "sometest" {
+ test_set "message" "${message}";
+
+ fileinto :create "Folder";
+
+ if not test_result_execute {
+ test_fail "";
+ }
+
+ test_message :folder "Folder" 0;
+
+ if not header "subject" "First message" {
+ test_fail "";
+ }
+
+ test_message :folder " .Folder" 1;
+
+ if not header "subject" "Second message" {
+ test_fail "";
+ }
+
+}
diff --git a/pigeonhole/tests/failures/fuzz3.svtest b/pigeonhole/tests/failures/fuzz3.svtest
new file mode 100644
index 0000000..c1c22dc
--- /dev/null
+++ b/pigeonhole/tests/failures/fuzz3.svtest
@@ -0,0 +1,12 @@
+require "vnd.dovecot.testsuite";
+require "fileinto";
+require "mailbox";
+
+test"" {
+ fileinto :create "Folder";
+
+ if test_result_execute {
+ }
+
+ test_message :folder "Folder" 2;
+}
diff --git a/pigeonhole/tests/failures/mailbox-bad-utf8.svtest b/pigeonhole/tests/failures/mailbox-bad-utf8.svtest
new file mode 100644
index 0000000..ad104e5
--- /dev/null
+++ b/pigeonhole/tests/failures/mailbox-bad-utf8.svtest
@@ -0,0 +1,6 @@
+require "vnd.dovecot.testsuite";
+require "encoded-character";
+
+test "Mailbox parameter with bad UTF-8" {
+ test_message :folder "I${hex:9b}BOX" 0;
+}
diff --git a/pigeonhole/tests/lexer.svtest b/pigeonhole/tests/lexer.svtest
new file mode 100644
index 0000000..491309d
--- /dev/null
+++ b/pigeonhole/tests/lexer.svtest
@@ -0,0 +1,39 @@
+require "vnd.dovecot.testsuite";
+require "variables";
+
+/* Test conformance to RFC 5228 - 2.4.2. Strings */
+
+set "text" text: # Comment
+Line 1
+.Line 2
+..Line 3
+.Line 4
+Line 5
+.
+;
+
+set "quoted"
+"Line 1
+.Line 2
+.Line 3
+.Line 4
+Line 5
+";
+
+test "String Literal" {
+ if not string :is "${text}" "${quoted}" {
+ test_fail "lexer messed-up dot stuffing";
+ }
+
+ if string :is "${text}" "" {
+ test_fail "variable substitution failed";
+ }
+}
+
+test "Unknown Escapes" {
+ if not string :is "\a\a\a\a\a" "aaaaa" {
+ test_fail "unknown quoted string escape sequences are handled inappropriately";
+ }
+}
+
+
diff --git a/pigeonhole/tests/match-types/contains.svtest b/pigeonhole/tests/match-types/contains.svtest
new file mode 100644
index 0000000..710afca
--- /dev/null
+++ b/pigeonhole/tests/match-types/contains.svtest
@@ -0,0 +1,81 @@
+require "vnd.dovecot.testsuite";
+
+test_set "message" text:
+From: stephan@example.org
+Cc: frop@example.com
+To: test@dovecot.example.net
+X-Bullshit: f fr fro frop frob frobn frobnitzn
+Subject: Test Message
+Comment:
+
+Test!
+.
+;
+
+# Match tests
+
+test "Match empty" {
+ if not header :contains "x-bullshit" "" {
+ test_fail "contains tests fails to match \"\" against non-empty string";
+ }
+
+ if not header :contains "comment" "" {
+ test_fail "contains tests fails to match \"\" against empty string";
+ }
+}
+
+test "Match full" {
+ if not address :contains "from" "stephan@example.org" {
+ test_fail "should have matched";
+ }
+}
+
+test "Match begin" {
+ if not address :contains "from" "stephan" {
+ test_fail "should have matched";
+ }
+}
+
+test "Match end" {
+ if not address :contains "from" "example.org" {
+ test_fail "should have matched";
+ }
+}
+
+test "Match middle" {
+ if not address :contains "from" "@" {
+ test_fail "should have matched";
+ }
+}
+
+test "Match similar beginnings" {
+ if not header :contains "x-bullshit" "frobnitzn" {
+ test_fail "should have matched";
+ }
+}
+
+test "Match case-insensitive" {
+ if not address :contains :comparator "i;ascii-casemap" "from" "EXAMPLE" {
+ test_fail "match fails to apply correct comparator";
+ }
+
+ if not address :contains "from" "EXAMPLE" {
+ test_fail "default comparator is wrong";
+ }
+}
+
+# Non-match tests
+
+test "No match full (typo)" {
+ if address :contains "to" "frob@example.com" {
+ test_fail "should not have matched";
+ }
+}
+
+test "No match end (typo)" {
+ if header :contains "x-bullshit" "frobnitzm" {
+ test_fail "should not have matched";
+ }
+}
+
+
diff --git a/pigeonhole/tests/match-types/is.svtest b/pigeonhole/tests/match-types/is.svtest
new file mode 100644
index 0000000..c715db8
--- /dev/null
+++ b/pigeonhole/tests/match-types/is.svtest
@@ -0,0 +1,22 @@
+require "vnd.dovecot.testsuite";
+
+test_set "message" text:
+From: Stephan Bosch <stephan@example.org>
+To: nico@frop.example.org
+Subject: Test message
+Comment:
+
+Test!
+
+.
+;
+
+test "Empty key" {
+ if header :is "from" "" {
+ test_fail "erroneously matched empty key against non-empty string";
+ }
+
+ if not header :is "comment" "" {
+ test_fail "failed to match empty string";
+ }
+}
diff --git a/pigeonhole/tests/match-types/matches.svtest b/pigeonhole/tests/match-types/matches.svtest
new file mode 100644
index 0000000..bcc188d
--- /dev/null
+++ b/pigeonhole/tests/match-types/matches.svtest
@@ -0,0 +1,241 @@
+require "vnd.dovecot.testsuite";
+
+test_set "message" text:
+From: stephan+sieve@friep.example.com
+To: sirius@example.org
+To: nico@frop.example.org
+Cc: me@example.com
+Cc: timo@dovecot.example.com
+X-Hufter: TRUE
+Subject: make your money very fast!!!
+X-Spam-Score: **********
+X-Bullshit: 33333???a
+Message-ID: <90a02fe01fc25e131d0e9c4c45975894@example.com>
+Comment:
+X-Subject: Log for successful build of Dovecot.
+
+Het werkt!
+.
+;
+
+/*
+ * General conformance testing
+ */
+
+test "Empty string" {
+ if not header :matches "comment" "" {
+ test_fail "failed to match \"\" against \"\"";
+ }
+
+ if not header :matches "comment" "*" {
+ test_fail "failed to match \"\" against \"*\"";
+ }
+
+ if header :matches "comment" "?" {
+ test_fail "inappropriately matched \"\" against \"?\"";
+ }
+}
+
+test "Multiple '*'" {
+ if not address :matches "from" "*@fri*p*examp*.com" {
+ test_fail "should have matched";
+ }
+
+ if address :matches "from" "*@f*pex*mple.com" {
+ test_fail "should not have matched";
+ }
+}
+
+test "End '*'" {
+ if not address :matches "from" "stephan+sieve@friep.*" {
+ test_fail "should have matched";
+ }
+
+ if address :matches "from" "stepan+sieve@friep.*" {
+ test_fail "should not have matched";
+ }
+}
+
+test "Begin '*'" {
+ if not address :matches "from" "*+sieve@friep.example.com" {
+ test_fail "should have matched";
+ }
+
+ if address :matches "from" "*+sieve@friep.example.om" {
+ test_fail "should not have matched";
+ }
+}
+
+test "Middle '?'" {
+ if not address :matches "from" "stephan+sieve?friep.example.com" {
+ test_fail "should have matched";
+ }
+
+ if address :matches "from" "stephan+sieve?fiep.example.com" {
+ test_fail "should not have matched";
+ }
+}
+
+test "Begin '?'" {
+ if not address :matches "from" "?tephan+sieve@friep.example.com" {
+ test_fail "should have matched";
+ }
+
+ if address :matches "from" "?tephan+sievefriep.example.com" {
+ test_fail "should not have matched";
+ }
+}
+
+test "End '?'" {
+ if not address :matches "from" "stephan+sieve@friep.example.co?" {
+ test_fail "should have matched";
+ }
+
+ if address :matches "from" "sephan+sieve@friep.example.co?" {
+ test_fail "should not have matched";
+ }
+}
+
+test "Multiple '?'" {
+ if not address :matches "from" "?t?phan?sieve?fri?p.exampl?.co?" {
+ test_fail "should have matched";
+ }
+
+ if address :matches "from" "?t?phan?sieve?fiep.exam?le.co?" {
+ test_fail "should not have matched";
+ }
+}
+
+test "Escaped '?'" {
+ if not header :matches "x-bullshit" "33333\\?\\?\\??" {
+ test_fail "should have matched";
+ }
+
+ if header :matches "x-bullshit" "33333\\?\\?\\?" {
+ test_fail "should not have matched";
+ }
+}
+
+test "Escaped '?' following '*'" {
+ if not header :matches "x-bullshit" "33333*\\?\\??" {
+ test_fail "should have matched";
+ }
+
+}
+
+test "Escaped '?' directly following initial '*'" {
+ if not header :matches "X-Bullshit" "*\\?\\?\\?a" {
+ test_fail "should have matched";
+ }
+}
+
+test "Escaped '?' following initial '*'" {
+ if not header :matches "x-bullshit" "*3333\\?\\?\\?a" {
+ test_fail "should have matched";
+ }
+}
+
+test "Escaped '*' with active '*' at the end" {
+ if not header :matches "x-spam-score" "\\*\\*\\*\\*\\**" {
+ test_fail "should have matched";
+ }
+}
+
+test "All escaped '*'" {
+ if not header :matches "x-spam-score" "\\*\\*\\*\\*\\*\\*\\*\\*\\*\\*" {
+ test_fail "should have matched";
+ }
+
+ if header :matches "x-spam-score" "\\*\\*\\*\\*\\*\\*\\*\\*\\*\\*\\*" {
+ test_fail "should not have matched";
+ }
+}
+
+test "Middle not escaped '*'" {
+ if not header :matches "x-spam-score" "\\*\\*\\***\\*\\*" {
+ test_fail "should have matched";
+ }
+}
+
+test "Escaped '*' alternating with '?'" {
+ if not header :matches "x-spam-score" "\\*?\\*?\\*?\\*?\\*?" {
+ test_fail "should have matched";
+ }
+
+ if header :matches "x-spam-score" "\\*?\\*?\\*?\\*?\\*??" {
+ test_fail "should not have matched";
+ }
+}
+
+test "All escaped" {
+ if header :matches "x-bullshit" "\\*3333\\?\\?\\?a" {
+ test_fail "should not have matched";
+ }
+
+
+ if header :matches "x-bullshit" "33333\\?\\?\\?aa" {
+ test_fail "should not have matched";
+ }
+
+ if header :matches "x-bullshit" "\\f3333\\?\\?\\?a" {
+ test_fail "should not have matched";
+ }
+}
+
+test "Put '*' directly before '?'" {
+ if header :matches "x-subject" "Log for *??????????? build of *" {
+ test_fail "should not have matched";
+ }
+
+ if not header :matches "x-subject" "Log for *?????????? build of *" {
+ test_fail "should have matched";
+ }
+
+ if not header :matches "x-subject" "Log for *? build of *" {
+ test_fail "should have matched";
+ }
+}
+
+test "Put '?' directly before '*'" {
+ if header :matches "x-subject" "Log for ???????????* build of *" {
+ test_fail "should not have matched";
+ }
+
+ if not header :matches "x-subject" "Log for ??????????* build of *" {
+ test_fail "should have matched";
+ }
+
+ if not header :matches "x-subject" "Log for ?* build of *" {
+ test_fail "should have matched";
+ }
+}
+
+test "Fixed beginning" {
+ if not header :matches "subject" "make your *" {
+ test_fail "should have matched";
+ }
+}
+
+test "Fixed end" {
+ if not header :matches "subject" "* very fast!!!" {
+ test_fail "should have matched";
+ }
+
+ if header :matches "subject" "* very fast!!" {
+ test_fail "should not have matched";
+ }
+}
+
+test "Fixed string" {
+ if not address :matches "to" "sirius@example.org" {
+ test_fail "should have matched";
+ }
+
+ if address :matches "to" "example.org" {
+ test_fail "should not have matched";
+ }
+
+ if address :matches "to" "sirius" {
+ test_fail "should not have matched";
+ }
+}
diff --git a/pigeonhole/tests/multiscript/basic.svtest b/pigeonhole/tests/multiscript/basic.svtest
new file mode 100644
index 0000000..ce9bb66
--- /dev/null
+++ b/pigeonhole/tests/multiscript/basic.svtest
@@ -0,0 +1,91 @@
+require "vnd.dovecot.testsuite";
+
+test_set "message" text:
+From: stephan@example.org
+Message-ID: <frop33333333333333333@frutsens.example.nl>
+To: nico@frop.example.org
+Subject: Frop.
+
+Friep.
+.
+;
+
+test "Append" {
+ if not allof (
+ test_script_compile "fileinto-inbox.sieve",
+ test_script_run ){
+ test_fail "failed to compile and run first script";
+ }
+
+ if not allof (
+ test_script_compile "vacation.sieve",
+ test_script_run :append_result ) {
+ test_fail "failed to compile and run second script";
+ }
+
+ if not allof (
+ test_script_compile "notify.sieve",
+ test_script_run :append_result ) {
+ test_fail "failed to compile and run third script";
+ }
+
+ if not test_result_action :index 1 "store" {
+ test_fail "first action is not 'store'";
+ }
+
+ if not test_result_action :index 2 "vacation" {
+ test_fail "second action is not 'vacation'";
+ }
+
+ if not test_result_action :index 3 "notify" {
+ test_fail "third action is not 'notify'";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed";
+ }
+}
+
+test "Sequential Execute" {
+ if not allof (
+ test_script_compile "fileinto-inbox.sieve",
+ test_script_run ) {
+ test_fail "failed to compile and run first script";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed after first script";
+ }
+
+ if not allof (
+ test_script_compile "vacation.sieve",
+ test_script_run :append_result ) {
+ test_fail "failed to compile and run second script";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed after second script";
+ }
+
+ if not allof (
+ test_script_compile "notify.sieve",
+ test_script_run :append_result ) {
+ test_fail "failed to compile and run third script";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed after third script";
+ }
+
+ if not test_result_action :index 1 "store" {
+ test_fail "first action is not 'store'";
+ }
+
+ if not test_result_action :index 2 "vacation" {
+ test_fail "second action is not 'vacation'";
+ }
+
+ if not test_result_action :index 3 "notify" {
+ test_fail "third action is not 'notify'";
+ }
+}
diff --git a/pigeonhole/tests/multiscript/conflicts.svtest b/pigeonhole/tests/multiscript/conflicts.svtest
new file mode 100644
index 0000000..a2b8fab
--- /dev/null
+++ b/pigeonhole/tests/multiscript/conflicts.svtest
@@ -0,0 +1,100 @@
+require "vnd.dovecot.testsuite";
+
+test_set "message" text:
+From: stephan@example.org
+Message-ID: <frop33333333333333333@nl.example.com>
+To: nico@frop.example.org
+Subject: Frop.
+
+Friep.
+.
+;
+
+test "Graceful Conflicts" {
+ if not allof (
+ test_script_compile "fileinto-inbox.sieve",
+ test_script_run ){
+ test_fail "failed to compile and run first script";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed after first script";
+ }
+
+ if not allof (
+ test_script_compile "reject-1.sieve",
+ test_script_run :append_result ) {
+ test_fail "failed to compile and run second script";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed after second script";
+ }
+
+ if not allof (
+ test_script_compile "reject-2.sieve",
+ test_script_run :append_result ) {
+ test_fail "failed to compile and run third script";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed after third script";
+ }
+
+ if not test_result_action :index 1 "store" {
+ test_result_print;
+ test_fail "first action is not 'store'";
+ }
+
+ if not test_result_action :index 2 "reject" {
+ test_result_print;
+ test_fail "first reject action not retained";
+ }
+
+ if test_result_action :index 3 "reject" {
+ test_result_print;
+ test_fail "second reject action not discarded";
+ }
+
+}
+
+test "Duplicates" {
+ if not allof (
+ test_script_compile "fileinto-inbox.sieve",
+ test_script_run ){
+ test_fail "failed to compile and run first script";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed after first script";
+ }
+
+ if not allof (
+ test_script_compile "fileinto-inbox.sieve",
+ test_script_run :append_result ) {
+ test_fail "failed to compile and run second script";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed after second script";
+ }
+
+ if not allof (
+ test_script_compile "keep.sieve",
+ test_script_run :append_result ) {
+ test_fail "failed to compile and run third script";
+ }
+
+ if not test_result_execute {
+ test_fail "result execute failed after third script";
+ }
+
+ if not test_result_action :index 1 "keep" {
+ test_fail "first action is not 'keep'";
+ }
+
+ if test_result_action :index 2 "store" {
+ test_fail "fileinto action not discarded";
+ }
+}
+
diff --git a/pigeonhole/tests/multiscript/fileinto-frop.sieve b/pigeonhole/tests/multiscript/fileinto-frop.sieve
new file mode 100644
index 0000000..9aafb95
--- /dev/null
+++ b/pigeonhole/tests/multiscript/fileinto-frop.sieve
@@ -0,0 +1,3 @@
+require "fileinto";
+
+fileinto "frop";
diff --git a/pigeonhole/tests/multiscript/fileinto-inbox.sieve b/pigeonhole/tests/multiscript/fileinto-inbox.sieve
new file mode 100644
index 0000000..b5da850
--- /dev/null
+++ b/pigeonhole/tests/multiscript/fileinto-inbox.sieve
@@ -0,0 +1,4 @@
+require "fileinto";
+
+fileinto "INBOX";
+
diff --git a/pigeonhole/tests/multiscript/keep.sieve b/pigeonhole/tests/multiscript/keep.sieve
new file mode 100644
index 0000000..6203a21
--- /dev/null
+++ b/pigeonhole/tests/multiscript/keep.sieve
@@ -0,0 +1 @@
+keep;
diff --git a/pigeonhole/tests/multiscript/notify.sieve b/pigeonhole/tests/multiscript/notify.sieve
new file mode 100644
index 0000000..af47ad9
--- /dev/null
+++ b/pigeonhole/tests/multiscript/notify.sieve
@@ -0,0 +1,3 @@
+require "enotify";
+
+notify "mailto:stephan@example.org";
diff --git a/pigeonhole/tests/multiscript/reject-1.sieve b/pigeonhole/tests/multiscript/reject-1.sieve
new file mode 100644
index 0000000..06744f6
--- /dev/null
+++ b/pigeonhole/tests/multiscript/reject-1.sieve
@@ -0,0 +1,3 @@
+require "reject";
+
+reject "Message is not wanted.";
diff --git a/pigeonhole/tests/multiscript/reject-2.sieve b/pigeonhole/tests/multiscript/reject-2.sieve
new file mode 100644
index 0000000..96b7564
--- /dev/null
+++ b/pigeonhole/tests/multiscript/reject-2.sieve
@@ -0,0 +1,3 @@
+require "reject";
+
+reject "Will not accept this nonsense.";
diff --git a/pigeonhole/tests/multiscript/vacation.sieve b/pigeonhole/tests/multiscript/vacation.sieve
new file mode 100644
index 0000000..d735da5
--- /dev/null
+++ b/pigeonhole/tests/multiscript/vacation.sieve
@@ -0,0 +1,3 @@
+require "vacation";
+
+vacation "I am not home";
diff --git a/pigeonhole/tests/plugins/extprograms/bin/addheader b/pigeonhole/tests/plugins/extprograms/bin/addheader
new file mode 100755
index 0000000..8f9805a
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/bin/addheader
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+echo "$1: $2"
+cat
+
+exit 0
diff --git a/pigeonhole/tests/plugins/extprograms/bin/big b/pigeonhole/tests/plugins/extprograms/bin/big
new file mode 100755
index 0000000..ce1df51
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/bin/big
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+N="0123456701234567012345670123456701234567012345670123456701234567"
+N="$N$N$N$N$N$N$N$N$N$N$N$N$N$N$N$N"
+echo -n "$N$N"
+
+exit 0
+
diff --git a/pigeonhole/tests/plugins/extprograms/bin/cat b/pigeonhole/tests/plugins/extprograms/bin/cat
new file mode 100755
index 0000000..02b9858
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/bin/cat
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+cat
diff --git a/pigeonhole/tests/plugins/extprograms/bin/cat-stdin b/pigeonhole/tests/plugins/extprograms/bin/cat-stdin
new file mode 100755
index 0000000..781d70b
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/bin/cat-stdin
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+cat /dev/stdin
diff --git a/pigeonhole/tests/plugins/extprograms/bin/crlf b/pigeonhole/tests/plugins/extprograms/bin/crlf
new file mode 100755
index 0000000..a0028cf
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/bin/crlf
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+tr -s '\r' '#'
diff --git a/pigeonhole/tests/plugins/extprograms/bin/env b/pigeonhole/tests/plugins/extprograms/bin/env
new file mode 100755
index 0000000..a7b81ac
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/bin/env
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+eval echo -n "\${$1}"
diff --git a/pigeonhole/tests/plugins/extprograms/bin/frame b/pigeonhole/tests/plugins/extprograms/bin/frame
new file mode 100755
index 0000000..225005e
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/bin/frame
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+echo -n "FRAMED $1{ "
+cat
+echo -n " }"
+
+exit 0
diff --git a/pigeonhole/tests/plugins/extprograms/bin/modify b/pigeonhole/tests/plugins/extprograms/bin/modify
new file mode 100755
index 0000000..ce87014
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/bin/modify
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+echo "X-Frop: Extra header"
+cat
+echo
+echo "Extra body content!"
+
+exit 0
diff --git a/pigeonhole/tests/plugins/extprograms/bin/program b/pigeonhole/tests/plugins/extprograms/bin/program
new file mode 100755
index 0000000..4b5edbf
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/bin/program
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+cat > /dev/null
+
+exit 0
diff --git a/pigeonhole/tests/plugins/extprograms/bin/replace b/pigeonhole/tests/plugins/extprograms/bin/replace
new file mode 100755
index 0000000..b010f06
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/bin/replace
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+cat > /dev/null
+
+echo "From: hatseflat@example.com"
+echo "To: frutsel@example.org"
+echo "Subject: replacement message"
+echo
+echo "Replaced!"
+
+
+exit 0
diff --git a/pigeonhole/tests/plugins/extprograms/bin/sleep10 b/pigeonhole/tests/plugins/extprograms/bin/sleep10
new file mode 100755
index 0000000..8c1b96d
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/bin/sleep10
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+sleep 10
diff --git a/pigeonhole/tests/plugins/extprograms/bin/sleep2 b/pigeonhole/tests/plugins/extprograms/bin/sleep2
new file mode 100755
index 0000000..a814acd
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/bin/sleep2
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+sleep 2
diff --git a/pigeonhole/tests/plugins/extprograms/bin/spamc b/pigeonhole/tests/plugins/extprograms/bin/spamc
new file mode 100755
index 0000000..a3232f4
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/bin/spamc
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+echo 'X-Spam-Status: Yes, score=66.5/5.0 tests=CONTAINS_LARGE_ROOSTER'
+cat
+
+exit 0
diff --git a/pigeonhole/tests/plugins/extprograms/bin/stderr b/pigeonhole/tests/plugins/extprograms/bin/stderr
new file mode 100755
index 0000000..75b94b0
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/bin/stderr
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+echo "========================================" 1>&2
+echo "Test shell script successfully executed!" 1>&2
+echo 1>&2
+echo "Arguments: $1 $2" 1>&2
+echo 1>&2
+echo "Environment:" 1>&2
+env 1>&2
+echo 1>&2
+echo "Message:" 1>&2
+cat 1>&2
+echo "========================================" 1>&2
+echo 1>&2
+
+echo "Subject: frop!"
+echo "From: stephan@example.org"
+echo "To: tss@example.com"
+echo
+echo "Frop!"
diff --git a/pigeonhole/tests/plugins/extprograms/errors.svtest b/pigeonhole/tests/plugins/extprograms/errors.svtest
new file mode 100644
index 0000000..148f4da
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/errors.svtest
@@ -0,0 +1,32 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Invalid program names
+ */
+
+test "Invalid Program Names" {
+ if test_script_compile "errors/programname.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "8" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Invalid arguments
+ */
+
+test "Invalid Arguments" {
+ if test_script_compile "errors/arguments.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "2" {
+ test_fail "wrong number of errors reported";
+ }
+}
diff --git a/pigeonhole/tests/plugins/extprograms/errors/arguments.sieve b/pigeonhole/tests/plugins/extprograms/errors/arguments.sieve
new file mode 100644
index 0000000..04f0aa0
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/errors/arguments.sieve
@@ -0,0 +1,5 @@
+require "vnd.dovecot.pipe";
+
+pipe :args "aaaa
+ aaaa" "frop";
+
diff --git a/pigeonhole/tests/plugins/extprograms/errors/programname.sieve b/pigeonhole/tests/plugins/extprograms/errors/programname.sieve
new file mode 100644
index 0000000..1d2d19c
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/errors/programname.sieve
@@ -0,0 +1,25 @@
+require "variables";
+require "encoded-character";
+require "vnd.dovecot.pipe";
+
+# Slash
+pipe "../frop";
+
+# More slashes
+pipe "../../james/sieve/vacation";
+
+# 0000-001F; [CONTROL CHARACTERS]
+pipe "idiotic${unicode: 001a}";
+
+# 007F; DELETE
+pipe "idiotic${unicode: 007f}";
+
+# 0080-009F; [CONTROL CHARACTERS]
+pipe "idiotic${unicode: 0085}";
+
+# 2028; LINE SEPARATOR
+pipe "idiotic${unicode: 2028}";
+
+# 2029; PARAGRAPH SEPARATOR
+pipe "idiotic${unicode: 2029}";
+
diff --git a/pigeonhole/tests/plugins/extprograms/execute/command.svtest b/pigeonhole/tests/plugins/extprograms/execute/command.svtest
new file mode 100644
index 0000000..92c1fd1
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/execute/command.svtest
@@ -0,0 +1,27 @@
+require "vnd.dovecot.testsuite";
+require "vnd.dovecot.execute";
+require "variables";
+
+test_config_set "sieve_execute_bin_dir" "${tst.path}/../bin";
+test_config_reload :extension "vnd.dovecot.execute";
+
+test "Basic" {
+ execute "program";
+}
+
+test "Input message" {
+ execute :pipe "program";
+}
+
+test "Input string" {
+ execute :input "DATA" "program";
+}
+
+test "Input variable" {
+ set "DATA" "DATA";
+ execute :input "${DATA}" "program";
+}
+
+test "Output variable" {
+ execute :output "DATA" "program";
+}
diff --git a/pigeonhole/tests/plugins/extprograms/execute/errors.svtest b/pigeonhole/tests/plugins/extprograms/execute/errors.svtest
new file mode 100644
index 0000000..3dd2d5f
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/execute/errors.svtest
@@ -0,0 +1,53 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+test_config_set "sieve_execute_bin_dir" "${tst.path}/../bin";
+test_config_reload :extension "vnd.dovecot.execute";
+
+/*
+ * Command syntax
+ */
+
+test "Command syntax" {
+ if test_script_compile "errors/syntax.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "13" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Variables
+ */
+
+test "Variables" {
+ if test_script_compile "errors/variables.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "2" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Unknown program
+ */
+
+test "Unknown program" {
+ if not test_script_compile "errors/unknown-program.sieve" {
+ test_fail "compile should have succeeded";
+ }
+
+ if test_script_run {
+ test_fail "execution should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "1" {
+ test_fail "wrong number of errors reported";
+ }
+}
diff --git a/pigeonhole/tests/plugins/extprograms/execute/errors/syntax.sieve b/pigeonhole/tests/plugins/extprograms/execute/errors/syntax.sieve
new file mode 100644
index 0000000..1f4646a
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/execute/errors/syntax.sieve
@@ -0,0 +1,38 @@
+require "vnd.dovecot.execute";
+
+# 1: error: no arguments
+execute;
+
+# 2: error: numeric argument
+execute 1;
+
+# 3: error: tag argument
+execute :frop;
+
+# 4: error: numeric second argument
+execute "sdfd" 1;
+
+# 5: error: stringlist first argument
+execute ["sdfd","werwe"] "sdfs";
+
+# 6: error: too many arguments
+execute "sdfs" "sdfd" "werwe";
+
+# 7: error: inappropriate :copy argument
+execute :copy "234234" ["324234", "23423"];
+
+# 8: error: invalid :input argument; missing parameter
+execute :input "frop";
+
+# 9: error: invalid :input argument; invalid parameter
+execute :input 1 "frop";
+
+# 10: error: invalid :input argument; invalid parameter
+execute :input ["23423","21342"] "frop";
+
+# 11: error: invalid :input argument; invalid parameter
+execute :input :friep "frop";
+
+# 12: error: :output not allowed without variables extension
+execute :output "${frop}" "frop";
+
diff --git a/pigeonhole/tests/plugins/extprograms/execute/errors/unknown-program.sieve b/pigeonhole/tests/plugins/extprograms/execute/errors/unknown-program.sieve
new file mode 100644
index 0000000..3a79bb6
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/execute/errors/unknown-program.sieve
@@ -0,0 +1,3 @@
+require "vnd.dovecot.execute";
+
+execute "unknown";
diff --git a/pigeonhole/tests/plugins/extprograms/execute/errors/variables.sieve b/pigeonhole/tests/plugins/extprograms/execute/errors/variables.sieve
new file mode 100644
index 0000000..3d0b3e7
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/execute/errors/variables.sieve
@@ -0,0 +1,7 @@
+require "vnd.dovecot.execute";
+require "variables";
+
+# 1: invalid variable name
+execute :output "wqwe-aeqwe" "frop";
+
+
diff --git a/pigeonhole/tests/plugins/extprograms/execute/execute.svtest b/pigeonhole/tests/plugins/extprograms/execute/execute.svtest
new file mode 100644
index 0000000..f16af11
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/execute/execute.svtest
@@ -0,0 +1,177 @@
+require "vnd.dovecot.testsuite";
+require "vnd.dovecot.execute";
+require "vnd.dovecot.debug";
+require "variables";
+require "relational";
+require "environment";
+require "encoded-character";
+
+test_set "message" text:
+From: stephan@example.com
+To: pipe@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_config_set "sieve_execute_bin_dir" "${tst.path}/../bin";
+test_config_reload :extension "vnd.dovecot.execute";
+test_result_reset;
+
+test "Execute - bare" {
+ execute "program";
+}
+
+test_result_reset;
+test "Execute - i/-" {
+ execute :input "FROP" "frame";
+}
+
+test_result_reset;
+test "Execute - -/o" {
+ execute :output "out" "frame";
+
+ if not string "${out}" "FRAMED { }" {
+ test_fail "wrong string returned: ${out}";
+ }
+}
+
+test_result_reset;
+test "Execute - i/o" {
+ execute :input "FROP" :output "out" "frame";
+
+ if not string "${out}" "FRAMED { FROP }" {
+ test_fail "wrong string returned: ${out}";
+ }
+}
+
+test_result_reset;
+test "Execute - i/o and arguments" {
+ execute :input "FROP" :output "out" "frame" ["FRIEP "];
+
+ if not string "${out}" "FRAMED FRIEP { FROP }" {
+ test_fail "wrong string returned: ${out}";
+ }
+}
+
+test_result_reset;
+test "Execute - pipe" {
+ execute :pipe :output "msg" "cat";
+
+ if not string :contains "${msg}" "Subject: Frop!" {
+ test_fail "wrong string returned: ${out}";
+ }
+}
+
+test_result_reset;
+test "Execute - pipe /dev/stdin" {
+ execute :pipe :output "msg" "cat-stdin";
+
+ if not string :contains "${msg}" "Subject: Frop!" {
+ test_fail "wrong string returned: ${out}";
+ }
+}
+
+test_result_reset;
+test "Execute - env" {
+ test_set "envelope.from" "stephan@sub.example.com";
+ test_set "envelope.to" "stephan@sub.example.net";
+ test_set "envelope.orig_to" "all@sub.example.net";
+
+ execute :output "out" "env" "SENDER";
+ if not string :is "${out}" "stephan@sub.example.com" {
+ test_fail "wrong SENDER env returned: '${out}'";
+ }
+
+ execute :output "out" "env" "RECIPIENT";
+ if not string :is "${out}" "stephan@sub.example.net" {
+ test_fail "wrong RECIPIENT env returned: '${out}'";
+ }
+
+ execute :output "out" "env" "ORIG_RECIPIENT";
+ if not string :is "${out}" "all@sub.example.net" {
+ test_fail "wrong ORIG_RECIPIENT env returned: '${out}'";
+ }
+
+ execute :output "out" "env" "HOST";
+ if not environment :is "host" "${out}" {
+ test_fail "wrong HOST env returned: '${out}'";
+ }
+
+ execute :output "out" "env" "HOME";
+ if string :count "eq" "${out}" "0" {
+ test_fail "empty HOME env returned";
+ }
+
+ execute :output "out" "env" "USER";
+ if string :count "eq" "${out}" "0" {
+ test_fail "empty USER env returned";
+ }
+}
+
+test_result_reset;
+test "Execute - used as test" {
+ if execute :pipe :output "msg" "dog" {
+ test_fail "execute action indicated success with invalid program";
+ }
+
+ if not execute :pipe :output "msg" "cat" {
+ test_fail "execute action indicated failure with valid program";
+ }
+
+ if not string :contains "${msg}" "Subject: Frop!" {
+ test_fail "wrong string returned: ${out}";
+ }
+}
+
+test_config_set "sieve_execute_input_eol" "crlf";
+test_config_reload :extension "vnd.dovecot.execute";
+test_result_reset;
+set "out" "";
+
+test "Execute - CRLF" {
+ execute
+ :input "FROP${hex:0A}FRIEP${hex:0a}"
+ :output "out"
+ "crlf";
+
+ if not string "${out}" "FROP#${hex:0A}FRIEP#${hex:0a}" {
+ test_fail "wrong string returned: '${out}'";
+ }
+}
+
+test_config_set "sieve_execute_input_eol" "lf";
+test_config_reload :extension "vnd.dovecot.execute";
+test_result_reset;
+set "out" "";
+
+test "Execute - LF" {
+ execute
+ :input "FROP${hex:0D 0A}FRIEP${hex:0d 0a}"
+ :output "out"
+ "crlf";
+
+ if not string "${out}" "FROP${hex:0A}FRIEP${hex:0a}" {
+ test_fail "wrong string returned: '${out}'";
+ }
+}
+
+set "D" "0123456701234567012345670123456701234567012345670123456701234567";
+set "D" "${D}${D}${D}${D}${D}${D}${D}${D}${D}${D}${D}${D}${D}${D}${D}${D}";
+set "data" "${D}${D}";
+
+test_config_set "sieve_execute_input_eol" "crlf";
+test_config_reload :extension "vnd.dovecot.execute";
+test_result_reset;
+set "out" "";
+
+test "Execute - big" {
+ execute
+ :output "out"
+ "big";
+
+ if not string "${out}" "${data}" {
+ test_fail "wrong string returned: '${out}'";
+ }
+}
diff --git a/pigeonhole/tests/plugins/extprograms/filter/command.svtest b/pigeonhole/tests/plugins/extprograms/filter/command.svtest
new file mode 100644
index 0000000..50f949a
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/filter/command.svtest
@@ -0,0 +1,10 @@
+require "vnd.dovecot.testsuite";
+require "vnd.dovecot.filter";
+require "variables";
+
+test_config_set "sieve_filter_bin_dir" "${tst.path}/../bin";
+test_config_reload :extension "vnd.dovecot.filter";
+
+test "Basic" {
+ filter "program";
+}
diff --git a/pigeonhole/tests/plugins/extprograms/filter/errors.svtest b/pigeonhole/tests/plugins/extprograms/filter/errors.svtest
new file mode 100644
index 0000000..1d04ba1
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/filter/errors.svtest
@@ -0,0 +1,39 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Command syntax
+ */
+
+test_config_set "sieve_filter_bin_dir" "${tst.path}/../bin";
+test_config_reload :extension "vnd.dovecot.filter";
+
+test "Command syntax" {
+ if test_script_compile "errors/syntax.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "8" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Unknown program
+ */
+
+test "Unknown program" {
+ if not test_script_compile "errors/unknown-program.sieve" {
+ test_fail "compile should have succeeded";
+ }
+
+ if test_script_run {
+ test_fail "execution should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "1" {
+ test_fail "wrong number of errors reported";
+ }
+}
diff --git a/pigeonhole/tests/plugins/extprograms/filter/errors/syntax.sieve b/pigeonhole/tests/plugins/extprograms/filter/errors/syntax.sieve
new file mode 100644
index 0000000..00a3a23
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/filter/errors/syntax.sieve
@@ -0,0 +1,22 @@
+require "vnd.dovecot.filter";
+
+# 1: error: no arguments
+filter;
+
+# 2: error: numeric argument
+filter 1;
+
+# 3: error: tag argument
+filter :frop;
+
+# 4: error: numeric second argument
+filter "sdfd" 1;
+
+# 5: error: stringlist first argument
+filter ["sdfd","werwe"] "sdfs";
+
+# 6: error: too many arguments
+filter "sdfd" "werwe" "sdfs";
+
+# 7: error: inappropriate :copy argument
+filter :try :copy "234234" ["324234", "23423"];
diff --git a/pigeonhole/tests/plugins/extprograms/filter/errors/unknown-program.sieve b/pigeonhole/tests/plugins/extprograms/filter/errors/unknown-program.sieve
new file mode 100644
index 0000000..7e530ee
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/filter/errors/unknown-program.sieve
@@ -0,0 +1,3 @@
+require "vnd.dovecot.filter";
+
+filter "unknown";
diff --git a/pigeonhole/tests/plugins/extprograms/filter/execute.svtest b/pigeonhole/tests/plugins/extprograms/filter/execute.svtest
new file mode 100644
index 0000000..15fab69
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/filter/execute.svtest
@@ -0,0 +1,213 @@
+require "vnd.dovecot.testsuite";
+require "vnd.dovecot.filter";
+require "vnd.dovecot.debug";
+require "variables";
+require "editheader";
+require "spamtest";
+require "body";
+require "fileinto";
+require "mailbox";
+
+test_set "message" text:
+From: stephan@example.com
+To: pipe@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_config_set "sieve_filter_bin_dir" "${tst.path}/../bin";
+test_config_reload :extension "vnd.dovecot.filter";
+test_result_reset;
+
+test_result_reset;
+test "Replace" {
+ if header :contains "subject" "replacement" {
+ test_fail "message already replaced";
+ }
+
+ filter "replace";
+
+ if not header :contains "subject" "replacement" {
+ test_fail "message not replaced";
+ }
+}
+
+test_result_reset;
+test "Used as test" {
+ if filter "nonsense" {
+ test_fail "filter action indicated success with invalid program";
+ }
+
+ if not filter "replace" {
+ test_fail "filter action indicated failure with valid program";
+ }
+
+ if not header :contains "subject" "replacement" {
+ test_fail "message not replaced; filter not actually executed";
+ }
+}
+
+test_result_reset;
+test "Modify" {
+ if anyof (
+ body :contains "extra",
+ exists "x-frop") {
+ test_fail "message already modified";
+ }
+
+ if not header "subject" "Frop!" {
+ test_fail "message is wrong";
+ }
+
+ filter "modify";
+
+ if not header "subject" "Frop!" {
+ test_fail "message replaced erroneously";
+ }
+
+ if not header :contains "x-frop" "extra" {
+ test_fail "message header not modified";
+ }
+
+ if not body :contains "Extra" {
+ test_fail "message body not modified";
+ }
+}
+
+test_result_reset;
+test "Editheader" {
+ if anyof ( exists "X-A", exists "X-B", exists "X-C", exists "X-D",
+ exists "X-E") {
+ test_fail "message already modified";
+ }
+
+ addheader "X-A" "1";
+ if not header "X-A" "1" {
+ test_fail "X-A header missing";
+ }
+
+ fileinto :create "A";
+
+ filter "addheader" ["X-B", "2"];
+ if not header "X-B" "2" {
+ test_fail "X-B header missing";
+ }
+
+ fileinto :create "B";
+
+ addheader "X-C" "3";
+ if not header "X-C" "3" {
+ test_fail "X-C header missing";
+ }
+
+ fileinto :create "C";
+
+ filter "addheader" ["X-D", "4"];
+ if not header "X-D" "4" {
+ test_fail "X-D header missing";
+ }
+
+ fileinto :create "D";
+
+ addheader "X-E" "5";
+ if not header "X-E" "5" {
+ test_fail "X-E header missing";
+ }
+
+ fileinto :create "E";
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ test_message :folder "A" 0;
+
+ if not header "X-A" "1" {
+ test_fail "X-A header missing";
+ }
+ if anyof (
+ header "X-B" "2", header "X-C" "3",
+ header "X-D" "4", header "X-E" "5") {
+ test_fail "X-B, X-C, X-D or X-E header found";
+ }
+
+ test_message :folder "B" 0;
+
+ if not header "X-B" "2" {
+ test_fail "X-B header missing";
+ }
+ if anyof (
+ header "X-C" "3", header "X-D" "4", header "X-E" "5") {
+ test_fail "X-C, X-D or X-E header found";
+ }
+
+ test_message :folder "C" 0;
+
+ if not header "X-C" "3" {
+ test_fail "X-C header missing";
+ }
+ if anyof (header "X-D" "4", header "X-E" "5") {
+ test_fail "X-D or X-E header found";
+ }
+
+ test_message :folder "D" 0;
+
+ if not header "X-D" "4" {
+ test_fail "X-D header missing";
+ }
+ if anyof (header "X-E" "5") {
+ test_fail "X-E header found";
+ }
+
+ test_message :folder "E" 0;
+
+ if not header "X-A" "1" {
+ test_fail "X-A header missing in final message";
+ }
+ if not header "X-B" "2" {
+ test_fail "X-B header missing in final message";
+ }
+ if not header "X-C" "3" {
+ test_fail "X-C header missing in final message";
+ }
+ if not header "X-D" "4" {
+ test_fail "X-D header missing in final message";
+ }
+ if not header "X-E" "5" {
+ test_fail "X-E header missing in final message";
+ }
+}
+
+test_config_set "sieve_spamtest_status_header"
+ "X-Spam-Status: [^,]*, score=(-?[[:digit:]]+\\.[[:digit:]]).*";
+test_config_set "sieve_spamtest_max_value" "10";
+test_config_set "sieve_spamtest_status_type" "score";
+test_config_reload :extension "spamtest";
+
+test_result_reset;
+test "Spamtest" {
+ if exists "x-spam-status" {
+ test_fail "message already modified";
+ }
+
+ if not header "subject" "Frop!" {
+ test_fail "message is wrong";
+ }
+
+ filter "spamc";
+
+ if not exists "x-spam-status" {
+ test_fail "x-spam-score header not added";
+ }
+
+ if spamtest :is "0" {
+ test_fail "spamtest not configured or test failed";
+ }
+
+ if not spamtest :is "10" {
+ test_fail "spamtest yields incorrect value";
+ }
+}
+
diff --git a/pigeonhole/tests/plugins/extprograms/pipe/command.svtest b/pigeonhole/tests/plugins/extprograms/pipe/command.svtest
new file mode 100644
index 0000000..dabd970
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/pipe/command.svtest
@@ -0,0 +1,10 @@
+require "vnd.dovecot.testsuite";
+require "vnd.dovecot.pipe";
+
+test_config_set "sieve_pipe_bin_dir" "${tst.path}/../bin";
+test_config_reload :extension "vnd.dovecot.pipe";
+
+test "Basic" {
+ pipe "program";
+}
+
diff --git a/pigeonhole/tests/plugins/extprograms/pipe/errors.svtest b/pigeonhole/tests/plugins/extprograms/pipe/errors.svtest
new file mode 100644
index 0000000..af36b91
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/pipe/errors.svtest
@@ -0,0 +1,94 @@
+require "vnd.dovecot.testsuite";
+require "variables";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Command syntax
+ */
+
+test "Command syntax" {
+ if test_script_compile "errors/syntax.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "8" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/* Unknown program */
+
+test_set "message" text:
+From: stephan@example.com
+To: pipe@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_config_set "sieve_pipe_bin_dir" "${tst.path}/../bin";
+test_config_reload :extension "vnd.dovecot.pipe";
+test_result_reset;
+
+test "Unknown program" {
+ if not test_script_compile "errors/unknown-program.sieve" {
+ test_fail "compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "execute failed";
+ }
+
+ if test_result_execute {
+ test_fail "pipe should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "1" {
+ test_fail "wrong number of errors reported";
+ }
+
+ if not test_error :index 1 :contains "failed to pipe" {
+ test_fail "wrong error reported";
+ }
+}
+
+/* Timeout */
+
+test_set "message" text:
+From: stephan@example.com
+To: pipe@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+
+test_config_set "sieve_pipe_bin_dir" "${tst.path}/../bin";
+test_config_set "sieve_pipe_exec_timeout" "1s";
+test_config_reload :extension "vnd.dovecot.pipe";
+test_result_reset;
+
+test "Timeout" {
+ if not test_script_compile "errors/timeout.sieve" {
+ test_fail "compile failed";
+ }
+
+ if not test_script_run {
+ test_fail "execute failed";
+ }
+
+ if test_result_execute {
+ test_fail "pipe should have timed out";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "2" {
+ test_fail "wrong number of errors reported";
+ }
+
+ if not test_error :index 2 :contains "failed to pipe" {
+ test_fail "wrong error reported";
+ }
+}
diff --git a/pigeonhole/tests/plugins/extprograms/pipe/errors/syntax.sieve b/pigeonhole/tests/plugins/extprograms/pipe/errors/syntax.sieve
new file mode 100644
index 0000000..64d5310
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/pipe/errors/syntax.sieve
@@ -0,0 +1,22 @@
+require "vnd.dovecot.pipe";
+
+# 1: error: no arguments
+pipe;
+
+# 2: error: numeric argument
+pipe 1;
+
+# 3: error: tag argument
+pipe :frop;
+
+# 4: error: numeric second argument
+pipe "sdfd" 1;
+
+# 5: error: stringlist first argument
+pipe ["sdfd","werwe"] "sdfs";
+
+# 6: error: too many arguments
+pipe "sdfd" "werwe" "sdfs";
+
+# 7: error: inappropriate :copy argument
+pipe :try :copy "234234" ["324234", "23423"];
diff --git a/pigeonhole/tests/plugins/extprograms/pipe/errors/timeout.sieve b/pigeonhole/tests/plugins/extprograms/pipe/errors/timeout.sieve
new file mode 100644
index 0000000..7a940c8
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/pipe/errors/timeout.sieve
@@ -0,0 +1,3 @@
+require "vnd.dovecot.pipe";
+
+pipe "sleep10";
diff --git a/pigeonhole/tests/plugins/extprograms/pipe/errors/unknown-program.sieve b/pigeonhole/tests/plugins/extprograms/pipe/errors/unknown-program.sieve
new file mode 100644
index 0000000..fd6338b
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/pipe/errors/unknown-program.sieve
@@ -0,0 +1,3 @@
+require "vnd.dovecot.pipe";
+
+pipe "unknown";
diff --git a/pigeonhole/tests/plugins/extprograms/pipe/execute.svtest b/pigeonhole/tests/plugins/extprograms/pipe/execute.svtest
new file mode 100644
index 0000000..34b6798
--- /dev/null
+++ b/pigeonhole/tests/plugins/extprograms/pipe/execute.svtest
@@ -0,0 +1,56 @@
+require "vnd.dovecot.testsuite";
+require "vnd.dovecot.pipe";
+require "vnd.dovecot.debug";
+require "variables";
+
+test_set "message" text:
+From: stephan@example.com
+To: pipe@example.net
+Subject: Frop!
+
+Frop!
+.
+;
+
+/* Basic pipe */
+
+test_config_set "sieve_pipe_bin_dir" "${tst.path}/../bin";
+test_config_reload :extension "vnd.dovecot.pipe";
+test_result_reset;
+
+test "Pipe" {
+ pipe "stderr" ["ONE", "TWO"];
+
+ if not test_result_execute {
+ test_fail "failed to pipe message to script";
+ }
+}
+
+/* Timeout */
+
+test_config_set "sieve_pipe_bin_dir" "${tst.path}/../bin";
+test_config_set "sieve_pipe_exec_timeout" "3s";
+test_config_reload :extension "vnd.dovecot.pipe";
+test_result_reset;
+
+test "Timeout 3s" {
+ pipe "sleep2";
+
+ if not test_result_execute {
+ test_fail "failed to pipe message to script";
+ }
+}
+
+test_result_reset;
+test_config_set "sieve_pipe_bin_dir" "${tst.path}/../bin";
+test_config_set "sieve_pipe_exec_timeout" "0";
+test_config_reload :extension "vnd.dovecot.pipe";
+test_result_reset;
+
+test "Timeout infinite" {
+ pipe "sleep2";
+
+ if not test_result_execute {
+ test_fail "failed to pipe message to script";
+ }
+}
diff --git a/pigeonhole/tests/test-address.svtest b/pigeonhole/tests/test-address.svtest
new file mode 100644
index 0000000..135d549
--- /dev/null
+++ b/pigeonhole/tests/test-address.svtest
@@ -0,0 +1,434 @@
+require "vnd.dovecot.testsuite";
+
+/*
+ * ## RFC 5228, Section 5.1. Test address (page 26) ##
+ */
+
+/*
+ * TEST: Basic functionionality
+ */
+
+/* "The "address" test matches Internet addresses in structured headers
+ * that contain addresses. It returns true if any header contains any
+ * key in the specified part of the address, as modified by the
+ * comparator and the match keyword. Whether there are other addresses
+ * present in the header doesn't affect this test; this test does not
+ * provide any way to determine whether an address is the only address
+ * in a header.
+ *
+ * Like envelope and header, this test returns true if any combination
+ * of the header-list and key-list arguments match and returns false
+ * otherwise.
+ * "
+ */
+
+test_set "message" text:
+From: stephan@example.com
+To: nico@nl.example.com, harry@de.example.com
+cc: Timo <tss(no spam)@fi.iki>
+Subject: Frobnitzm
+
+Test.
+.
+;
+
+test "Basic functionality" {
+ /* Must match */
+ if not address :contains ["to", "from"] "harry" {
+ test_fail "failed to match address (1)";
+ }
+
+ if not address :contains ["to", "from"] "de.example" {
+ test_fail "failed to match address (2)";
+ }
+
+ if not address :matches "to" "*@*.example.com" {
+ test_fail "failed to match address (3)";
+ }
+
+ if not address :is "to" "harry@de.example.com" {
+ test_fail "failed to match address (4)";
+ }
+
+ /* Must not match */
+ if address :is ["to", "from"] "nonsense@example.com" {
+ test_fail "matches erroneous address";
+ }
+
+ /* Match first key */
+ if not address :contains ["to"] ["nico", "fred", "henk"] {
+ test_fail "failed to match first key";
+ }
+
+ /* Match second key */
+ if not address :contains ["to"] ["fred", "nico", "henk"] {
+ test_fail "failed to match second key";
+ }
+
+ /* Match last key */
+ if not address :contains ["to"] ["fred", "henk", "nico"] {
+ test_fail "failed to match last key";
+ }
+
+ /* First header */
+ if not address :contains ["to", "from"] ["fred", "nico", "henk"] {
+ test_fail "failed to match first header";
+ }
+
+ /* Second header */
+ if not address :contains ["from", "to"] ["fred", "nico", "henk"] {
+ test_fail "failed to match second header";
+ }
+
+ /* Comment */
+ if not address :is "cc" "tss@fi.iki" {
+ test_fail "failed to ignore comment in address";
+ }
+}
+
+/*
+ * TEST: Case-sensitivity
+ */
+
+/* "Internet email addresses [RFC 2822] have the somewhat awkward characteristic
+ * that the local-part to the left of the at-sign is considered case sensitive,
+ * and the domain-part to the right of the at-sign is case insensitive. The
+ * "address" command does not deal with this itself, but provides the
+ * ADDRESS-PART argument for allowing users to deal with it.
+ * "
+ */
+
+test_set "message" text:
+From: stephan@example.com
+To: Nico@nl.example.com, harry@DE.EXAMPLE.COM
+Subject: Case-sensitivity
+
+Test.
+.
+;
+
+
+test "Case-sensitivity" {
+ /* Default: i;ascii-casemap */
+
+ if not address :is ["to", "from"] "nico@nl.example.com" {
+ test_fail "address comparator is i;octet by default (1)";
+ }
+
+ if not address :is ["to", "from"] "harry@de.example.com" {
+ test_fail "address comparator is i;octet by default (2)";
+ }
+
+ if not address :is ["to", "from"] "STEPHAN@example.com" {
+ test_fail "address comparator is i;octet by default (3)";
+ }
+
+ if not address :is :localpart ["to"] "nico" {
+ test_fail "address comparator is i;octet by default (4)";
+ }
+
+ /* Match case-sensitively */
+
+ if not address :is :comparator "i;octet" ["to"] "Nico@nl.example.com" {
+ test_fail "failed to match case-sensitive address (1)";
+ }
+
+ if not address :is :comparator "i;octet" ["to"] "harry@DE.EXAMPLE.COM" {
+ test_fail "failed to match case-sensitive address (2)";
+ }
+
+ if address :is :comparator "i;octet" ["to"] "harry@de.example.com" {
+ test_fail "failed to notice case difference in address with i;octet (1)";
+ }
+
+ if address :is :comparator "i;octet" ["from"] "STEPHAN@example.com" {
+ test_fail "failed to notice case difference in address with i;octet (2)";
+ }
+
+ if not address :is :localpart :comparator "i;octet" ["to"] "Nico" {
+ test_fail "failed to match case-sensitive localpart";
+ }
+
+ if address :is :localpart :comparator "i;octet" ["to"] "nico" {
+ test_fail "failed to notice case difference in local_part with i;octet";
+ }
+
+ if not address :is :domain :comparator "i;octet" ["to"] "DE.EXAMPLE.COM" {
+ test_fail "failed to match case-sensitive localpart";
+ }
+
+ if address :is :domain :comparator "i;octet" ["to"] "de.example.com" {
+ test_fail "failed to notice case difference in domain with i;octet";
+ }
+}
+
+/*
+ * TEST: Phrase part, comments and group names
+ */
+
+/* "The address primitive never acts on the phrase part of an email
+ * address or on comments within that address. It also never acts on
+ * group names, ...
+ * "
+ */
+
+test_set "message" text:
+From: Stephan Bosch <stephan(the author)@example.com>
+To: Nico Thalens <nico@nl.example.com>, Harry Becker <harry@de.example.com>
+cc: tukkers: henk@tukkerland.ex, theo@tukkerland.ex, frits@tukkerland.ex;
+Subject: Frobnitzm
+
+Test.
+.
+;
+
+test "Phrase part, comments and group names" {
+ if address :contains :all :comparator "i;ascii-casemap"
+ ["to","from"] ["Bosch", "Thalens", "Becker"] {
+ test_fail "matched phrase part";
+ }
+
+ if address :contains :all :comparator "i;ascii-casemap" "from" "author" {
+ test_fail "matched comment";
+ }
+
+
+ if address :contains :all :comparator "i;ascii-casemap" ["cc"] ["tukkers"] {
+ test_fail "matched group name";
+ }
+}
+
+
+/*
+ * TEST: Group addresses
+ */
+
+/* "... although it does act on the addresses within the group
+ * construct.
+ * "
+ */
+
+test_set "message" text:
+From: stephan@friep.frop
+To: undisclosed-recipients:;
+cc: tukkers: henk@tukkerland.ex, theo@tukkerland.ex, frits@tukkerland.ex;
+Subject: Invalid addresses
+
+Test.
+.
+;
+
+test "Group addresses" {
+ if not address :is :domain ["cc"] ["tukkerland.ex"] {
+ test_fail "failed to match group address (1)";
+ }
+
+ if not address :is :localpart ["cc"] ["henk"] {
+ test_fail "failed to match group address (2)";
+ }
+
+ if not address :is :localpart ["cc"] ["theo"] {
+ test_fail "failed to match group address (3)";
+ }
+
+ if not address :is :localpart ["cc"] ["frits"] {
+ test_fail "failed to match group address (4)";
+ }
+}
+
+/*
+ * TEST: Address headers
+ */
+
+/* "Implementations MUST restrict the address test to headers that
+ * contain addresses, but MUST include at least From, To, Cc, Bcc,
+ * Sender, Resent-From, and Resent-To, and it SHOULD include any other
+ * header that utilizes an "address-list" structured header body.
+ * "
+ */
+
+test_set "message" text:
+From: stephan@friep.frop
+To: henk@tukkerland.ex
+CC: ivo@boer.ex
+Bcc: joop@hooibaal.ex
+Sender: s.bosch@friep.frop
+Resent-From: ivo@boer.ex
+Resent-To: idioot@dombo.ex
+Subject: Berichtje
+
+Test.
+.
+;
+
+
+test "Address headers" {
+ if not address "from" "stephan@friep.frop" {
+ test_fail "from header not recognized";
+ }
+
+ if not address "to" "henk@tukkerland.ex" {
+ test_fail "to header not recognized";
+ }
+
+ if not address "cc" "ivo@boer.ex" {
+ test_fail "cc header not recognized";
+ }
+
+ if not address "bcc" "joop@hooibaal.ex" {
+ test_fail "bcc header not recognized";
+ }
+
+ if not address "sender" "s.bosch@friep.frop" {
+ test_fail "sender header not recognized";
+ }
+
+ if not address "resent-from" "ivo@boer.ex" {
+ test_fail "resent-from header not recognized";
+ }
+
+ if not address "resent-to" "idioot@dombo.ex" {
+ test_fail "resent-to header not recognized";
+ }
+}
+
+/* ## RFC 5228, Section 2.7.4. Comparisons against Addresses (page 16) ## */
+
+/*
+ * TEST: Invalid addresses
+ */
+
+/*
+ * "If an address is not syntactically valid, then it will not be matched
+ * by tests specifying ":localpart" or ":domain".
+ * "
+ */
+
+test_set "message" text:
+From: stephan@
+To: @example.org
+Cc: nonsense
+Resent-To:
+Bcc: nico@frop.example.com, @example.org
+Resent-Cc:<jürgen@example.com>
+Subject: Invalid addresses
+
+Test.
+.
+;
+
+test "Invalid addresses" {
+ if address :localpart "from" "stephan" {
+ test_fail ":localpart matched invalid address";
+ }
+
+ if address :localpart "resent-cc" "jürgen" {
+ test_fail ":localpart matched invalid UTF-8 address";
+ }
+
+ if address :domain "to" "example.org" {
+ test_fail ":domain matched invalid address";
+ }
+
+ if address :domain "resent-cc" "example.com" {
+ test_fail ":domain matched invalid UTF-8 address";
+ }
+
+ if not address :is :all "resent-to" "" {
+ test_fail ":all failed to match empty address";
+ }
+
+ if not address :is :all "cc" "nonsense" {
+ test_fail ":all failed to match invalid address";
+ }
+
+ if not address :is :all "resent-cc" "<jürgen@example.com>" {
+ test_fail ":all failed to match invalid UTF-8 address";
+ }
+
+ if address :is :localpart "bcc" "" {
+ test_fail ":localpart matched invalid address";
+ }
+
+ if address :is :domain "cc" "example.org" {
+ test_fail ":domain matched invalid address";
+ }
+}
+
+/*
+ * TEST: Default address part
+ */
+
+/* "If an optional address-part is omitted, the default is ":all".
+ * "
+ */
+
+test_set "message" text:
+From: stephan@example.com
+To: nico@nl.example.com, harry@de.example.com
+Subject: Frobnitzm
+
+Test.
+.
+;
+
+test "Default address part" {
+ if not address :is :comparator "i;ascii-casemap" "from" "stephan@example.com"
+ {
+ test_fail "invalid default address part (1)";
+ }
+
+ if not address :is :comparator "i;ascii-casemap" "to"
+ ["harry@de.example.com"] {
+ test_fail "invalid default address part (2)";
+ }
+}
+
+/*
+ * TEST: Mime encoding of '@' in display name
+ */
+
+test_set "message" text:
+From: "Frop <frop@example.org>"
+To: =?UTF-8?B?RnJpZXBAZnJvcA0K?=
+ <friep@example.com>
+Subject: Test
+
+Frop!
+.
+;
+
+
+test "Mime encoding of '@' in display name" {
+ # Relevant sieve rule:
+
+ if not address :is "To"
+ ["friep@example.com"] {
+ test_fail "Invalid address extracted";
+ }
+}
+
+/*
+ * TEST: Erroneous mime encoding
+ */
+
+test_set "message" text:
+From: "William Wallace <william@scotsmen.ex>"
+To: "=?UTF-8?B?IkR1bWIgTWFpbGVyIg==?="
+ <horde@lists.scotsmen.ex>
+Subject: Test
+
+Frop!
+.
+;
+
+
+test "Erroneous mime encoding" {
+ # Relevant sieve rule:
+
+ if not address :is ["To","CC"] ["horde@lists.scotsmen.ex","archers@lists.scotsmen.ex"] {
+ test_fail "Failed to match improperly encoded address headers";
+ }
+}
+
+
diff --git a/pigeonhole/tests/test-allof.svtest b/pigeonhole/tests/test-allof.svtest
new file mode 100644
index 0000000..1ebef67
--- /dev/null
+++ b/pigeonhole/tests/test-allof.svtest
@@ -0,0 +1,446 @@
+require "vnd.dovecot.testsuite";
+
+/*
+ * ## RFC 5228, Section 5.2. Test allof (page 27) ##
+ */
+
+/* "The "allof" test performs a logical AND on the tests supplied to it.
+ *
+ * Example: allof (false, false) => false
+ * allof (false, true) => false
+ * allof (true, true) => true
+ *
+ * The allof test takes as its argument a test-list.
+ * "
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: test@dovecot.example.net
+cc: stephan@idiot.ex
+Subject: Test
+
+Test!
+.
+;
+
+/*
+ * TEST: Basic functionality: static
+ */
+
+test "Basic functionality: static" {
+ if allof ( true ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong single outcome: false";
+ }
+
+ if allof ( false ) {
+ test_fail "chose wrong single outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( true, true, true ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong all-true outcome: false";
+ }
+
+ if allof ( false, false, false ) {
+ test_fail "chose wrong all-false outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( true, false, false ) {
+ test_fail "chose wrong first-true outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( false, true, false ) {
+ test_fail "chose wrong second-true outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( false, false, true ) {
+ test_fail "chose wrong last-true outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( false, true, true ) {
+ test_fail "chose wrong first-false outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( true, false, true ) {
+ test_fail "chose wrong second-false outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( true, true, false ) {
+ test_fail "chose wrong last-false outcome: true";
+ } else {
+ /* Correct */
+ }
+}
+
+/*
+ * TEST: Basic functionality: dynamic
+ */
+
+test "Basic functionality: dynamic" {
+ if allof ( exists "from" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong single outcome: false";
+ }
+
+ if allof ( exists "friep" ) {
+ test_fail "chose wrong single outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "from", exists "to", exists "cc" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong all-true outcome: false";
+ }
+
+ if allof ( exists "friep", exists "frop", exists "frml" ) {
+ test_fail "chose wrong all-false outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "to", exists "frop", exists "frml" ) {
+ test_fail "chose wrong first-true outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "friep", exists "from", exists "frml" ) {
+ test_fail "chose wrong second-true outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "friep", exists "frop", exists "cc" ) {
+ test_fail "chose wrong last-true outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "friep", exists "from", exists "cc" ) {
+ test_fail "chose wrong first-false outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "to", exists "frop", exists "cc" ) {
+ test_fail "chose wrong second-false outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "to", exists "from", exists "frml" ) {
+ test_fail "chose wrong last-false outcome: true";
+ } else {
+ /* Correct */
+ }
+}
+
+/*
+ * TEST: Basic functionality: static/dynamic
+ */
+
+test "Basic functionality: static/dynamic" {
+ /* All true */
+
+ if allof ( true, exists "to", exists "cc" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong all-true first-static outcome: false";
+ }
+
+ if allof ( exists "from", true, exists "cc" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong all-true second-static outcome: false";
+ }
+
+ if allof ( exists "from", exists "to", true ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong all-true third-static outcome: false";
+ }
+
+ /* All false */
+
+ if allof ( false, exists "frop", exists "frml" ) {
+ test_fail "chose wrong all-false first-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "friep", false, exists "frml" ) {
+ test_fail "chose wrong all-false second-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "friep", exists "frop", false ) {
+ test_fail "chose wrong all-false third-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ /* First true */
+
+ if allof ( true, exists "frop", exists "frml" ) {
+ test_fail "chose wrong first-true first-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "to", false, exists "frml" ) {
+ test_fail "chose wrong first-true second-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "to", exists "frop", false ) {
+ test_fail "chose wrong first-true third-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ /* Second true */
+
+ if allof ( false, exists "from", exists "frml" ) {
+ test_fail "chose wrong second-true first-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "friep", true, exists "frml" ) {
+ test_fail "chose wrong second-true second-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "friep", exists "from", false ) {
+ test_fail "chose wrong second-true third-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ /* Last true */
+
+ if allof ( false, exists "frop", exists "cc" ) {
+ test_fail "chose wrong last-true first-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "friep", false, exists "cc" ) {
+ test_fail "chose wrong last-true second-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "friep", exists "frop", true ) {
+ test_fail "chose wrong last-true third-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ /* First false */
+
+ if allof ( false, exists "from", exists "cc" ) {
+ test_fail "chose wrong first-false first-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "friep", true, exists "cc" ) {
+ test_fail "chose wrong first-false second-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "friep", exists "from", true ) {
+ test_fail "chose wrong first-false third-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ /* Second false */
+
+ if allof ( true, exists "frop", exists "cc" ) {
+ test_fail "chose wrong second-false first-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "to", false, exists "cc" ) {
+ test_fail "chose wrong second-false second-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "to", exists "frop", true ) {
+ test_fail "chose wrong second-false third-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ /* Last false */
+
+ if allof ( true, exists "from", exists "frml" ) {
+ test_fail "chose wrong last-false first-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "to", true, exists "frml" ) {
+ test_fail "chose wrong last-false second-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( exists "to", exists "from", false ) {
+ test_fail "chose wrong last-false last-static outcome: true";
+ } else {
+ /* Correct */
+ }
+}
+
+/*
+ * TEST: Basic functionality: nesting
+ */
+
+test "Basic functionality: nesting" {
+ /* Static */
+
+ if allof ( allof(true, true), allof(true, true) ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong static nesting ((true, true),(true,true)) outcome: false";
+ }
+
+ if allof ( allof(false, true), allof(true, true) ) {
+ test_fail "chose wrong static nesting ((false, true),(true,true)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( allof(true, false), allof(true, true) ) {
+ test_fail "chose wrong static nesting ((true,false),(true,true)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( allof(true, true), allof(false, true) ) {
+ test_fail "chose wrong static nesting ((true, true),(false,true)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( allof(true, true), allof(true, false) ) {
+ test_fail "chose wrong static nesting ((true, true),(true,false)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( allof(true, false), allof(true, false) ) {
+ test_fail "chose wrong static nesting ((true, false),(true,false)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ /* Dynamic */
+
+ if allof ( allof(exists "to", exists "from"), allof(exists "cc", exists "subject") ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong dynamic nesting ((true, true),(true,true)) outcome: false";
+ }
+
+ if allof ( allof(exists "frop", exists "from"), allof(exists "cc", exists "subject") ) {
+ test_fail "chose wrong dynamic nesting ((false, true),(true,true)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( allof(exists "to", exists "friep"), allof(exists "cc", exists "subject") ) {
+ test_fail "chose wrong dynamic nesting ((true,false),(true,true)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( allof(exists "to", exists "from"), allof(exists "frml", exists "subject") ) {
+ test_fail "chose wrong dynamic nesting ((true, true),(false,true)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( allof(exists "to", exists "from"), allof(exists "cc", exists "fruts") ) {
+ test_fail "chose wrong dynamic nesting ((true, true),(true,false)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( allof(exists "to", exists "friep"), allof(exists "cc", exists "fruts") ) {
+ test_fail "chose wrong dynamic nesting ((true, false),(true,false)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ /* Static/Dynamic */
+
+ if allof ( allof(exists "to", true), allof(true, exists "subject") ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong static/dynamic nesting ((true, true),(true,true)) outcome: false";
+ }
+
+ if allof ( allof(false, exists "from"), allof(exists "cc", exists "subject") ) {
+ test_fail "chose wrong static/dynamic nesting ((false, true),(true,true)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( allof(exists "to", false), allof(exists "cc", exists "subject") ) {
+ test_fail "chose wrong static/dynamic nesting ((true,false),(true,true)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( allof(exists "to", exists "from"), allof(false, exists "subject") ) {
+ test_fail "chose wrong static/dynamic nesting ((true, true),(false,true)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( allof(exists "to", exists "from"), allof(exists "cc", false) ) {
+ test_fail "chose wrong static/dynamic nesting ((true, true),(true,false)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if allof ( allof(exists "to", false), allof(true, exists "fruts") ) {
+ test_fail "chose wrong static/dynamic nesting ((true, false),(true,false)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+}
+
+
diff --git a/pigeonhole/tests/test-anyof.svtest b/pigeonhole/tests/test-anyof.svtest
new file mode 100644
index 0000000..77a9c79
--- /dev/null
+++ b/pigeonhole/tests/test-anyof.svtest
@@ -0,0 +1,445 @@
+require "vnd.dovecot.testsuite";
+
+/*
+ * ## RFC 5228, Section 5.3. Test anyof (page 27) ##
+ */
+
+/* "The "anyof" test performs a logical OR on the tests supplied to it.
+ *
+ * Example: anyof (false, false) => false
+ * anyof (false, true) => true
+ * anyof (true, true) => true
+ * "
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: test@dovecot.example.net
+cc: stephan@idiot.ex
+Subject: Test
+
+Test!
+.
+;
+
+/*
+ * TEST: Basic functionality: static
+ */
+
+test "Basic functionality: static" {
+ if anyof ( true ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong single outcome: false";
+ }
+
+ if anyof ( false ) {
+ test_fail "chose wrong single outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if anyof ( true, true, true ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong all-true outcome: false";
+ }
+
+ if anyof ( false, false, false ) {
+ test_fail "chose wrong all-false outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if anyof ( true, false, false ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong first-true outcome: false";
+ }
+
+ if anyof ( false, true, false ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong second-true outcome: false";
+ }
+
+ if anyof ( false, false, true ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong last-true outcome: false";
+ }
+
+ if anyof ( false, true, true ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong first-false outcome: false";
+ }
+
+ if anyof ( true, false, true ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong second-false outcome: false";
+ }
+
+ if anyof ( true, true, false ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong last-false outcome: false";
+ }
+}
+
+/*
+ * TEST: Basic functionality: dynamic
+ */
+
+test "Basic functionality: dynamic" {
+ if anyof ( exists "from" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong single outcome: false";
+ }
+
+ if anyof ( exists "friep" ) {
+ test_fail "chose wrong single outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if anyof ( exists "from", exists "to", exists "cc" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong all-true outcome: false";
+ }
+
+ if anyof ( exists "friep", exists "frop", exists "frml" ) {
+ test_fail "chose wrong all-false outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if anyof ( exists "to", exists "frop", exists "frml" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong first-true outcome: false";
+ }
+
+ if anyof ( exists "friep", exists "from", exists "frml" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong second-true outcome: false";
+ }
+
+ if anyof ( exists "friep", exists "frop", exists "cc" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong last-true outcome: false";
+ }
+
+ if anyof ( exists "friep", exists "from", exists "cc" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong first-false outcome: false";
+ }
+
+ if anyof ( exists "to", exists "frop", exists "cc" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong second-false outcome: false";
+ }
+
+ if anyof ( exists "to", exists "from", exists "frml" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong last-false outcome: false";
+ }
+}
+
+/*
+ * TEST: Basic functionality: static/dynamic
+ */
+
+test "Basic functionality: static/dynamic" {
+ /* All true */
+
+ if anyof ( true, exists "to", exists "cc" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong all-true first-static outcome: false";
+ }
+
+ if anyof ( exists "from", true, exists "cc" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong all-true second-static outcome: false";
+ }
+
+ if anyof ( exists "from", exists "to", true ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong all-true third-static outcome: false";
+ }
+
+ /* All false */
+
+ if anyof ( false, exists "frop", exists "frml" ) {
+ test_fail "chose wrong all-false first-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if anyof ( exists "friep", false, exists "frml" ) {
+ test_fail "chose wrong all-false second-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if anyof ( exists "friep", exists "frop", false ) {
+ test_fail "chose wrong all-false third-static outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ /* First true */
+
+ if anyof ( true, exists "frop", exists "frml" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong first-true first-static outcome: false";
+ }
+
+ if anyof ( exists "to", false, exists "frml" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong first-true second-static outcome: false";
+ }
+
+ if anyof ( exists "to", exists "frop", false ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong first-true third-static outcome: false";
+ }
+
+ /* Second true */
+
+ if anyof ( false, exists "from", exists "frml" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong second-true first-static outcome: false";
+ }
+
+ if anyof ( exists "friep", true, exists "frml" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong second-true second-static outcome: false";
+ }
+
+ if anyof ( exists "friep", exists "from", false ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong second-true third-static outcome: false";
+ }
+
+ /* Last true */
+
+ if anyof ( false, exists "frop", exists "cc" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong last-true first-static outcome: false";
+ }
+
+ if anyof ( exists "friep", false, exists "cc" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong last-true second-static outcome: false";
+ }
+
+ if anyof ( exists "friep", exists "frop", true ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong last-true third-static outcome: false";
+ }
+
+ /* First false */
+
+ if anyof ( false, exists "from", exists "cc" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong first-false first-static outcome: false";
+ }
+
+ if anyof ( exists "friep", true, exists "cc" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong first-false second-static outcome: false";
+ }
+
+ if anyof ( exists "friep", exists "from", true ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong first-false third-static outcome: false";
+ }
+
+ /* Second false */
+
+ if anyof ( true, exists "frop", exists "cc" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong second-false first-static outcome: false";
+ }
+
+ if anyof ( exists "to", false, exists "cc" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong second-false second-static outcome: false";
+ }
+
+ if anyof ( exists "to", exists "frop", true ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong second-false third-static outcome: false";
+ }
+
+ /* Third false */
+
+ if anyof ( true, exists "from", exists "frml" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong last-false first-static outcome: false";
+ }
+
+ if anyof ( exists "to", true, exists "frml" ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong last-false second-static outcome: false";
+ }
+
+ if anyof ( exists "to", exists "from", false ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong last-false third-static outcome: false";
+ }
+}
+
+/*
+ * TEST: Basic functionality: nesting
+ */
+
+test "Basic functionality: nesting" {
+ /* Static */
+
+ if anyof ( anyof(false, false), anyof(false, false) ) {
+ test_fail "chose wrong static nesting ((false, false),(false,false)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if anyof ( anyof(true, false), anyof(false, false) ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong static nesting ((true, false),(false,false)) outcome: false";
+ }
+
+ if anyof ( anyof(false, true), anyof(false, false) ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong static nesting ((false, true),(false,false)) outcome: false";
+ }
+
+ if anyof ( anyof(false, false), anyof(true, false) ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong static nesting ((false, false),(true,false)) outcome: false";
+ }
+
+ if anyof ( anyof(false, false), anyof(false, true) ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong static nesting ((false, false),(false,true)) outcome: false";
+ }
+
+ if anyof ( anyof(true, false), anyof(false, true) ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong static nesting ((true, false),(false,true)) outcome: false";
+ }
+
+ /* Dynamic */
+
+ if anyof ( anyof(exists "frop", exists "friep"), anyof(exists "frml", exists "fruts") ) {
+ test_fail "chose wrong dynamic nesting ((false, false),(false,false)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if anyof ( anyof(exists "to", exists "friep"), anyof(exists "frml", exists "fruts") ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong dynamic nesting ((true, false),(false,false)) outcome: false";
+ }
+
+ if anyof ( anyof(exists "frop", exists "from"), anyof(exists "frml", exists "fruts") ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong dynamic nesting ((false, true),(false,false)) outcome: false";
+ }
+
+ if anyof ( anyof(exists "frop", exists "friep"), anyof(exists "cc", exists "fruts") ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong dynamic nesting ((false, false),(true,false)) outcome: false";
+ }
+
+ if anyof ( anyof(exists "frop", exists "friep"), anyof(exists "frml", exists "subject") ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong dynamic nesting ((false, false),(false,true)) outcome: false";
+ }
+
+ if anyof ( anyof(exists "to", exists "friep"), anyof(exists "frml", exists "subject") ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong dynamic nesting ((true, false),(false,true)) outcome: false";
+ }
+
+ /* Static/Dynamic */
+
+ if anyof ( anyof(false, exists "friep"), anyof(exists "frml", exists "fruts") ) {
+ test_fail "chose wrong static/dynamic nesting ((false, false),(false,false)) outcome: true";
+ } else {
+ /* Correct */
+ }
+
+ if anyof ( anyof(exists "to", false), anyof(exists "frml", exists "fruts") ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong static/dynamic nesting ((true, false),(false,false)) outcome: false";
+ }
+
+ if anyof ( anyof(exists "frop", exists "from"), anyof(false, exists "fruts") ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong static/dynamic nesting ((false, true),(false,false)) outcome: false";
+ }
+
+ if anyof ( anyof(exists "frop", exists "friep"), anyof(exists "cc", false) ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong static/dynamic nesting ((false, false),(true,false)) outcome: false";
+ }
+
+ if anyof ( anyof(exists "frop", exists "friep"), anyof(exists "frml", true) ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong static/dynamic nesting ((false, false),(false,true)) outcome: false";
+ }
+
+ if anyof ( anyof(true, exists "friep"), anyof(false, exists "subject") ) {
+ /* Correct */
+ } else {
+ test_fail "chose wrong dynamic nesting ((true, false),(false,true)) outcome: false";
+ }
+
+}
+
+
+
diff --git a/pigeonhole/tests/test-exists.svtest b/pigeonhole/tests/test-exists.svtest
new file mode 100644
index 0000000..8c4c2fc
--- /dev/null
+++ b/pigeonhole/tests/test-exists.svtest
@@ -0,0 +1,93 @@
+require "vnd.dovecot.testsuite";
+
+/* "The "exists" test is true if the headers listed in the header-names
+ * argument exist within the message. All of the headers must exist or
+ * the test is false.
+ * "
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@vestingbar.bl
+Subject: Test message
+Date: Wed, 29 Jul 2009 18:21:44 +0300
+X-Spam-Status: Not Spam
+Resent-To: nico@frop.example.com
+
+Test!
+.
+;
+
+/*
+ * TEST: One header
+ */
+
+test "One header" {
+ if not exists "from" {
+ test_fail "exists test missed from header";
+ }
+
+ if exists "x-nonsense" {
+ test_fail "exists test found non-existent header";
+ }
+}
+
+/*
+ * TEST: Two headers
+ */
+
+test "Two headers" {
+ if not exists ["from","to"] {
+ test_fail "exists test missed from or to header";
+ }
+
+ if exists ["from","x-nonsense"] {
+ test_fail "exists test found non-existent header (1)";
+ }
+
+ if exists ["x-nonsense","to"] {
+ test_fail "exists test found non-existent header (2)";
+ }
+
+ if exists ["x-nonsense","x-nonsense2"] {
+ test_fail "exists test found non-existent header (3)";
+ }
+}
+
+/*
+ * TEST: Three headers
+ */
+
+test "Three headers" {
+ if not exists ["Subject","date","resent-to"] {
+ test_fail "exists test missed subject, date or resent-to header";
+ }
+
+ if exists ["x-nonsense","date","resent-to"] {
+ test_fail "exists test found non-existent header (1)";
+ }
+
+ if exists ["subject", "x-nonsense","resent-to"] {
+ test_fail "exists test found non-existent header (2)";
+ }
+
+ if exists ["subject","date","x-nonsense"] {
+ test_fail "exists test found non-existent header (3)";
+ }
+
+ if exists ["subject", "x-nonsense","x-nonsense2"] {
+ test_fail "exists test found non-existent header (4)";
+ }
+
+ if exists ["x-nonsense","date","x-nonsense2"] {
+ test_fail "exists test found non-existent header (5)";
+ }
+
+ if exists ["x-nonsense","x-nonsense2","resent-to"] {
+ test_fail "exists test found non-existent header (6)";
+ }
+
+ if exists ["x-nonsense","x-nonsense2","x-nonsense3"] {
+ test_fail "exists test found non-existent header (7)";
+ }
+}
diff --git a/pigeonhole/tests/test-header.svtest b/pigeonhole/tests/test-header.svtest
new file mode 100644
index 0000000..138fb82
--- /dev/null
+++ b/pigeonhole/tests/test-header.svtest
@@ -0,0 +1,280 @@
+require "vnd.dovecot.testsuite";
+require "variables";
+
+/*
+ * ## RFC 5228, Section 5.7. Test header (page 29) ##
+ */
+
+/*
+ * TEST: Basic functionality
+ */
+
+/* "The "header" test evaluates to true if the value of any of the named
+ * headers, ignoring leading and trailing whitespace, matches any key.
+ * The type of match is specified by the optional match argument, which
+ * defaults to ":is" if not specified, as specified in section 2.6.
+ *
+ * Like address and envelope, this test returns true if any combination
+ * of the header-names list and key-list arguments match and returns
+ * false otherwise.
+ * "
+ */
+
+test_set "message" text:
+From: stephan@example.com
+To: nico@nl.example.com, harry@de.example.com
+Subject: Frobnitzm
+Comments: This is nonsense.
+Keywords: nonsense, strange, testing
+X-Spam: Yes
+
+Test.
+.
+;
+
+test "Basic functionality" {
+ /* Must match */
+ if not header :contains ["Subject", "Comments"] "Frobnitzm" {
+ test_fail "failed to match header (1)";
+ }
+
+ if not header :contains ["Subject", "Comments"] "nonsense" {
+ test_fail "failed to match header(2)";
+ }
+
+ if not header :matches "Keywords" "*, strange, *" {
+ test_fail "failed to match header (3)";
+ }
+
+ if not header :is "Comments" "This is nonsense." {
+ test_fail "failed to match header (4)";
+ }
+
+ /* Must not match */
+ if header ["subject", "comments", "keywords"] "idiotic" {
+ test_fail "matched nonsense";
+ }
+
+ /* Match first key */
+ if not header :contains ["keywords"] ["strange", "snot", "vreemd"] {
+ test_fail "failed to match first key";
+ }
+
+ /* Match second key */
+ if not header :contains ["keywords"] ["raar", "strange", "vreemd"] {
+ test_fail "failed to match second key";
+ }
+
+ /* Match last key */
+ if not header :contains ["keywords"] ["raar", "snot", "strange"] {
+ test_fail "failed to match last key";
+ }
+
+ /* First header */
+ if not header :contains ["keywords", "subject"]
+ ["raar", "strange", "vreemd"] {
+ test_fail "failed to match first header";
+ }
+
+ /* Second header */
+ if not header :contains ["subject", "keywords"]
+ ["raar", "strange", "vreemd"] {
+ test_fail "failed to match second header";
+ }
+}
+
+/*
+ * TEST: Matching empty key
+ */
+
+/* "If a header listed in the header-names argument exists, it contains
+ * the empty key (""). However, if the named header is not present, it
+ * does not match any key, including the empty key. So if a message
+ * contained the header
+ *
+ * X-Caffeine: C8H10N4O2
+ *
+ * these tests on that header evaluate as follows:
+ *
+ * header :is ["X-Caffeine"] [""] => false
+ * header :contains ["X-Caffeine"] [""] => true
+ * "
+ */
+
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.com
+X-Caffeine: C8H10N4O2
+Subject: I need coffee!
+Comments:
+
+Text
+.
+;
+
+test "Matching empty key" {
+ if header :is "X-Caffeine" "" {
+ test_fail ":is-matched non-empty header with empty string";
+ }
+
+ if not header :contains "X-Caffeine" "" {
+ test_fail "failed to match existing header with empty string";
+ }
+
+ if not header :is "comments" "" {
+ test_fail "failed to match empty header with empty string";
+ }
+
+ if header :contains "X-Nonsense" "" {
+ test_fail ":contains-matched non-existent header with empty string";
+ }
+}
+
+/*
+ * TEST: Ignoring whitespace
+ */
+
+/* "The "header" test evaluates to true if the value of any of the named
+ * headers, ignoring leading and trailing whitespace, matches any key.
+ * ...
+ * "
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.com
+Subject: Help
+X-A: Text
+X-B: Text
+
+Text
+.
+;
+
+test "Ignoring whitespace" {
+ if not header :is "x-a" "Text" {
+ if header :matches "x-a" "*" {
+ set "header" "${1}";
+ }
+ test_fail "header test does not strip leading whitespace (header=`${header}`)";
+ }
+
+ if not header :is "x-b" "Text" {
+ if header :matches "x-b" "*" {
+ set "header" "${1}";
+ }
+ test_fail "header test does not strip trailing whitespace (header=`${header}`)";
+ }
+
+ if not header :is "subject" "Help" {
+ if header :matches "subject" "*" {
+ set "header" "${1}";
+ }
+ test_fail "header test does not strip both leading and trailing whitespace (header=`${header}`)";
+ }
+}
+
+/*
+ * TEST: Absent or empty header
+ */
+
+/* "Testing whether a given header is either absent or doesn't contain
+ * any non-whitespace characters can be done using a negated "header"
+ * test:
+ *
+ * not header :matches "Cc" "?*"
+ * "
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.com
+CC: harry@nonsense.ex
+Subject:
+Comments:
+
+Text
+.
+;
+
+test "Absent or empty header" {
+ if not header :matches "Cc" "?*" {
+ test_fail "CC header is not absent or empty";
+ }
+
+ if header :matches "Subject" "?*" {
+ test_fail "Subject header is empty, but matched otherwise";
+ }
+
+ if header :matches "Comment" "?*" {
+ test_fail "Comment header is empty, but matched otherwise";
+ }
+}
+
+/*
+ * ## RFC 5228, Section 2.4.2.2. Headers (page 9)
+ */
+
+/*
+ * TEST: Invalid header name
+ */
+
+/* "A header name never contains a colon. The "From" header refers to a
+ * line beginning "From:" (or "From :", etc.). No header will match
+ * the string "From:" due to the trailing colon.
+ *
+ * Similarly, no header will match a syntactically invalid header name.
+ * An implementation MUST NOT cause an error for syntactically invalid
+ * header names in tests.
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.com
+Subject: Valid message
+X-Multiline: This is a multi-line
+ header body, which should be
+ unfolded correctly.
+
+Text
+.
+;
+
+test "Invalid header name" {
+ if header :contains "subject:" "" {
+ test_fail "matched invalid header name";
+ }
+
+ if header :contains "to!" "" {
+ test_fail "matched invalid header name";
+ }
+}
+
+/*
+ * TEST: Folded headers
+ */
+
+/* "Header lines are unfolded as described in [RFC 2822] section 2.2.3.
+ * ...
+ * "
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.com
+Subject: Not enough space on a line!
+X-Multiline: This is a multi-line
+ header body, which should be
+ unfolded correctly.
+
+Text
+.
+;
+
+test "Folded header" {
+ if not header :is "x-multiline"
+ "This is a multi-line header body, which should be unfolded correctly." {
+ test_fail "failed to properly unfold folded header.";
+ }
+}
diff --git a/pigeonhole/tests/test-size.svtest b/pigeonhole/tests/test-size.svtest
new file mode 100644
index 0000000..dd5cdc4
--- /dev/null
+++ b/pigeonhole/tests/test-size.svtest
@@ -0,0 +1,74 @@
+require "vnd.dovecot.testsuite";
+
+/*
+ * ## RFC 5228, Section 5.9. Test size (page 29) ##
+ */
+
+/*
+ * TEST: Basic functionality
+ */
+
+/* "The "size" test deals with the size of a message. It takes either a
+ * tagged argument of ":over" or ":under", followed by a number
+ * representing the size of the message.
+ *
+ * If the argument is ":over", and the size of the message is greater
+ * than the number provided, the test is true; otherwise, it is false.
+
+ * If the argument is ":under", and the size of the message is less than
+ * the number provided, the test is true; otherwise, it is false.
+ * "
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.com
+Subject: Help
+X-A: Text
+X-B: Text
+X-Multiline: This is a multi-line
+ header body, which should be
+ unfolded correctly.
+
+Text
+
+.
+;
+
+test "Basic functionality" {
+ if not size :under 1000 {
+ test_fail "size test produced unexpected result (1)";
+ }
+
+ if size :under 10 {
+ test_fail "size test produced unexpected result (2)";
+ }
+
+ if not size :over 10 {
+ test_fail "size test produced unexpected result (3)";
+ }
+
+ if size :over 1000 {
+ test_fail "size test produced unexpected result (4)";
+ }
+}
+
+/*
+ * TEST: Exact size
+ */
+
+/* "Note that for a message that is exactly 4,000 octets, the message is
+ * neither ":over" nor ":under" 4000 octets.
+ * "
+ */
+
+test "Exact size" {
+ if size :under 221 {
+ test_fail "size :under matched exact limit";
+ }
+
+ if size :over 221 {
+ test_fail "size :over matched exact limit";
+ }
+}
+
diff --git a/pigeonhole/tests/testsuite.svtest b/pigeonhole/tests/testsuite.svtest
new file mode 100644
index 0000000..349ba89
--- /dev/null
+++ b/pigeonhole/tests/testsuite.svtest
@@ -0,0 +1,75 @@
+require "vnd.dovecot.testsuite";
+require "envelope";
+
+/* Test message environment */
+
+test "Message Environment" {
+ test_set "message" text:
+From: sirius@example.org
+To: nico@frop.example.com
+Subject: Frop!
+
+Frop!
+.
+ ;
+
+ if not header :contains "from" "example.org" {
+ test_fail "message data not set properly.";
+ }
+
+ test_set "message" text:
+From: nico@frop.example.com
+To: stephan@nl.example.com
+Subject: Friep!
+
+Friep!
+.
+ ;
+
+ if not header :is "from" "nico@frop.example.com" {
+ test_fail "message data not set properly.";
+ }
+
+ keep;
+}
+
+/* Test envelope environment */
+
+test "Envelope Environment" {
+ test_set "envelope.from" "stephan@hutsefluts.example.net";
+
+ if not envelope :is "from" "stephan@hutsefluts.example.net" {
+ test_fail "envelope.from data not set properly (1).";
+ }
+
+ test_set "envelope.to" "news@example.org";
+
+ if not envelope :is "to" "news@example.org" {
+ test_fail "envelope.to data not set properly (1).";
+ }
+
+ test_set "envelope.auth" "sirius";
+
+ if not envelope :is "auth" "sirius" {
+ test_fail "envelope.auth data not set properly (1).";
+ }
+
+ test_set "envelope.from" "stephan@example.org";
+
+ if not envelope :is "from" "stephan@example.org" {
+ test_fail "envelope.from data not reset properly (2).";
+ }
+
+ test_set "envelope.to" "past-news@example.org";
+
+ if not envelope :is "to" "past-news@example.org" {
+ test_fail "envelope.to data not reset properly (2).";
+ }
+
+ test_set "envelope.auth" "zilla";
+
+ if not envelope :is "auth" "zilla" {
+ test_fail "envelope.auth data not reset properly (2).";
+ }
+}
+
diff --git a/pigeonhole/update-version.sh b/pigeonhole/update-version.sh
new file mode 100644
index 0000000..ec47deb
--- /dev/null
+++ b/pigeonhole/update-version.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+SRCDIR="${1:-`pwd`}"
+BUILDDIR="${2:-`pwd`}"
+VERSION_H="pigeonhole-version.h"
+VERSION_HT="pigeonhole-version.h.tmp"
+
+abspath()
+{ #$1 the path
+ #$2 1 -> SRCDIR || 2 -> BUILDDIR
+ old=`pwd`
+ cd "${1}"
+ if [ ${2} -eq 1 ]; then
+ SRCDIR=`pwd`
+ else
+ BUILDDIR=`pwd`
+ fi
+ cd "$old"
+}
+
+abspath "${SRCDIR}" 1
+abspath "${BUILDDIR}" 2
+
+# when using a different BUILDDIR just copy from SRCDIR, if there is no .git
+if [ "${BUILDDIR}" != "${SRCDIR}" ]; then
+ if [ ! -d "${SRCDIR}/.git" ] && [ -f "${SRCDIR}/${VERSION_H}" ]; then
+ cmp -s "${SRCDIR}/${VERSION_H}" "${BUILDDIR}/${VERSION_H}"
+ if [ $? -ne 0 ]; then
+ cp "${SRCDIR}/${VERSION_H}" "${BUILDDIR}/${VERSION_H}"
+ exit 0
+ fi
+ fi
+fi
+
+# Don't generate dovecot-version.h if the source tree has no .git dir but
+# a dovecot-version.h. This may be the result of a release/nightly tarball.
+[ ! -d "${SRCDIR}/.git" ] && [ -f "${BUILDDIR}/${VERSION_H}" ] && exit 0
+
+# Lets generate the dovecot-version.h
+[ -f "${BUILDDIR}/${VERSION_HT}" ] && rm -f "${BUILDDIR}/${VERSION_HT}"
+if true; then
+ GITID=`git --git-dir ${SRCDIR}/.git rev-parse --short HEAD`
+ cat > "${BUILDDIR}/${VERSION_HT}" <<EOF
+#ifndef PIGEONHOLE_VERSION_H
+#define PIGEONHOLE_VERSION_H
+
+#define PIGEONHOLE_VERSION_FULL PIGEONHOLE_VERSION" (${GITID})"
+
+#endif /* PIGEONHOLE_VERSION_H */
+EOF
+else
+ cat > "${BUILDDIR}/${VERSION_HT}" <<EOF
+#ifndef PIGEONHOLE_VERSION_H
+#define PIGEONHOLE_VERSION_H
+
+#define PIGEONHOLE_VERSION_FULL PIGEONHOLE_VERSION
+
+#endif /* PIGEONHOLE_VERSION_H */
+EOF
+fi
+
+cmp -s "${BUILDDIR}/${VERSION_H}" "${BUILDDIR}/${VERSION_HT}" && \
+ rm -f "${BUILDDIR}/${VERSION_HT}" || \
+ mv -f "${BUILDDIR}/${VERSION_HT}" "${BUILDDIR}/${VERSION_H}"